Annotation of embedaddon/miniupnpc/src/minissdpc.c, revision 1.1.1.1
1.1 misho 1: /* $Id: minissdpc.c,v 1.49 2021/05/13 11:00:36 nanard Exp $ */
2: /* vim: tabstop=4 shiftwidth=4 noexpandtab
3: * Project : miniupnp
4: * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
5: * Author : Thomas BERNARD
6: * copyright (c) 2005-2021 Thomas Bernard
7: * This software is subjet to the conditions detailed in the
8: * provided LICENCE file. */
9: #include <stdio.h>
10: #include <string.h>
11: #include <stdlib.h>
12: #include <time.h>
13: #include <sys/types.h>
14: #if defined (__NetBSD__)
15: #include <net/if.h>
16: #endif
17: #if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)
18: #ifdef _WIN32
19: #include <winsock2.h>
20: #include <ws2tcpip.h>
21: #include <io.h>
22: #include <iphlpapi.h>
23: #include "win32_snprintf.h"
24: #if !defined(_MSC_VER)
25: #include <stdint.h>
26: #else /* !defined(_MSC_VER) */
27: typedef unsigned short uint16_t;
28: #endif /* !defined(_MSC_VER) */
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: #if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PARTITION)
37: #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP
38: #define in6addr_any in6addr_any_init
39: static const IN6_ADDR in6addr_any_init = {0};
40: #endif
41: #endif
42: #endif /* _WIN32 */
43: #if defined(__amigaos__) || defined(__amigaos4__)
44: #include <sys/socket.h>
45: #endif /* defined(__amigaos__) || defined(__amigaos4__) */
46: #if defined(__amigaos__)
47: #define uint16_t unsigned short
48: #endif /* defined(__amigaos__) */
49: /* Hack */
50: #define UNIX_PATH_LEN 108
51: struct sockaddr_un {
52: uint16_t sun_family;
53: char sun_path[UNIX_PATH_LEN];
54: };
55: #else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */
56: #include <strings.h>
57: #include <unistd.h>
58: #include <sys/socket.h>
59: #include <sys/param.h>
60: #include <sys/time.h>
61: #include <sys/un.h>
62: #include <netinet/in.h>
63: #include <arpa/inet.h>
64: #include <netdb.h>
65: #include <net/if.h>
66: #define closesocket close
67: #endif
68:
69: #include "miniupnpc_socketdef.h"
70:
71: #if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__) && !defined(__HAIKU__)
72: #define HAS_IP_MREQN
73: #endif
74:
75: #ifndef _WIN32
76: #include <sys/ioctl.h>
77: #if defined(__sun) || defined(__HAIKU__)
78: #include <sys/sockio.h>
79: #endif
80: #endif
81:
82: #if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN)
83: /* Several versions of glibc don't define this structure,
84: * define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */
85: struct ip_mreqn
86: {
87: struct in_addr imr_multiaddr; /* IP multicast address of group */
88: struct in_addr imr_address; /* local IP address of interface */
89: int imr_ifindex; /* Interface index */
90: };
91: #endif
92:
93: #if defined(__amigaos__) || defined(__amigaos4__)
94: /* Amiga OS specific stuff */
95: #define TIMEVAL struct timeval
96: #endif
97:
98: #include "minissdpc.h"
99: #include "miniupnpc.h"
100: #include "receivedata.h"
101:
102: #if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
103:
104: #include "codelength.h"
105:
106: struct UPNPDev *
107: getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error)
108: {
109: struct UPNPDev * devlist = NULL;
110: int s;
111: int res;
112:
113: s = connectToMiniSSDPD(socketpath);
114: if (s < 0) {
115: if (error)
116: *error = s;
117: return NULL;
118: }
119: res = requestDevicesFromMiniSSDPD(s, devtype);
120: if (res < 0) {
121: if (error)
122: *error = res;
123: } else {
124: devlist = receiveDevicesFromMiniSSDPD(s, error);
125: }
126: disconnectFromMiniSSDPD(s);
127: return devlist;
128: }
129:
130: /* macros used to read from unix socket */
131: #define READ_BYTE_BUFFER(c) \
132: if((int)bufferindex >= n) { \
133: n = read(s, buffer, sizeof(buffer)); \
134: if(n<=0) break; \
135: bufferindex = 0; \
136: } \
137: c = buffer[bufferindex++];
138:
139: #ifndef MIN
140: #define MIN(a, b) (((a) < (b)) ? (a) : (b))
141: #endif /* MIN */
142:
143: #define READ_COPY_BUFFER(dst, len) \
144: for(l = len, p = (unsigned char *)dst; l > 0; ) { \
145: unsigned int lcopy; \
146: if((int)bufferindex >= n) { \
147: n = read(s, buffer, sizeof(buffer)); \
148: if(n<=0) break; \
149: bufferindex = 0; \
150: } \
151: lcopy = MIN(l, (n - bufferindex)); \
152: memcpy(p, buffer + bufferindex, lcopy); \
153: l -= lcopy; \
154: p += lcopy; \
155: bufferindex += lcopy; \
156: }
157:
158: #define READ_DISCARD_BUFFER(len) \
159: for(l = len; l > 0; ) { \
160: unsigned int lcopy; \
161: if(bufferindex >= n) { \
162: n = read(s, buffer, sizeof(buffer)); \
163: if(n<=0) break; \
164: bufferindex = 0; \
165: } \
166: lcopy = MIN(l, (n - bufferindex)); \
167: l -= lcopy; \
168: bufferindex += lcopy; \
169: }
170:
171: int
172: connectToMiniSSDPD(const char * socketpath)
173: {
174: int s;
175: struct sockaddr_un addr;
176: #if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun)
177: struct timeval timeout;
178: #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
179:
180: s = socket(AF_UNIX, SOCK_STREAM, 0);
181: if(s < 0)
182: {
183: /*syslog(LOG_ERR, "socket(unix): %m");*/
184: perror("socket(unix)");
185: return MINISSDPC_SOCKET_ERROR;
186: }
187: #if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun)
188: /* setting a 3 seconds timeout */
189: /* not supported for AF_UNIX sockets under Solaris */
190: timeout.tv_sec = 3;
191: timeout.tv_usec = 0;
192: if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
193: {
194: perror("setsockopt SO_RCVTIMEO unix");
195: }
196: timeout.tv_sec = 3;
197: timeout.tv_usec = 0;
198: if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
199: {
200: perror("setsockopt SO_SNDTIMEO unix");
201: }
202: #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
203: if(!socketpath)
204: socketpath = "/var/run/minissdpd.sock";
205: memset(&addr, 0, sizeof(addr));
206: addr.sun_family = AF_UNIX;
207: strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
208: /* TODO : check if we need to handle the EINTR */
209: if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0)
210: {
211: /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
212: close(s);
213: return MINISSDPC_SOCKET_ERROR;
214: }
215: return s;
216: }
217:
218: int
219: disconnectFromMiniSSDPD(int s)
220: {
221: if (close(s) < 0)
222: return MINISSDPC_SOCKET_ERROR;
223: return MINISSDPC_SUCCESS;
224: }
225:
226: int
227: requestDevicesFromMiniSSDPD(int s, const char * devtype)
228: {
229: unsigned char buffer[256];
230: unsigned char * p;
231: unsigned int stsize, l;
232:
233: stsize = strlen(devtype);
234: if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8))
235: {
236: buffer[0] = 3; /* request type 3 : everything */
237: }
238: else
239: {
240: buffer[0] = 1; /* request type 1 : request devices/services by type */
241: }
242: p = buffer + 1;
243: l = stsize; CODELENGTH(l, p);
244: if(p + stsize > buffer + sizeof(buffer))
245: {
246: /* devtype is too long ! */
247: #ifdef DEBUG
248: fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n",
249: stsize, (unsigned)sizeof(buffer));
250: #endif /* DEBUG */
251: return MINISSDPC_INVALID_INPUT;
252: }
253: memcpy(p, devtype, stsize);
254: p += stsize;
255: if(write(s, buffer, p - buffer) < 0)
256: {
257: /*syslog(LOG_ERR, "write(): %m");*/
258: perror("minissdpc.c: write()");
259: return MINISSDPC_SOCKET_ERROR;
260: }
261: return MINISSDPC_SUCCESS;
262: }
263:
264: struct UPNPDev *
265: receiveDevicesFromMiniSSDPD(int s, int * error)
266: {
267: struct UPNPDev * tmp;
268: struct UPNPDev * devlist = NULL;
269: unsigned char buffer[256];
270: ssize_t n;
271: unsigned char * p;
272: unsigned char * url;
273: unsigned char * st;
274: unsigned int bufferindex;
275: unsigned int i, ndev;
276: unsigned int urlsize, stsize, usnsize, l;
277:
278: n = read(s, buffer, sizeof(buffer));
279: if(n<=0)
280: {
281: perror("minissdpc.c: read()");
282: if (error)
283: *error = MINISSDPC_SOCKET_ERROR;
284: return NULL;
285: }
286: ndev = buffer[0];
287: bufferindex = 1;
288: for(i = 0; i < ndev; i++)
289: {
290: DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER);
291: if(n<=0) {
292: if (error)
293: *error = MINISSDPC_INVALID_SERVER_REPLY;
294: return devlist;
295: }
296: #ifdef DEBUG
297: printf(" urlsize=%u", urlsize);
298: #endif /* DEBUG */
299: url = malloc(urlsize);
300: if(url == NULL) {
301: if (error)
302: *error = MINISSDPC_MEMORY_ERROR;
303: return devlist;
304: }
305: READ_COPY_BUFFER(url, urlsize);
306: if(n<=0) {
307: if (error)
308: *error = MINISSDPC_INVALID_SERVER_REPLY;
309: goto free_url_and_return;
310: }
311: DECODELENGTH_READ(stsize, READ_BYTE_BUFFER);
312: if(n<=0) {
313: if (error)
314: *error = MINISSDPC_INVALID_SERVER_REPLY;
315: goto free_url_and_return;
316: }
317: #ifdef DEBUG
318: printf(" stsize=%u", stsize);
319: #endif /* DEBUG */
320: st = malloc(stsize);
321: if (st == NULL) {
322: if (error)
323: *error = MINISSDPC_MEMORY_ERROR;
324: goto free_url_and_return;
325: }
326: READ_COPY_BUFFER(st, stsize);
327: if(n<=0) {
328: if (error)
329: *error = MINISSDPC_INVALID_SERVER_REPLY;
330: goto free_url_and_st_and_return;
331: }
332: DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER);
333: if(n<=0) {
334: if (error)
335: *error = MINISSDPC_INVALID_SERVER_REPLY;
336: goto free_url_and_st_and_return;
337: }
338: #ifdef DEBUG
339: printf(" usnsize=%u\n", usnsize);
340: #endif /* DEBUG */
341: tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
342: if(tmp == NULL) {
343: if (error)
344: *error = MINISSDPC_MEMORY_ERROR;
345: goto free_url_and_st_and_return;
346: }
347: tmp->pNext = devlist;
348: tmp->descURL = tmp->buffer;
349: tmp->st = tmp->buffer + 1 + urlsize;
350: memcpy(tmp->buffer, url, urlsize);
351: tmp->buffer[urlsize] = '\0';
352: memcpy(tmp->st, st, stsize);
353: tmp->buffer[urlsize+1+stsize] = '\0';
354: free(url);
355: free(st);
356: url = NULL;
357: st = NULL;
358: tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize;
359: READ_COPY_BUFFER(tmp->usn, usnsize);
360: if(n<=0) {
361: if (error)
362: *error = MINISSDPC_INVALID_SERVER_REPLY;
363: goto free_tmp_and_return;
364: }
365: tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
366: tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */
367: devlist = tmp;
368: }
369: if (error)
370: *error = MINISSDPC_SUCCESS;
371: return devlist;
372:
373: free_url_and_st_and_return:
374: free(st);
375: free_url_and_return:
376: free(url);
377: return devlist;
378:
379: free_tmp_and_return:
380: free(tmp);
381: return devlist;
382: }
383:
384: #endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
385:
386: /* parseMSEARCHReply()
387: * the last 4 arguments are filled during the parsing :
388: * - location/locationsize : "location:" field of the SSDP reply packet
389: * - st/stsize : "st:" field of the SSDP reply packet.
390: * - usn/usnsize : "usn:" filed of the SSDP reply packet
391: * The strings are NOT null terminated */
392: static void
393: parseMSEARCHReply(const char * reply, int size,
394: const char * * location, int * locationsize,
395: const char * * st, int * stsize,
396: const char * * usn, int * usnsize)
397: {
398: int a, b, i;
399: i = 0;
400: a = i; /* start of the line */
401: b = 0; /* end of the "header" (position of the colon) */
402: while(i<size)
403: {
404: switch(reply[i])
405: {
406: case ':':
407: if(b==0)
408: {
409: b = i; /* end of the "header" */
410: /*for(j=a; j<b; j++)
411: {
412: putchar(reply[j]);
413: }
414: */
415: }
416: break;
417: case '\x0a':
418: case '\x0d':
419: if(b!=0)
420: {
421: /*for(j=b+1; j<i; j++)
422: {
423: putchar(reply[j]);
424: }
425: putchar('\n');*/
426: /* skip the colon and white spaces */
427: do { b++; } while(reply[b]==' ');
428: if(0==strncasecmp(reply+a, "location:", 9))
429: {
430: *location = reply+b;
431: *locationsize = i-b;
432: }
433: else if(0==strncasecmp(reply+a, "st:", 3))
434: {
435: *st = reply+b;
436: *stsize = i-b;
437: }
438: else if(0==strncasecmp(reply+a, "usn:", 4))
439: {
440: *usn = reply+b;
441: *usnsize = i-b;
442: }
443: b = 0;
444: }
445: a = i+1;
446: break;
447: default:
448: break;
449: }
450: i++;
451: }
452: }
453:
454: #if defined(CLOCK_MONOTONIC_FAST)
455: #define UPNP_CLOCKID CLOCK_MONOTONIC_FAST
456: #elif defined(CLOCK_MONOTONIC)
457: #define UPNP_CLOCKID CLOCK_MONOTONIC
458: #endif
459:
460: static int upnp_gettimeofday(struct timeval * tv)
461: {
462: #if defined(_WIN32)
463: #if _WIN32_WINNT >= 0x0600 // _WIN32_WINNT_VISTA
464: ULONGLONG ts = GetTickCount64();
465: #else
466: DWORD ts = GetTickCount();
467: #endif
468: tv->tv_sec = (long)(ts / 1000);
469: tv->tv_usec = (ts % 1000) * 1000;
470: return 0; /* success */
471: #elif defined(CLOCK_MONOTONIC_FAST) || defined(CLOCK_MONOTONIC)
472: #if defined(__APPLE__)
473: #if defined(__clang__)
474: if (__builtin_available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)) {
475: #else /* !defined(__clang__) */
476: if (clock_gettime != NULL) {
477: #endif /* defined(__clang__) */
478: #endif /* defined(__APPLE__) */
479: struct timespec ts;
480: int ret_code = clock_gettime(UPNP_CLOCKID, &ts);
481: if (ret_code == 0)
482: {
483: tv->tv_sec = ts.tv_sec;
484: tv->tv_usec = ts.tv_nsec / 1000;
485: }
486: return ret_code;
487: #if defined(__APPLE__)
488: }
489: else
490: {
491: /* fall-back for earlier Apple platforms */
492: return gettimeofday(tv, NULL);
493: }
494: #endif /* defined(__APPLE__) */
495: #else
496: return gettimeofday(tv, NULL);
497: #endif
498: }
499: /* port upnp discover : SSDP protocol */
500: #define SSDP_PORT 1900
501: #define XSTR(s) STR(s)
502: #define STR(s) #s
503: #define UPNP_MCAST_ADDR "239.255.255.250"
504: /* for IPv6 */
505: #define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
506: #define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
507:
508: /* direct discovery if minissdpd responses are not sufficient */
509: /* ssdpDiscoverDevices() :
510: * return a chained list of all devices found or NULL if
511: * no devices was found.
512: * It is up to the caller to free the chained list
513: * delay is in millisecond (poll).
514: * UDA v1.1 says :
515: * The TTL for the IP packet SHOULD default to 2 and
516: * SHOULD be configurable. */
517: struct UPNPDev *
518: ssdpDiscoverDevices(const char * const deviceTypes[],
519: int delay, const char * multicastif,
520: int localport,
521: int ipv6, unsigned char ttl,
522: int * error,
523: int searchalltypes)
524: {
525: struct UPNPDev * tmp;
526: struct UPNPDev * devlist = NULL;
527: unsigned int scope_id = 0;
528: int opt = 1;
529: static const char MSearchMsgFmt[] =
530: "M-SEARCH * HTTP/1.1\r\n"
531: "HOST: %s:" XSTR(SSDP_PORT) "\r\n"
532: "ST: %s\r\n"
533: "MAN: \"ssdp:discover\"\r\n"
534: "MX: %u\r\n"
535: "\r\n";
536: int deviceIndex;
537: char bufr[1536]; /* reception and emission buffer */
538: SOCKET sudp;
539: int n;
540: struct sockaddr_storage sockudp_r;
541: unsigned int mx;
542: #ifdef NO_GETADDRINFO
543: struct sockaddr_storage sockudp_w;
544: #else
545: int rv;
546: struct addrinfo hints, *servinfo;
547: #endif
548: #ifdef _WIN32
549: unsigned long _ttl = (unsigned long)ttl;
550: #endif
551: int linklocal = 1;
552: int sentok;
553:
554: if(error)
555: *error = MINISSDPC_UNKNOWN_ERROR;
556:
557: if(localport==UPNP_LOCAL_PORT_SAME)
558: localport = SSDP_PORT;
559:
560: #ifdef _WIN32
561: sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
562: #else
563: sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
564: #endif
565: if(ISINVALID(sudp))
566: {
567: if(error)
568: *error = MINISSDPC_SOCKET_ERROR;
569: PRINT_SOCKET_ERROR("socket");
570: return NULL;
571: }
572: /* reception */
573: memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
574: if(ipv6) {
575: struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
576: p->sin6_family = AF_INET6;
577: if(localport > 0 && localport < 65536)
578: p->sin6_port = htons((unsigned short)localport);
579: p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
580: } else {
581: struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
582: p->sin_family = AF_INET;
583: if(localport > 0 && localport < 65536)
584: p->sin_port = htons((unsigned short)localport);
585: p->sin_addr.s_addr = INADDR_ANY;
586: }
587: #ifdef _WIN32
588: /* This code could help us to use the right Network interface for
589: * SSDP multicast traffic */
590: /* Get IP associated with the index given in the ip_forward struct
591: * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
592: if(!ipv6) {
593: DWORD ifbestidx;
594: #if _WIN32_WINNT >= 0x0600 // _WIN32_WINNT_VISTA
595: // While we don't need IPv6 support, the IPv4 only funciton is not available in UWP apps.
596: SOCKADDR_IN destAddr;
597: memset(&destAddr, 0, sizeof(destAddr));
598: destAddr.sin_family = AF_INET;
599: destAddr.sin_addr.s_addr = inet_addr("223.255.255.255");
600: destAddr.sin_port = 0;
601: if (GetBestInterfaceEx((struct sockaddr *)&destAddr, &ifbestidx) == NO_ERROR) {
602: #else
603: if (GetBestInterface(inet_addr("223.255.255.255"), &ifbestidx) == NO_ERROR) {
604: #endif
605: DWORD dwRetVal = NO_ERROR;
606: PIP_ADAPTER_ADDRESSES pAddresses = NULL;
607: ULONG outBufLen = 15360;
608: int Iterations;
609: PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
610: PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
611:
612: for (Iterations = 0; Iterations < 3; Iterations++) {
613: pAddresses = (IP_ADAPTER_ADDRESSES *) HeapAlloc(GetProcessHeap(), 0, outBufLen);
614: if (pAddresses == NULL) {
615: break;
616: }
617:
618: dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &outBufLen);
619:
620: if (dwRetVal != ERROR_BUFFER_OVERFLOW) {
621: break;
622: }
623: HeapFree(GetProcessHeap(), 0, pAddresses);
624: pAddresses = NULL;
625: }
626:
627: if (dwRetVal == NO_ERROR) {
628: pCurrAddresses = pAddresses;
629: while (pCurrAddresses) {
630: #ifdef DEBUG
631: int i;
632: PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
633: PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
634:
635: printf("\tIfIndex (IPv4 interface): %u\n", pCurrAddresses->IfIndex);
636: printf("\tAdapter name: %s\n", pCurrAddresses->AdapterName);
637: pUnicast = pCurrAddresses->FirstUnicastAddress;
638: if (pUnicast != NULL) {
639: for (i = 0; pUnicast != NULL; i++) {
640: printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(((PSOCKADDR_IN)pUnicast->Address.lpSockaddr)->sin_addr) );
641: pUnicast = pUnicast->Next;
642: }
643: printf("\tNumber of Unicast Addresses: %d\n", i);
644: }
645: pAnycast = pCurrAddresses->FirstAnycastAddress;
646: if (pAnycast) {
647: for (i = 0; pAnycast != NULL; i++) {
648: printf("\tAnycast Address[%d]: \t%s\n", i, inet_ntoa(((PSOCKADDR_IN)pAnycast->Address.lpSockaddr)->sin_addr) );
649: pAnycast = pAnycast->Next;
650: }
651: printf("\tNumber of Anycast Addresses: %d\n", i);
652: }
653: pMulticast = pCurrAddresses->FirstMulticastAddress;
654: if (pMulticast) {
655: for (i = 0; pMulticast != NULL; i++) {
656: printf("\tMulticast Address[%d]: \t%s\n", i, inet_ntoa(((PSOCKADDR_IN)pMulticast->Address.lpSockaddr)->sin_addr) );
657: pMulticast = pMulticast->Next;
658: }
659: }
660: printf("\n");
661: #endif
662: pUnicast = pCurrAddresses->FirstUnicastAddress;
663: if (pCurrAddresses->IfIndex == ifbestidx && pUnicast != NULL) {
664: SOCKADDR_IN *ipv4 = (SOCKADDR_IN *)(pUnicast->Address.lpSockaddr);
665: /* Set the address of this interface to be used */
666: struct in_addr mc_if;
667: memset(&mc_if, 0, sizeof(mc_if));
668: mc_if.s_addr = ipv4->sin_addr.s_addr;
669: if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
670: PRINT_SOCKET_ERROR("setsockopt");
671: }
672: ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = ipv4->sin_addr.s_addr;
673: #ifndef DEBUG
674: break;
675: #endif
676: }
677: pCurrAddresses = pCurrAddresses->Next;
678: }
679: }
680: if (pAddresses != NULL) {
681: HeapFree(GetProcessHeap(), 0, pAddresses);
682: pAddresses = NULL;
683: }
684: }
685: }
686: #endif /* _WIN32 */
687:
688: #ifdef _WIN32
689: if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
690: #else
691: if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
692: #endif
693: {
694: if(error)
695: *error = MINISSDPC_SOCKET_ERROR;
696: PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)");
697: goto error;
698: }
699:
700: if(ipv6) {
701: #ifdef _WIN32
702: DWORD mcastHops = ttl;
703: if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char *)&mcastHops, sizeof(mcastHops)) < 0)
704: #else /* _WIN32 */
705: int mcastHops = ttl;
706: if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastHops, sizeof(mcastHops)) < 0)
707: #endif /* _WIN32 */
708: {
709: PRINT_SOCKET_ERROR("setsockopt(IPV6_MULTICAST_HOPS,...)");
710: }
711: } else {
712: #ifdef _WIN32
713: if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0)
714: #else /* _WIN32 */
715: if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
716: #endif /* _WIN32 */
717: {
718: /* not a fatal error */
719: PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)");
720: }
721: }
722:
723: if(multicastif && multicastif[0] != '\0')
724: {
725: if(ipv6) {
726: #if !defined(_WIN32)
727: /* according to MSDN, if_nametoindex() is supported since
728: * MS Windows Vista and MS Windows Server 2008.
729: * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
730: unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
731: if(ifindex == 0)
732: {
733: if(error)
734: *error = MINISSDPC_INVALID_INPUT;
735: fprintf(stderr, "Invalid multicast interface name %s\n", multicastif);
736: goto error;
737: }
738: if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0)
739: {
740: PRINT_SOCKET_ERROR("setsockopt IPV6_MULTICAST_IF");
741: }
742: #else
743: #ifdef DEBUG
744: printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
745: #endif
746: #endif
747: } else {
748: struct in_addr mc_if;
749: #if defined(_WIN32)
750: #if _WIN32_WINNT >= 0x0600 // _WIN32_WINNT_VISTA
751: InetPtonA(AF_INET, multicastif, &mc_if);
752: #else
753: mc_if.s_addr = inet_addr(multicastif); /* old Windows SDK do not support InetPtoA() */
754: #endif
755: #else
756: /* was : mc_if.s_addr = inet_addr(multicastif); */ /* ex: 192.168.x.x */
757: if (inet_pton(AF_INET, multicastif, &mc_if.s_addr) <= 0) {
758: mc_if.s_addr = INADDR_NONE;
759: }
760: #endif
761: if(mc_if.s_addr != INADDR_NONE)
762: {
763: ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
764: if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
765: {
766: PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
767: }
768: } else {
769: /* was not an ip address, try with an interface name */
770: #ifndef _WIN32
771: #ifdef HAS_IP_MREQN
772: struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
773: #endif
774: struct ifreq ifr;
775: int ifrlen = sizeof(ifr);
776: strncpy(ifr.ifr_name, multicastif, IFNAMSIZ);
777: ifr.ifr_name[IFNAMSIZ-1] = '\0';
778: if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0)
779: {
780: PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)");
781: goto error;
782: }
783: mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
784: #ifdef HAS_IP_MREQN
785: memset(&reqn, 0, sizeof(struct ip_mreqn));
786: reqn.imr_address.s_addr = mc_if.s_addr;
787: reqn.imr_ifindex = if_nametoindex(multicastif);
788: if(reqn.imr_ifindex == 0)
789: {
790: if(error)
791: *error = MINISSDPC_INVALID_INPUT;
792: fprintf(stderr, "Invalid multicast ip address / interface name %s\n", multicastif);
793: goto error;
794: }
795: if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
796: {
797: PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
798: }
799: #else
800: if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
801: {
802: PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
803: }
804: #endif
805: #else /* _WIN32 */
806: #ifdef DEBUG
807: printf("Setting of multicast interface not supported with interface name.\n");
808: #endif
809: #endif /* #ifdef HAS_IP_MREQN / !defined(_WIN32) */
810: }
811: }
812: }
813:
814: /* Before sending the packed, we first "bind" in order to be able
815: * to receive the response */
816: if (bind(sudp, (const struct sockaddr *)&sockudp_r,
817: ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
818: {
819: if(error)
820: *error = MINISSDPC_SOCKET_ERROR;
821: PRINT_SOCKET_ERROR("bind");
822: closesocket(sudp);
823: return NULL;
824: }
825:
826: if(error)
827: *error = MINISSDPC_SUCCESS;
828: /* Calculating maximum response time in seconds */
829: mx = ((unsigned int)delay) / 1000u;
830: if(mx == 0) {
831: mx = 1;
832: delay = 1000;
833: }
834: /* receiving SSDP response packet */
835: for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
836: sentok = 0;
837: /* sending the SSDP M-SEARCH packet */
838: n = snprintf(bufr, sizeof(bufr),
839: MSearchMsgFmt,
840: ipv6 ?
841: (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
842: : UPNP_MCAST_ADDR,
843: deviceTypes[deviceIndex], mx);
844: if ((unsigned int)n >= sizeof(bufr)) {
845: if(error)
846: *error = MINISSDPC_MEMORY_ERROR;
847: goto error;
848: }
849: #ifdef DEBUG
850: /*printf("Sending %s", bufr);*/
851: printf("Sending M-SEARCH request to %s with ST: %s\n",
852: ipv6 ?
853: (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
854: : UPNP_MCAST_ADDR,
855: deviceTypes[deviceIndex]);
856: #endif
857: #ifdef NO_GETADDRINFO
858: /* the following code is not using getaddrinfo */
859: /* emission */
860: memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
861: if(ipv6) {
862: struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
863: p->sin6_family = AF_INET6;
864: p->sin6_port = htons(SSDP_PORT);
865: inet_pton(AF_INET6,
866: linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
867: &(p->sin6_addr));
868: } else {
869: struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
870: p->sin_family = AF_INET;
871: p->sin_port = htons(SSDP_PORT);
872: p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
873: }
874: n = sendto(sudp, bufr, n, 0, &sockudp_w,
875: ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
876: if (n < 0) {
877: if(error)
878: *error = MINISSDPC_SOCKET_ERROR;
879: PRINT_SOCKET_ERROR("sendto");
880: } else {
881: sentok = 1;
882: }
883: #else /* #ifdef NO_GETADDRINFO */
884: memset(&hints, 0, sizeof(hints));
885: hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
886: hints.ai_socktype = SOCK_DGRAM;
887: /*hints.ai_flags = */
888: if ((rv = getaddrinfo(ipv6
889: ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
890: : UPNP_MCAST_ADDR,
891: XSTR(SSDP_PORT), &hints, &servinfo)) != 0) {
892: if(error)
893: *error = MINISSDPC_SOCKET_ERROR;
894: #ifdef _WIN32
895: fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
896: #else
897: fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
898: #endif
899: break;
900: } else {
901: struct addrinfo *p;
902: for(p = servinfo; p; p = p->ai_next) {
903: n = sendto(sudp, bufr, n, 0, p->ai_addr, MSC_CAST_INT p->ai_addrlen);
904: if (n < 0) {
905: #ifdef DEBUG
906: char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
907: if (getnameinfo(p->ai_addr, (socklen_t)p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
908: sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
909: fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
910: }
911: #endif
912: PRINT_SOCKET_ERROR("sendto");
913: continue;
914: } else {
915: sentok = 1;
916: }
917: }
918: freeaddrinfo(servinfo);
919: }
920: if(!sentok) {
921: if(error)
922: *error = MINISSDPC_SOCKET_ERROR;
923: }
924: #endif /* #ifdef NO_GETADDRINFO */
925: /* Waiting for SSDP REPLY packet to M-SEARCH
926: * if searchalltypes is set, enter the loop only
927: * when the last deviceType is reached */
928: if((sentok && !searchalltypes) || !deviceTypes[deviceIndex + 1]) {
929: struct timeval start = {0, 0}, current = {0, 0};
930: upnp_gettimeofday(&start);
931: do {
932: n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
933: if (n < 0) {
934: /* error */
935: if(error)
936: *error = MINISSDPC_SOCKET_ERROR;
937: goto error;
938: } else if (n == 0) {
939: /* no data or Time Out */
940: #ifdef DEBUG
941: printf("NODATA or TIMEOUT\n");
942: #endif /* DEBUG */
943: if (devlist && !searchalltypes) {
944: /* found some devices, stop now*/
945: if(error)
946: *error = MINISSDPC_SUCCESS;
947: goto error;
948: }
949: } else {
950: const char * descURL=NULL;
951: int urlsize=0;
952: const char * st=NULL;
953: int stsize=0;
954: const char * usn=NULL;
955: int usnsize=0;
956: parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
957: if(st&&descURL) {
958: #ifdef DEBUG
959: printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
960: stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
961: #endif /* DEBUG */
962: for(tmp=devlist; tmp; tmp = tmp->pNext) {
963: if(strncmp(tmp->descURL, descURL, urlsize) == 0 &&
964: tmp->descURL[urlsize] == '\0' &&
965: strncmp(tmp->st, st, stsize) == 0 &&
966: tmp->st[stsize] == '\0' &&
967: (usnsize == 0 || strncmp(tmp->usn, usn, usnsize) == 0) &&
968: tmp->usn[usnsize] == '\0')
969: break;
970: }
971: /* at the exit of the loop above, tmp is null if
972: * no duplicate device was found */
973: if(tmp)
974: continue;
975: tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize+3);
976: if(!tmp) {
977: /* memory allocation error */
978: if(error)
979: *error = MINISSDPC_MEMORY_ERROR;
980: goto error;
981: }
982: tmp->pNext = devlist;
983: tmp->descURL = tmp->buffer;
984: tmp->st = tmp->buffer + 1 + urlsize;
985: tmp->usn = tmp->st + 1 + stsize;
986: memcpy(tmp->buffer, descURL, urlsize);
987: tmp->buffer[urlsize] = '\0';
988: memcpy(tmp->st, st, stsize);
989: tmp->buffer[urlsize+1+stsize] = '\0';
990: if(usn != NULL)
991: memcpy(tmp->usn, usn, usnsize);
992: tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
993: tmp->scope_id = scope_id;
994: devlist = tmp;
995: }
996: if (upnp_gettimeofday(¤t) >= 0) {
997: /* exit the loop if delay is reached */
998: long interval = (current.tv_sec - start.tv_sec) * 1000;
999: interval += (current.tv_usec - start.tv_usec) / 1000;
1000: if (interval > (long)delay)
1001: break;
1002: }
1003: }
1004: } while(n > 0);
1005: }
1006: if(ipv6) {
1007: /* switch linklocal flag */
1008: if(linklocal) {
1009: linklocal = 0;
1010: --deviceIndex;
1011: } else {
1012: linklocal = 1;
1013: }
1014: }
1015: }
1016: error:
1017: closesocket(sudp);
1018: return devlist;
1019: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>