minissdpc.c 25 KB

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