1 /* Copyright (c) 2006 Adam Warrington
2 ** $Id$
3 **
4 ** Permission is hereby granted, free of charge, to any person obtaining a copy
5 ** of this software and associated documentation files (the "Software"), to deal
6 ** in the Software without restriction, including without limitation the rights
7 ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 ** copies of the Software, and to permit persons to whom the Software is
9 ** furnished to do so, subject to the following conditions:
10 **
11 ** The above copyright notice and this permission notice shall be included in
12 ** all copies or substantial portions of the Software.
13 **
14 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 ** SOFTWARE.
21 **
22 ******************************************************************************
23 **
24 ** This header file defines SSDP functions to send and receive SSDP requests
25 ** to and from the router.
26 */
27 
28 /* define this to deprecate unsecure string warnings in vs2005.net */
29 #define _CRT_SECURE_NO_DEPRECATE 1
30 
31 #include <string.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include "ssdp.h"
35 #include "os.h"
36 #include "utility.h"
37 #include "error.h"
38 
39 
40 /* Address and port of an SSDP request used for discovery */
41 #define SSDP_HOST_ADDRESS "239.255.255.250"
42 #define SSDP_HOST_PORT 1900
43 
44 /* This is the format for the SSDP message that will be broadcast to
45    find a router on the network with UPnP enabled. The variable is
46    going to be what service we want to search for, since a router can
47    be one of two services, we need to search for both. */
48 #define SEARCH_REQUEST_STRING "M-SEARCH * HTTP/1.1\r\n"            \
49                               "MX: 2\r\n"                          \
50                               "HOST: 239.255.255.250:1900\r\n"     \
51                               "MAN: \"ssdp:discover\"\r\n"         \
52                               "ST: %s\r\n"                         \
53                               "\r\n"
54 #define SEARCH_REQUEST_LEN_WO_VARS 86
55 
56 /* maximum size of a discovery response */
57 #define MAX_DISCOVERY_RECEIVE_SIZE 1024
58 
59 /* timeout in seconds of a discovery request */
60 #define DISCOVERY_TIMEOUT     2
61 
62 
63 /* local file defines */
64 static int Send_Discover_Request(OsSocket * s, const char * search_target);
65 static int Get_Discover_Response(OsSocket * s, char ** response);
66 
67 
68 /* send an ssdp discover request, and receive a SsdpDiscResp back.
69    Caller is responsible for freeing the response with free() */
LNat_Ssdp_Discover(const char * search_target,char ** response)70 int LNat_Ssdp_Discover(const char * search_target,
71                        char ** response)
72 {
73   int ret;
74   OsSocket * s;
75 
76   /* setup the udp connection */
77   if((ret = LNat_Os_Socket_Udp_Setup(&s)) != OK) {
78     return ret;
79   }
80 
81   /* send the discovery request */
82   if((ret = Send_Discover_Request(s, search_target)) != OK) {
83     return ret;
84   }
85 
86   /* get the discovery response */
87   if((ret = Get_Discover_Response(s, response)) != OK) {
88     LNat_Os_Socket_Udp_Close(&s);
89     return ret;
90   }
91 
92   /* close the udp connection */
93   if((ret = LNat_Os_Socket_Udp_Close(&s)) != OK) {
94     free(*response);
95     return ret;
96   }
97 
98   return OK;
99 }
100 
101 
102 /* send a discover request over udp */
Send_Discover_Request(OsSocket * s,const char * search_target)103 static int Send_Discover_Request(OsSocket * s,
104                                  const char * search_target)
105 {
106   int ret;
107   int amt_sent;
108   char * discover_request;
109 
110   discover_request = (char *)malloc(SEARCH_REQUEST_LEN_WO_VARS +
111                                     strlen(search_target) +
112                                     NULL_TERM_LEN);
113   if(NULL == discover_request) {
114     return BAD_MALLOC;
115   }
116   (void)sprintf(discover_request, SEARCH_REQUEST_STRING, search_target);
117 
118   if((ret = LNat_Os_Socket_Udp_Send(s, SSDP_HOST_ADDRESS, SSDP_HOST_PORT,
119                                     discover_request, (int)strlen(discover_request),
120                                     &amt_sent)) != OK) {
121     free(discover_request);
122     return ret;
123   }
124 
125   free(discover_request);
126   return OK;
127 }
128 
129 
130 /* receive a discover response */
Get_Discover_Response(OsSocket * s,char ** response)131 static int Get_Discover_Response(OsSocket * s,
132                                  char ** response)
133 {
134   int ret;
135   int amt_recv;
136   int recv_sofar = 0;
137 
138   *response = (char *)malloc(MAX_DISCOVERY_RECEIVE_SIZE +
139                              NULL_TERM_LEN);
140   if(NULL == *response) {
141     return BAD_MALLOC;
142   }
143 
144   ret = LNat_Os_Socket_Udp_Recv(s, SSDP_HOST_ADDRESS, SSDP_HOST_PORT,
145                                   &((*response)[recv_sofar]),
146                                   MAX_DISCOVERY_RECEIVE_SIZE, &amt_recv,
147                                   DISCOVERY_TIMEOUT);
148   if(ret != OK) {
149     free(*response);
150     return ret;
151   }
152 
153   if(amt_recv <= 0) {
154     free(*response);
155     return SSDP_RECV_FAILED;
156   }
157 
158   (*response)[amt_recv] = NULL_TERM;
159   return OK;
160 }
161 
162 
163 
164 
165