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