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