diff options
Diffstat (limited to 'src/nat/miniupnp/miniupnpc.c')
-rw-r--r-- | src/nat/miniupnp/miniupnpc.c | 901 |
1 files changed, 0 insertions, 901 deletions
diff --git a/src/nat/miniupnp/miniupnpc.c b/src/nat/miniupnp/miniupnpc.c deleted file mode 100644 index 34bae0ad8..000000000 --- a/src/nat/miniupnp/miniupnpc.c +++ /dev/null | |||
@@ -1,901 +0,0 @@ | |||
1 | /* $Id: miniupnpc.c,v 1.57 2008/12/18 17:46:36 nanard Exp $ */ | ||
2 | /* Project : miniupnp | ||
3 | * Author : Thomas BERNARD | ||
4 | * copyright (c) 2005-2007 Thomas Bernard | ||
5 | * This software is subjet to the conditions detailed in the | ||
6 | * provided LICENCE file. */ | ||
7 | #include <stdio.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <string.h> | ||
10 | #ifdef WIN32 | ||
11 | /* Win32 Specific includes and defines */ | ||
12 | #include <winsock2.h> | ||
13 | #include <Ws2tcpip.h> | ||
14 | #include <Iphlpapi.h> | ||
15 | #include <io.h> | ||
16 | #define snprintf _snprintf | ||
17 | #if defined(_MSC_VER) && (_MSC_VER >= 1400) | ||
18 | #define strncasecmp _memicmp | ||
19 | #else | ||
20 | #define strncasecmp memicmp | ||
21 | #endif | ||
22 | #define MAXHOSTNAMELEN 64 | ||
23 | #else | ||
24 | /* Standard POSIX includes */ | ||
25 | #include <unistd.h> | ||
26 | #include <sys/socket.h> | ||
27 | #include <sys/types.h> | ||
28 | #include <sys/param.h> | ||
29 | #include <netinet/in.h> | ||
30 | #include <net/if.h> | ||
31 | #include <arpa/inet.h> | ||
32 | #include <poll.h> | ||
33 | #include <netdb.h> | ||
34 | #define closesocket close | ||
35 | #endif | ||
36 | #include "miniupnpc.h" | ||
37 | #include "minissdpc.h" | ||
38 | #include "miniwget.h" | ||
39 | #include "minisoap.h" | ||
40 | #include "minixml.h" | ||
41 | #include "upnpcommands.h" | ||
42 | |||
43 | #ifdef WIN32 | ||
44 | #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); | ||
45 | #else | ||
46 | #define PRINT_SOCKET_ERROR(x) perror(x) | ||
47 | #endif | ||
48 | |||
49 | #define SOAPPREFIX "s" | ||
50 | #define SERVICEPREFIX "u" | ||
51 | #define SERVICEPREFIX2 'u' | ||
52 | |||
53 | /* root description parsing */ | ||
54 | void | ||
55 | parserootdesc (const char *buffer, int bufsize, struct IGDdatas *data) | ||
56 | { | ||
57 | struct xmlparser parser; | ||
58 | /* xmlparser object */ | ||
59 | parser.xmlstart = buffer; | ||
60 | parser.xmlsize = bufsize; | ||
61 | parser.data = data; | ||
62 | parser.starteltfunc = IGDstartelt; | ||
63 | parser.endeltfunc = IGDendelt; | ||
64 | parser.datafunc = IGDdata; | ||
65 | parser.attfunc = 0; | ||
66 | parsexml (&parser); | ||
67 | #ifdef DEBUG | ||
68 | printIGD (data); | ||
69 | #endif | ||
70 | } | ||
71 | |||
72 | /* Content-length: nnn */ | ||
73 | static int | ||
74 | getcontentlenfromline (const char *p, int n) | ||
75 | { | ||
76 | static const char contlenstr[] = "content-length"; | ||
77 | const char *p2 = contlenstr; | ||
78 | int a = 0; | ||
79 | while (*p2) | ||
80 | { | ||
81 | if (n == 0) | ||
82 | return -1; | ||
83 | if (*p2 != *p && *p2 != (*p + 32)) | ||
84 | return -1; | ||
85 | p++; | ||
86 | p2++; | ||
87 | n--; | ||
88 | } | ||
89 | if (n == 0) | ||
90 | return -1; | ||
91 | if (*p != ':') | ||
92 | return -1; | ||
93 | p++; | ||
94 | n--; | ||
95 | while (*p == ' ') | ||
96 | { | ||
97 | if (n == 0) | ||
98 | return -1; | ||
99 | p++; | ||
100 | n--; | ||
101 | } | ||
102 | while (*p >= '0' && *p <= '9') | ||
103 | { | ||
104 | if (n == 0) | ||
105 | return -1; | ||
106 | a = (a * 10) + (*p - '0'); | ||
107 | p++; | ||
108 | n--; | ||
109 | } | ||
110 | return a; | ||
111 | } | ||
112 | |||
113 | static void | ||
114 | getContentLengthAndHeaderLength (char *p, int n, | ||
115 | int *contentlen, int *headerlen) | ||
116 | { | ||
117 | char *line; | ||
118 | int linelen; | ||
119 | int r; | ||
120 | line = p; | ||
121 | while (line < p + n) | ||
122 | { | ||
123 | linelen = 0; | ||
124 | while (line[linelen] != '\r' && line[linelen] != '\r') | ||
125 | { | ||
126 | if (line + linelen >= p + n) | ||
127 | return; | ||
128 | linelen++; | ||
129 | } | ||
130 | r = getcontentlenfromline (line, linelen); | ||
131 | if (r > 0) | ||
132 | *contentlen = r; | ||
133 | line = line + linelen + 2; | ||
134 | if (line[0] == '\r' && line[1] == '\n') | ||
135 | { | ||
136 | *headerlen = (line - p) + 2; | ||
137 | return; | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | |||
142 | /* simpleUPnPcommand : | ||
143 | * not so simple ! | ||
144 | * return values : | ||
145 | * 0 - OK | ||
146 | * -1 - error */ | ||
147 | int | ||
148 | simpleUPnPcommand (int s, const char *url, const char *service, | ||
149 | const char *action, struct UPNParg *args, | ||
150 | char *buffer, int *bufsize) | ||
151 | { | ||
152 | struct sockaddr_in dest; | ||
153 | struct sockaddr_in6 dest6; | ||
154 | char hostname[MAXHOSTNAMELEN + 1]; | ||
155 | unsigned short port = 0; | ||
156 | char *path; | ||
157 | char soapact[128]; | ||
158 | char soapbody[2048]; | ||
159 | char *buf; | ||
160 | int buffree; | ||
161 | int n; | ||
162 | int err; | ||
163 | int contentlen, headerlen; /* for the response */ | ||
164 | snprintf (soapact, sizeof (soapact), "%s#%s", service, action); | ||
165 | if (args == NULL) | ||
166 | { | ||
167 | /*soapbodylen = */ snprintf (soapbody, sizeof (soapbody), | ||
168 | "<?xml version=\"1.0\"?>\r\n" | ||
169 | "<" SOAPPREFIX ":Envelope " | ||
170 | "xmlns:" SOAPPREFIX | ||
171 | "=\"http://schemas.xmlsoap.org/soap/envelope/\" " | ||
172 | SOAPPREFIX | ||
173 | ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" | ||
174 | "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX | ||
175 | ":%s xmlns:" SERVICEPREFIX "=\"%s\">" "</" | ||
176 | SERVICEPREFIX ":%s>" "</" SOAPPREFIX | ||
177 | ":Body></" SOAPPREFIX ":Envelope>" "\r\n", | ||
178 | action, service, action); | ||
179 | } | ||
180 | else | ||
181 | { | ||
182 | char *p; | ||
183 | const char *pe, *pv; | ||
184 | int soapbodylen; | ||
185 | soapbodylen = snprintf (soapbody, sizeof (soapbody), | ||
186 | "<?xml version=\"1.0\"?>\r\n" | ||
187 | "<" SOAPPREFIX ":Envelope " | ||
188 | "xmlns:" SOAPPREFIX | ||
189 | "=\"http://schemas.xmlsoap.org/soap/envelope/\" " | ||
190 | SOAPPREFIX | ||
191 | ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" | ||
192 | "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX | ||
193 | ":%s xmlns:" SERVICEPREFIX "=\"%s\">", action, | ||
194 | service); | ||
195 | p = soapbody + soapbodylen; | ||
196 | while (args->elt) | ||
197 | { | ||
198 | /* check that we are never overflowing the string... */ | ||
199 | if (soapbody + sizeof (soapbody) <= p + 100) | ||
200 | { | ||
201 | /* we keep a margin of at least 100 bytes */ | ||
202 | *bufsize = 0; | ||
203 | return -1; | ||
204 | } | ||
205 | *(p++) = '<'; | ||
206 | pe = args->elt; | ||
207 | while (*pe) | ||
208 | *(p++) = *(pe++); | ||
209 | *(p++) = '>'; | ||
210 | if ((pv = args->val)) | ||
211 | { | ||
212 | while (*pv) | ||
213 | *(p++) = *(pv++); | ||
214 | } | ||
215 | *(p++) = '<'; | ||
216 | *(p++) = '/'; | ||
217 | pe = args->elt; | ||
218 | while (*pe) | ||
219 | *(p++) = *(pe++); | ||
220 | *(p++) = '>'; | ||
221 | args++; | ||
222 | } | ||
223 | *(p++) = '<'; | ||
224 | *(p++) = '/'; | ||
225 | *(p++) = SERVICEPREFIX2; | ||
226 | *(p++) = ':'; | ||
227 | pe = action; | ||
228 | while (*pe) | ||
229 | *(p++) = *(pe++); | ||
230 | strncpy (p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n", | ||
231 | soapbody + sizeof (soapbody) - p); | ||
232 | } | ||
233 | if (!parseURL (url, hostname, &port, &path)) | ||
234 | return -1; | ||
235 | |||
236 | if (s < 0) | ||
237 | { | ||
238 | /* Test IPv4 address, else use IPv6 */ | ||
239 | if (inet_pton (AF_INET, hostname, &dest.sin_addr) == 1) | ||
240 | { | ||
241 | memset (&dest, 0, sizeof (dest)); | ||
242 | dest.sin_family = AF_INET; | ||
243 | dest.sin_port = htons (port); | ||
244 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
245 | dest.sin_len = sizeof (dest); | ||
246 | #endif | ||
247 | if ((s = socket (PF_INET, SOCK_STREAM, 0)) < 0) | ||
248 | { | ||
249 | PRINT_SOCKET_ERROR ("socket"); | ||
250 | *bufsize = 0; | ||
251 | return -1; | ||
252 | } | ||
253 | err = connect (s, (struct sockaddr *) &dest, sizeof (dest)); | ||
254 | } | ||
255 | else if (inet_pton (AF_INET6, hostname, &dest6.sin6_addr) == 1) | ||
256 | { | ||
257 | memset (&dest6, 0, sizeof (dest6)); | ||
258 | dest6.sin6_family = AF_INET6; | ||
259 | dest6.sin6_port = htons (port); | ||
260 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
261 | dest6.sin6_len = sizeof (dest6); | ||
262 | #endif | ||
263 | if ((s = socket (PF_INET6, SOCK_STREAM, 0)) < 0) | ||
264 | { | ||
265 | PRINT_SOCKET_ERROR ("socket"); | ||
266 | *bufsize = 0; | ||
267 | return -1; | ||
268 | } | ||
269 | err = connect (s, (struct sockaddr *) &dest6, sizeof (dest6)); | ||
270 | } | ||
271 | else | ||
272 | { | ||
273 | PRINT_SOCKET_ERROR ("inet_pton"); | ||
274 | if (s > 0) | ||
275 | closesocket (s); | ||
276 | |||
277 | *bufsize = 0; | ||
278 | return -1; | ||
279 | } | ||
280 | |||
281 | if (err < 0) | ||
282 | { | ||
283 | PRINT_SOCKET_ERROR ("connect"); | ||
284 | closesocket (s); | ||
285 | *bufsize = 0; | ||
286 | return -1; | ||
287 | } | ||
288 | } | ||
289 | n = soapPostSubmit (s, path, hostname, port, soapact, soapbody); | ||
290 | if (n <= 0) | ||
291 | { | ||
292 | #ifdef DEBUG | ||
293 | printf ("Error sending SOAP request\n"); | ||
294 | #endif | ||
295 | closesocket (s); | ||
296 | return -1; | ||
297 | } | ||
298 | |||
299 | contentlen = -1; | ||
300 | headerlen = -1; | ||
301 | buf = buffer; | ||
302 | buffree = *bufsize; | ||
303 | *bufsize = 0; | ||
304 | while ((n = ReceiveData (s, buf, buffree, 5000)) > 0) | ||
305 | { | ||
306 | buffree -= n; | ||
307 | buf += n; | ||
308 | *bufsize += n; | ||
309 | getContentLengthAndHeaderLength (buffer, *bufsize, | ||
310 | &contentlen, &headerlen); | ||
311 | #ifdef DEBUG | ||
312 | printf ("received n=%dbytes bufsize=%d ContLen=%d HeadLen=%d\n", | ||
313 | n, *bufsize, contentlen, headerlen); | ||
314 | #endif | ||
315 | /* break if we received everything */ | ||
316 | if (contentlen > 0 && headerlen > 0 | ||
317 | && *bufsize >= contentlen + headerlen) | ||
318 | break; | ||
319 | } | ||
320 | |||
321 | closesocket (s); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | /* parseMSEARCHReply() | ||
326 | * the last 4 arguments are filled during the parsing : | ||
327 | * - location/locationsize : "location:" field of the SSDP reply packet | ||
328 | * - st/stsize : "st:" field of the SSDP reply packet. | ||
329 | * The strings are NOT null terminated */ | ||
330 | static void | ||
331 | parseMSEARCHReply (const char *reply, int size, | ||
332 | const char **location, int *locationsize, | ||
333 | const char **st, int *stsize) | ||
334 | { | ||
335 | int a, b, i; | ||
336 | i = 0; | ||
337 | a = i; /* start of the line */ | ||
338 | b = 0; | ||
339 | while (i < size) | ||
340 | { | ||
341 | switch (reply[i]) | ||
342 | { | ||
343 | case ':': | ||
344 | if (b == 0) | ||
345 | { | ||
346 | b = i; /* end of the "header" */ | ||
347 | /*for(j=a; j<b; j++) | ||
348 | { | ||
349 | putchar(reply[j]); | ||
350 | } | ||
351 | */ | ||
352 | } | ||
353 | break; | ||
354 | case '\x0a': | ||
355 | case '\x0d': | ||
356 | if (b != 0) | ||
357 | { | ||
358 | /*for(j=b+1; j<i; j++) | ||
359 | { | ||
360 | putchar(reply[j]); | ||
361 | } | ||
362 | putchar('\n'); */ | ||
363 | do | ||
364 | { | ||
365 | b++; | ||
366 | } | ||
367 | while (reply[b] == ' '); | ||
368 | if (0 == strncasecmp (reply + a, "location", 8)) | ||
369 | { | ||
370 | *location = reply + b; | ||
371 | *locationsize = i - b; | ||
372 | } | ||
373 | else if (0 == strncasecmp (reply + a, "st", 2)) | ||
374 | { | ||
375 | *st = reply + b; | ||
376 | *stsize = i - b; | ||
377 | } | ||
378 | b = 0; | ||
379 | } | ||
380 | a = i + 1; | ||
381 | break; | ||
382 | default: | ||
383 | break; | ||
384 | } | ||
385 | i++; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | /* port upnp discover : SSDP protocol */ | ||
390 | #define PORT 1900 | ||
391 | #define XSTR(s) STR(s) | ||
392 | #define STR(s) #s | ||
393 | #define UPNP_MCAST_ADDR "239.255.255.250" | ||
394 | #define UPNP_MCAST_ADDR6 "FF02:0:0:0:0:0:0:F" | ||
395 | |||
396 | /* upnpDiscover() : | ||
397 | * return a chained list of all devices found or NULL if | ||
398 | * no devices was found. | ||
399 | * It is up to the caller to free the chained list | ||
400 | * delay is in millisecond (poll) */ | ||
401 | struct UPNPDev * | ||
402 | upnpDiscover (int delay, const char *multicastif, | ||
403 | const struct sockaddr *addr, | ||
404 | const char *minissdpdsock, int sameport) | ||
405 | { | ||
406 | struct UPNPDev *tmp; | ||
407 | struct UPNPDev *devlist = 0; | ||
408 | int opt = 1; | ||
409 | static const char MSearchMsgFmt[] = | ||
410 | "M-SEARCH * HTTP/1.1\r\n" | ||
411 | "HOST: " UPNP_MCAST_ADDR ":" XSTR (PORT) "\r\n" | ||
412 | "ST: %s\r\n" "MAN: \"ssdp:discover\"\r\n" "MX: 3\r\n" "\r\n"; | ||
413 | static const char *const deviceList[] = { | ||
414 | "urn:schemas-upnp-org:device:InternetGatewayDevice:1", | ||
415 | "urn:schemas-upnp-org:service:WANIPConnection:1", | ||
416 | "urn:schemas-upnp-org:service:WANPPPConnection:1", | ||
417 | "upnp:rootdevice", | ||
418 | 0 | ||
419 | }; | ||
420 | int deviceIndex = 0; | ||
421 | char bufr[1536]; /* reception and emission buffer */ | ||
422 | int sudp; | ||
423 | int n; | ||
424 | int domain = PF_INET; | ||
425 | int if_index; | ||
426 | struct in6_addr any_addr = IN6ADDR_ANY_INIT; | ||
427 | struct sockaddr_in sockudp_r, sockudp_w; | ||
428 | struct sockaddr_in6 sockudp6_r, sockudp6_w; | ||
429 | |||
430 | #ifndef WIN32 | ||
431 | /* first try to get infos from minissdpd ! */ | ||
432 | if (!minissdpdsock) | ||
433 | minissdpdsock = "/var/run/minissdpd.sock"; | ||
434 | while (!devlist && deviceList[deviceIndex]) | ||
435 | { | ||
436 | devlist = getDevicesFromMiniSSDPD (deviceList[deviceIndex], | ||
437 | minissdpdsock); | ||
438 | /* We return what we have found if it was not only a rootdevice */ | ||
439 | if (devlist && !strstr (deviceList[deviceIndex], "rootdevice")) | ||
440 | return devlist; | ||
441 | deviceIndex++; | ||
442 | } | ||
443 | deviceIndex = 0; | ||
444 | #endif | ||
445 | |||
446 | if (addr && addr->sa_family == AF_INET) | ||
447 | domain = PF_INET; | ||
448 | else if (addr && addr->sa_family == AF_INET6) | ||
449 | domain = PF_INET6; | ||
450 | else if (addr) | ||
451 | return NULL; | ||
452 | |||
453 | /* fallback to direct discovery */ | ||
454 | #ifdef WIN32 | ||
455 | sudp = socket (domain, SOCK_DGRAM, IPPROTO_UDP); | ||
456 | #else | ||
457 | sudp = socket (domain, SOCK_DGRAM, 0); | ||
458 | #endif | ||
459 | if (sudp < 0) | ||
460 | { | ||
461 | PRINT_SOCKET_ERROR ("socket"); | ||
462 | return NULL; | ||
463 | } | ||
464 | |||
465 | if (domain == PF_INET) | ||
466 | { | ||
467 | /* receive */ | ||
468 | memset (&sockudp_r, 0, sizeof (struct sockaddr_in)); | ||
469 | sockudp_r.sin_family = AF_INET; | ||
470 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
471 | sockudp_r.sin_len = sizeof (struct sockaddr_in); | ||
472 | #endif | ||
473 | if (sameport) | ||
474 | sockudp_r.sin_port = htons (PORT); | ||
475 | sockudp_r.sin_addr.s_addr = INADDR_ANY; | ||
476 | /* send */ | ||
477 | memset (&sockudp_w, 0, sizeof (struct sockaddr_in)); | ||
478 | sockudp_w.sin_family = AF_INET; | ||
479 | sockudp_w.sin_port = htons (PORT); | ||
480 | sockudp_w.sin_addr.s_addr = inet_addr (UPNP_MCAST_ADDR); | ||
481 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
482 | sockudp_w.sin_len = sizeof (struct sockaddr_in); | ||
483 | #endif | ||
484 | } | ||
485 | else | ||
486 | { | ||
487 | /* receive */ | ||
488 | memcpy (&sockudp6_r, addr, sizeof (struct sockaddr_in6)); | ||
489 | if (sameport) | ||
490 | sockudp6_r.sin6_port = htons (PORT); | ||
491 | else | ||
492 | sockudp6_r.sin6_port = 0; | ||
493 | sockudp6_r.sin6_addr = any_addr; | ||
494 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
495 | sockudp6_r.sin6_len = sizeof (struct sockaddr_in6); | ||
496 | #endif | ||
497 | /* send */ | ||
498 | memset (&sockudp6_w, 0, sizeof (struct sockaddr_in6)); | ||
499 | sockudp6_w.sin6_family = AF_INET6; | ||
500 | sockudp6_w.sin6_port = htons (PORT); | ||
501 | if (inet_pton (AF_INET6, UPNP_MCAST_ADDR6, &sockudp6_w.sin6_addr) != 1) | ||
502 | { | ||
503 | PRINT_SOCKET_ERROR ("inet_pton"); | ||
504 | return NULL; | ||
505 | } | ||
506 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
507 | sockudp6_w.sin6_len = sizeof (struct sockaddr_in6); | ||
508 | #endif | ||
509 | } | ||
510 | |||
511 | #ifdef WIN32 | ||
512 | if (setsockopt | ||
513 | (sudp, SOL_SOCKET, SO_REUSEADDR, (const char *) &opt, sizeof (opt)) < 0) | ||
514 | #else | ||
515 | if (setsockopt (sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) | ||
516 | #endif | ||
517 | { | ||
518 | PRINT_SOCKET_ERROR ("setsockopt"); | ||
519 | return NULL; | ||
520 | } | ||
521 | |||
522 | if (addr) | ||
523 | { | ||
524 | if (domain == PF_INET) | ||
525 | { | ||
526 | sockudp_r.sin_addr.s_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; | ||
527 | if (setsockopt | ||
528 | (sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *) &sockudp_r.sin_addr, | ||
529 | sizeof (struct in_addr)) < 0) | ||
530 | { | ||
531 | PRINT_SOCKET_ERROR ("setsockopt"); | ||
532 | } | ||
533 | |||
534 | /* Bind to receive response before sending packet */ | ||
535 | if (bind (sudp, (struct sockaddr *) &sockudp_r, sizeof (struct sockaddr_in)) | ||
536 | != 0) | ||
537 | { | ||
538 | PRINT_SOCKET_ERROR ("bind"); | ||
539 | closesocket (sudp); | ||
540 | return NULL; | ||
541 | } | ||
542 | } | ||
543 | else | ||
544 | { | ||
545 | if (multicastif) | ||
546 | { | ||
547 | if_index = if_nametoindex (multicastif); | ||
548 | if (!if_index) | ||
549 | PRINT_SOCKET_ERROR ("if_nametoindex"); | ||
550 | |||
551 | if (setsockopt | ||
552 | (sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_index, sizeof (if_index)) < 0) | ||
553 | { | ||
554 | PRINT_SOCKET_ERROR ("setsockopt"); | ||
555 | } | ||
556 | } | ||
557 | |||
558 | /* Bind to receive response before sending packet */ | ||
559 | memcpy (&sockudp6_r.sin6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr, | ||
560 | sizeof (sockudp6_r.sin6_addr)); | ||
561 | if (bind (sudp, (struct sockaddr *) &sockudp6_r, sizeof (struct sockaddr_in6)) | ||
562 | != 0) | ||
563 | { | ||
564 | PRINT_SOCKET_ERROR ("bind"); | ||
565 | closesocket (sudp); | ||
566 | return NULL; | ||
567 | } | ||
568 | } | ||
569 | } | ||
570 | |||
571 | /* receiving SSDP response packet */ | ||
572 | for (n = 0;;) | ||
573 | { | ||
574 | if (n == 0) | ||
575 | { | ||
576 | /* sending the SSDP M-SEARCH packet */ | ||
577 | n = snprintf (bufr, sizeof (bufr), | ||
578 | MSearchMsgFmt, deviceList[deviceIndex++]); | ||
579 | /*printf("Sending %s", bufr); */ | ||
580 | if (domain == PF_INET) | ||
581 | n = sendto (sudp, bufr, n, 0, | ||
582 | (struct sockaddr *) &sockudp_w, | ||
583 | sizeof (struct sockaddr_in)); | ||
584 | else | ||
585 | n = sendto (sudp, bufr, n, 0, | ||
586 | (struct sockaddr *) &sockudp6_w, | ||
587 | sizeof (struct sockaddr_in6)); | ||
588 | |||
589 | if (n < 0) | ||
590 | { | ||
591 | PRINT_SOCKET_ERROR ("sendto"); | ||
592 | closesocket (sudp); | ||
593 | return devlist; | ||
594 | } | ||
595 | } | ||
596 | /* Waiting for SSDP REPLY packet to M-SEARCH */ | ||
597 | n = ReceiveData (sudp, bufr, sizeof (bufr), delay); | ||
598 | |||
599 | if (n < 0) | ||
600 | { | ||
601 | /* error */ | ||
602 | closesocket (sudp); | ||
603 | return devlist; | ||
604 | } | ||
605 | else if (n == 0) | ||
606 | { | ||
607 | /* no data or Time Out */ | ||
608 | if (devlist || (deviceList[deviceIndex] == 0)) | ||
609 | { | ||
610 | /* no more device type to look for... */ | ||
611 | closesocket (sudp); | ||
612 | return devlist; | ||
613 | } | ||
614 | } | ||
615 | else | ||
616 | { | ||
617 | const char *descURL = NULL; | ||
618 | int urlsize = 0; | ||
619 | const char *st = NULL; | ||
620 | int stsize = 0; | ||
621 | /*printf("%d byte(s) :\n%s\n", n, bufr); *//* affichage du message */ | ||
622 | parseMSEARCHReply (bufr, n, &descURL, &urlsize, &st, &stsize); | ||
623 | if (st && descURL) | ||
624 | { | ||
625 | /*printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n", | ||
626 | stsize, st, urlsize, descURL); */ | ||
627 | tmp = | ||
628 | (struct UPNPDev *) malloc (sizeof (struct UPNPDev) + urlsize + | ||
629 | stsize); | ||
630 | tmp->pNext = devlist; | ||
631 | tmp->descURL = tmp->buffer; | ||
632 | tmp->st = tmp->buffer + 1 + urlsize; | ||
633 | memcpy (tmp->buffer, descURL, urlsize); | ||
634 | tmp->buffer[urlsize] = '\0'; | ||
635 | memcpy (tmp->buffer + urlsize + 1, st, stsize); | ||
636 | tmp->buffer[urlsize + 1 + stsize] = '\0'; | ||
637 | devlist = tmp; | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | } | ||
642 | |||
643 | /* freeUPNPDevlist() should be used to | ||
644 | * free the chained list returned by upnpDiscover() */ | ||
645 | void | ||
646 | freeUPNPDevlist (struct UPNPDev *devlist) | ||
647 | { | ||
648 | struct UPNPDev *next; | ||
649 | while (devlist) | ||
650 | { | ||
651 | next = devlist->pNext; | ||
652 | free (devlist); | ||
653 | devlist = next; | ||
654 | } | ||
655 | } | ||
656 | |||
657 | static void | ||
658 | url_cpy_or_cat (char *dst, const char *src, int n) | ||
659 | { | ||
660 | if ((src[0] == 'h') | ||
661 | && (src[1] == 't') | ||
662 | && (src[2] == 't') | ||
663 | && (src[3] == 'p') | ||
664 | && (src[4] == ':') && (src[5] == '/') && (src[6] == '/')) | ||
665 | { | ||
666 | strncpy (dst, src, n); | ||
667 | } | ||
668 | else | ||
669 | { | ||
670 | int l = strlen (dst); | ||
671 | if (src[0] != '/') | ||
672 | dst[l++] = '/'; | ||
673 | if (l <= n) | ||
674 | strncpy (dst + l, src, n - l); | ||
675 | } | ||
676 | } | ||
677 | |||
678 | /* Prepare the Urls for usage... | ||
679 | */ | ||
680 | void | ||
681 | GetUPNPUrls (struct UPNPUrls *urls, struct IGDdatas *data, | ||
682 | const char *descURL) | ||
683 | { | ||
684 | char *p; | ||
685 | int n1, n2, n3; | ||
686 | n1 = strlen (data->urlbase); | ||
687 | if (n1 == 0) | ||
688 | n1 = strlen (descURL); | ||
689 | n1 += 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */ | ||
690 | n2 = n1; | ||
691 | n3 = n1; | ||
692 | n1 += strlen (data->scpdurl); | ||
693 | n2 += strlen (data->controlurl); | ||
694 | n3 += strlen (data->controlurl_CIF); | ||
695 | |||
696 | urls->ipcondescURL = (char *) malloc (n1); | ||
697 | urls->controlURL = (char *) malloc (n2); | ||
698 | urls->controlURL_CIF = (char *) malloc (n3); | ||
699 | /* maintenant on chope la desc du WANIPConnection */ | ||
700 | if (data->urlbase[0] != '\0') | ||
701 | strncpy (urls->ipcondescURL, data->urlbase, n1); | ||
702 | else | ||
703 | strncpy (urls->ipcondescURL, descURL, n1); | ||
704 | p = strchr (urls->ipcondescURL + 7, '/'); | ||
705 | if (p) | ||
706 | p[0] = '\0'; | ||
707 | strncpy (urls->controlURL, urls->ipcondescURL, n2); | ||
708 | strncpy (urls->controlURL_CIF, urls->ipcondescURL, n3); | ||
709 | |||
710 | url_cpy_or_cat (urls->ipcondescURL, data->scpdurl, n1); | ||
711 | |||
712 | url_cpy_or_cat (urls->controlURL, data->controlurl, n2); | ||
713 | |||
714 | url_cpy_or_cat (urls->controlURL_CIF, data->controlurl_CIF, n3); | ||
715 | |||
716 | #ifdef DEBUG | ||
717 | printf ("urls->ipcondescURL='%s' %d n1=%d\n", urls->ipcondescURL, | ||
718 | strlen (urls->ipcondescURL), n1); | ||
719 | printf ("urls->controlURL='%s' %d n2=%d\n", urls->controlURL, | ||
720 | strlen (urls->controlURL), n2); | ||
721 | printf ("urls->controlURL_CIF='%s' %d n3=%d\n", urls->controlURL_CIF, | ||
722 | strlen (urls->controlURL_CIF), n3); | ||
723 | #endif | ||
724 | } | ||
725 | |||
726 | void | ||
727 | FreeUPNPUrls (struct UPNPUrls *urls) | ||
728 | { | ||
729 | if (!urls) | ||
730 | return; | ||
731 | free (urls->controlURL); | ||
732 | urls->controlURL = 0; | ||
733 | free (urls->ipcondescURL); | ||
734 | urls->ipcondescURL = 0; | ||
735 | free (urls->controlURL_CIF); | ||
736 | urls->controlURL_CIF = 0; | ||
737 | } | ||
738 | |||
739 | |||
740 | int | ||
741 | ReceiveData (int socket, char *data, int length, int timeout) | ||
742 | { | ||
743 | int n; | ||
744 | #ifndef WIN32 | ||
745 | struct pollfd fds[1]; /* for the poll */ | ||
746 | fds[0].fd = socket; | ||
747 | fds[0].events = POLLIN; | ||
748 | n = poll (fds, 1, timeout); | ||
749 | if (n < 0) | ||
750 | { | ||
751 | PRINT_SOCKET_ERROR ("poll"); | ||
752 | return -1; | ||
753 | } | ||
754 | else if (n == 0) | ||
755 | { | ||
756 | return 0; | ||
757 | } | ||
758 | #else | ||
759 | fd_set socketSet; | ||
760 | TIMEVAL timeval; | ||
761 | FD_ZERO (&socketSet); | ||
762 | FD_SET (socket, &socketSet); | ||
763 | timeval.tv_sec = timeout / 1000; | ||
764 | timeval.tv_usec = (timeout % 1000) * 1000; | ||
765 | /*n = select(0, &socketSet, NULL, NULL, &timeval); */ | ||
766 | n = select (FD_SETSIZE, &socketSet, NULL, NULL, &timeval); | ||
767 | if (n < 0) | ||
768 | { | ||
769 | PRINT_SOCKET_ERROR ("select"); | ||
770 | return -1; | ||
771 | } | ||
772 | else if (n == 0) | ||
773 | { | ||
774 | return 0; | ||
775 | } | ||
776 | #endif | ||
777 | n = recv (socket, data, length, 0); | ||
778 | if (n < 0) | ||
779 | { | ||
780 | PRINT_SOCKET_ERROR ("recv"); | ||
781 | } | ||
782 | return n; | ||
783 | } | ||
784 | |||
785 | int | ||
786 | UPNPIGD_IsConnected (struct UPNPUrls *urls, struct IGDdatas *data) | ||
787 | { | ||
788 | char status[64]; | ||
789 | unsigned int uptime; | ||
790 | status[0] = '\0'; | ||
791 | UPNP_GetStatusInfo (urls->controlURL, data->servicetype, | ||
792 | status, &uptime, NULL); | ||
793 | if (0 == strcmp ("Connected", status)) | ||
794 | { | ||
795 | return 1; | ||
796 | } | ||
797 | else | ||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | |||
802 | /* UPNP_GetValidIGD() : | ||
803 | * return values : | ||
804 | * 0 = NO IGD found | ||
805 | * 1 = A valid connected IGD has been found | ||
806 | * 2 = A valid IGD has been found but it reported as | ||
807 | * not connected | ||
808 | * 3 = an UPnP device has been found but was not recognized as an IGD | ||
809 | * | ||
810 | * In any non zero return case, the urls and data structures | ||
811 | * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to | ||
812 | * free allocated memory. | ||
813 | */ | ||
814 | int | ||
815 | UPNP_GetValidIGD (struct UPNPDev *devlist, | ||
816 | struct UPNPUrls *urls, | ||
817 | struct IGDdatas *data, char *lanaddr, int lanaddrlen) | ||
818 | { | ||
819 | char *descXML; | ||
820 | int descXMLsize = 0; | ||
821 | struct UPNPDev *dev; | ||
822 | int ndev = 0; | ||
823 | int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ | ||
824 | if (!devlist) | ||
825 | { | ||
826 | #ifdef DEBUG | ||
827 | printf ("Empty devlist\n"); | ||
828 | #endif | ||
829 | return 0; | ||
830 | } | ||
831 | for (state = 1; state <= 3; state++) | ||
832 | { | ||
833 | for (dev = devlist; dev; dev = dev->pNext) | ||
834 | { | ||
835 | /* we should choose an internet gateway device. | ||
836 | * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ | ||
837 | descXML = miniwget_getaddr (dev->descURL, &descXMLsize, | ||
838 | lanaddr, lanaddrlen); | ||
839 | if (descXML) | ||
840 | { | ||
841 | ndev++; | ||
842 | memset (data, 0, sizeof (struct IGDdatas)); | ||
843 | memset (urls, 0, sizeof (struct UPNPUrls)); | ||
844 | parserootdesc (descXML, descXMLsize, data); | ||
845 | free (descXML); | ||
846 | descXML = NULL; | ||
847 | if (0 == strcmp (data->servicetype_CIF, | ||
848 | "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1") | ||
849 | || state >= 3) | ||
850 | { | ||
851 | GetUPNPUrls (urls, data, dev->descURL); | ||
852 | |||
853 | #ifdef DEBUG | ||
854 | printf ("UPNPIGD_IsConnected(%s) = %d\n", | ||
855 | urls->controlURL, UPNPIGD_IsConnected (urls, data)); | ||
856 | #endif | ||
857 | if ((state >= 2) || UPNPIGD_IsConnected (urls, data)) | ||
858 | return state; | ||
859 | FreeUPNPUrls (urls); | ||
860 | } | ||
861 | memset (data, 0, sizeof (struct IGDdatas)); | ||
862 | } | ||
863 | #ifdef DEBUG | ||
864 | else | ||
865 | { | ||
866 | printf ("error getting XML description %s\n", dev->descURL); | ||
867 | } | ||
868 | #endif | ||
869 | } | ||
870 | } | ||
871 | return 0; | ||
872 | } | ||
873 | |||
874 | /* UPNP_GetIGDFromUrl() | ||
875 | * Used when skipping the discovery process. | ||
876 | * return value : | ||
877 | * 0 - Not ok | ||
878 | * 1 - OK */ | ||
879 | int | ||
880 | UPNP_GetIGDFromUrl (const char *rootdescurl, | ||
881 | struct UPNPUrls *urls, | ||
882 | struct IGDdatas *data, char *lanaddr, int lanaddrlen) | ||
883 | { | ||
884 | char *descXML; | ||
885 | int descXMLsize = 0; | ||
886 | descXML = miniwget_getaddr (rootdescurl, &descXMLsize, lanaddr, lanaddrlen); | ||
887 | if (descXML) | ||
888 | { | ||
889 | memset (data, 0, sizeof (struct IGDdatas)); | ||
890 | memset (urls, 0, sizeof (struct UPNPUrls)); | ||
891 | parserootdesc (descXML, descXMLsize, data); | ||
892 | free (descXML); | ||
893 | descXML = NULL; | ||
894 | GetUPNPUrls (urls, data, rootdescurl); | ||
895 | return 1; | ||
896 | } | ||
897 | else | ||
898 | { | ||
899 | return 0; | ||
900 | } | ||
901 | } | ||