minissdpc.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. #define _CRT_SECURE_NO_WARNINGS
  2. /* $Id: minissdpc.c,v 1.31 2016/01/19 09:56:46 nanard Exp $ */
  3. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  4. * Project : miniupnp
  5. * Web : http://miniupnp.free.fr/
  6. * Author : Thomas BERNARD
  7. * copyright (c) 2005-2015 Thomas Bernard
  8. * This software is subjet to the conditions detailed in the
  9. * provided LICENCE file. */
  10. /*#include <syslog.h>*/
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <stdlib.h>
  14. #include <sys/types.h>
  15. #if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)
  16. #ifdef _WIN32
  17. #include <winsock2.h>
  18. #include <ws2tcpip.h>
  19. #include <io.h>
  20. #include <iphlpapi.h>
  21. #include <winsock.h>
  22. #define snprintf _snprintf
  23. #if !defined(_MSC_VER)
  24. #include <stdint.h>
  25. #else /* !defined(_MSC_VER) */
  26. typedef unsigned short uint16_t;
  27. #endif /* !defined(_MSC_VER) */
  28. #ifndef strncasecmp
  29. #if defined(_MSC_VER) && (_MSC_VER >= 1400)
  30. #define strncasecmp _memicmp
  31. #else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
  32. #define strncasecmp memicmp
  33. #endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
  34. #endif /* #ifndef strncasecmp */
  35. #endif /* _WIN32 */
  36. #if defined(__amigaos__) || defined(__amigaos4__)
  37. #include <sys/socket.h>
  38. #endif /* defined(__amigaos__) || defined(__amigaos4__) */
  39. #if defined(__amigaos__)
  40. #define uint16_t unsigned short
  41. #endif /* defined(__amigaos__) */
  42. /* Hack */
  43. #define UNIX_PATH_LEN 108
  44. struct sockaddr_un {
  45. uint16_t sun_family;
  46. char sun_path[UNIX_PATH_LEN];
  47. };
  48. #else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */
  49. #include <strings.h>
  50. #include <unistd.h>
  51. #include <sys/socket.h>
  52. #include <sys/param.h>
  53. #include <sys/time.h>
  54. #include <sys/un.h>
  55. #include <netinet/in.h>
  56. #include <arpa/inet.h>
  57. #include <netdb.h>
  58. #include <net/if.h>
  59. #define closesocket close
  60. #endif
  61. #ifdef _WIN32
  62. #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
  63. #else
  64. #define PRINT_SOCKET_ERROR(x) perror(x)
  65. #endif
  66. #if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__)
  67. #define HAS_IP_MREQN
  68. #endif
  69. #if !defined(HAS_IP_MREQN) && !defined(_WIN32)
  70. #include <sys/ioctl.h>
  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. #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
  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. #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
  166. /* setting a 3 seconds timeout */
  167. timeout.tv_sec = 3;
  168. timeout.tv_usec = 0;
  169. if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
  170. {
  171. perror("setsockopt");
  172. }
  173. timeout.tv_sec = 3;
  174. timeout.tv_usec = 0;
  175. if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
  176. {
  177. perror("setsockopt");
  178. }
  179. #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
  180. if(!socketpath)
  181. socketpath = "/var/run/minissdpd.sock";
  182. addr.sun_family = AF_UNIX;
  183. strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
  184. /* TODO : check if we need to handle the EINTR */
  185. if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0)
  186. {
  187. /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
  188. close(s);
  189. return MINISSDPC_SOCKET_ERROR;
  190. }
  191. return s;
  192. }
  193. int
  194. disconnectFromMiniSSDPD(int s)
  195. {
  196. if (close(s) < 0)
  197. return MINISSDPC_SOCKET_ERROR;
  198. return MINISSDPC_SUCCESS;
  199. }
  200. int
  201. requestDevicesFromMiniSSDPD(int s, const char * devtype)
  202. {
  203. unsigned char buffer[256];
  204. unsigned char * p;
  205. unsigned int stsize, l;
  206. stsize = strlen(devtype);
  207. if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8))
  208. {
  209. buffer[0] = 3; /* request type 3 : everything */
  210. }
  211. else
  212. {
  213. buffer[0] = 1; /* request type 1 : request devices/services by type */
  214. }
  215. p = buffer + 1;
  216. l = stsize; CODELENGTH(l, p);
  217. if(p + stsize > buffer + sizeof(buffer))
  218. {
  219. /* devtype is too long ! */
  220. #ifdef DEBUG
  221. fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n",
  222. stsize, (unsigned)sizeof(buffer));
  223. #endif /* DEBUG */
  224. return MINISSDPC_INVALID_INPUT;
  225. }
  226. memcpy(p, devtype, stsize);
  227. p += stsize;
  228. if(write(s, buffer, p - buffer) < 0)
  229. {
  230. /*syslog(LOG_ERR, "write(): %m");*/
  231. perror("minissdpc.c: write()");
  232. return MINISSDPC_SOCKET_ERROR;
  233. }
  234. return MINISSDPC_SUCCESS;
  235. }
  236. struct UPNPDev *
  237. receiveDevicesFromMiniSSDPD(int s, int * error)
  238. {
  239. struct UPNPDev * tmp;
  240. struct UPNPDev * devlist = NULL;
  241. unsigned char buffer[256];
  242. ssize_t n;
  243. unsigned char * p;
  244. unsigned char * url;
  245. unsigned char * st;
  246. unsigned int bufferindex;
  247. unsigned int i, ndev;
  248. unsigned int urlsize, stsize, usnsize, l;
  249. n = read(s, buffer, sizeof(buffer));
  250. if(n<=0)
  251. {
  252. perror("minissdpc.c: read()");
  253. if (error)
  254. *error = MINISSDPC_SOCKET_ERROR;
  255. return NULL;
  256. }
  257. ndev = buffer[0];
  258. bufferindex = 1;
  259. for(i = 0; i < ndev; i++)
  260. {
  261. DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER);
  262. if(n<=0) {
  263. if (error)
  264. *error = MINISSDPC_INVALID_SERVER_REPLY;
  265. return devlist;
  266. }
  267. #ifdef DEBUG
  268. printf(" urlsize=%u", urlsize);
  269. #endif /* DEBUG */
  270. url = malloc(urlsize);
  271. if(url == NULL) {
  272. if (error)
  273. *error = MINISSDPC_MEMORY_ERROR;
  274. return devlist;
  275. }
  276. READ_COPY_BUFFER(url, urlsize);
  277. if(n<=0) {
  278. if (error)
  279. *error = MINISSDPC_INVALID_SERVER_REPLY;
  280. goto free_url_and_return;
  281. }
  282. DECODELENGTH_READ(stsize, READ_BYTE_BUFFER);
  283. if(n<=0) {
  284. if (error)
  285. *error = MINISSDPC_INVALID_SERVER_REPLY;
  286. goto free_url_and_return;
  287. }
  288. #ifdef DEBUG
  289. printf(" stsize=%u", stsize);
  290. #endif /* DEBUG */
  291. st = malloc(stsize);
  292. if (st == NULL) {
  293. if (error)
  294. *error = MINISSDPC_MEMORY_ERROR;
  295. goto free_url_and_return;
  296. }
  297. READ_COPY_BUFFER(st, stsize);
  298. if(n<=0) {
  299. if (error)
  300. *error = MINISSDPC_INVALID_SERVER_REPLY;
  301. goto free_url_and_st_and_return;
  302. }
  303. DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER);
  304. if(n<=0) {
  305. if (error)
  306. *error = MINISSDPC_INVALID_SERVER_REPLY;
  307. goto free_url_and_st_and_return;
  308. }
  309. #ifdef DEBUG
  310. printf(" usnsize=%u\n", usnsize);
  311. #endif /* DEBUG */
  312. tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
  313. if(tmp == NULL) {
  314. if (error)
  315. *error = MINISSDPC_MEMORY_ERROR;
  316. goto free_url_and_st_and_return;
  317. }
  318. tmp->pNext = devlist;
  319. tmp->descURL = tmp->buffer;
  320. tmp->st = tmp->buffer + 1 + urlsize;
  321. memcpy(tmp->buffer, url, urlsize);
  322. tmp->buffer[urlsize] = '\0';
  323. memcpy(tmp->st, st, stsize);
  324. tmp->buffer[urlsize+1+stsize] = '\0';
  325. free(url);
  326. free(st);
  327. url = NULL;
  328. st = NULL;
  329. tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize;
  330. READ_COPY_BUFFER(tmp->usn, usnsize);
  331. if(n<=0) {
  332. if (error)
  333. *error = MINISSDPC_INVALID_SERVER_REPLY;
  334. goto free_tmp_and_return;
  335. }
  336. tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
  337. tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */
  338. devlist = tmp;
  339. }
  340. if (error)
  341. *error = MINISSDPC_SUCCESS;
  342. return devlist;
  343. free_url_and_st_and_return:
  344. free(st);
  345. free_url_and_return:
  346. free(url);
  347. return devlist;
  348. free_tmp_and_return:
  349. free(tmp);
  350. return devlist;
  351. }
  352. #endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
  353. /* parseMSEARCHReply()
  354. * the last 4 arguments are filled during the parsing :
  355. * - location/locationsize : "location:" field of the SSDP reply packet
  356. * - st/stsize : "st:" field of the SSDP reply packet.
  357. * The strings are NOT null terminated */
  358. static void
  359. parseMSEARCHReply(const char * reply, int size,
  360. const char * * location, int * locationsize,
  361. const char * * st, int * stsize,
  362. const char * * usn, int * usnsize)
  363. {
  364. int a, b, i;
  365. i = 0;
  366. a = i; /* start of the line */
  367. b = 0; /* end of the "header" (position of the colon) */
  368. while(i<size)
  369. {
  370. switch(reply[i])
  371. {
  372. case ':':
  373. if(b==0)
  374. {
  375. b = i; /* end of the "header" */
  376. /*for(j=a; j<b; j++)
  377. {
  378. putchar(reply[j]);
  379. }
  380. */
  381. }
  382. break;
  383. case '\x0a':
  384. case '\x0d':
  385. if(b!=0)
  386. {
  387. /*for(j=b+1; j<i; j++)
  388. {
  389. putchar(reply[j]);
  390. }
  391. putchar('\n');*/
  392. /* skip the colon and white spaces */
  393. do { b++; } while(reply[b]==' ');
  394. if(0==strncasecmp(reply+a, "location", 8))
  395. {
  396. *location = reply+b;
  397. *locationsize = i-b;
  398. }
  399. else if(0==strncasecmp(reply+a, "st", 2))
  400. {
  401. *st = reply+b;
  402. *stsize = i-b;
  403. }
  404. else if(0==strncasecmp(reply+a, "usn", 3))
  405. {
  406. *usn = reply+b;
  407. *usnsize = i-b;
  408. }
  409. b = 0;
  410. }
  411. a = i+1;
  412. break;
  413. default:
  414. break;
  415. }
  416. i++;
  417. }
  418. }
  419. /* port upnp discover : SSDP protocol */
  420. #define SSDP_PORT 1900
  421. #define XSTR(s) STR(s)
  422. #define STR(s) #s
  423. #define UPNP_MCAST_ADDR "239.255.255.250"
  424. /* for IPv6 */
  425. #define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
  426. #define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
  427. /* direct discovery if minissdpd responses are not sufficient */
  428. /* ssdpDiscoverDevices() :
  429. * return a chained list of all devices found or NULL if
  430. * no devices was found.
  431. * It is up to the caller to free the chained list
  432. * delay is in millisecond (poll).
  433. * UDA v1.1 says :
  434. * The TTL for the IP packet SHOULD default to 2 and
  435. * SHOULD be configurable. */
  436. struct UPNPDev *
  437. ssdpDiscoverDevices(const char * const deviceTypes[],
  438. int delay, const char * multicastif,
  439. int localport,
  440. int ipv6, unsigned char ttl,
  441. int * error,
  442. int searchalltypes)
  443. {
  444. struct UPNPDev * tmp;
  445. struct UPNPDev * devlist = 0;
  446. unsigned int scope_id = 0;
  447. int opt = 1;
  448. static const char MSearchMsgFmt[] =
  449. "M-SEARCH * HTTP/1.1\r\n"
  450. "HOST: %s:" XSTR(SSDP_PORT) "\r\n"
  451. "ST: %s\r\n"
  452. "MAN: \"ssdp:discover\"\r\n"
  453. "MX: %u\r\n"
  454. "\r\n";
  455. int deviceIndex;
  456. char bufr[1536]; /* reception and emission buffer */
  457. int sudp;
  458. int n;
  459. struct sockaddr_storage sockudp_r;
  460. unsigned int mx;
  461. #ifdef NO_GETADDRINFO
  462. struct sockaddr_storage sockudp_w;
  463. #else
  464. int rv;
  465. struct addrinfo hints, *servinfo, *p;
  466. #endif
  467. #ifdef _WIN32
  468. MIB_IPFORWARDROW ip_forward;
  469. unsigned long _ttl = (unsigned long)ttl;
  470. #endif
  471. int linklocal = 1;
  472. if(error)
  473. *error = MINISSDPC_UNKNOWN_ERROR;
  474. if(localport==UPNP_LOCAL_PORT_SAME)
  475. localport = SSDP_PORT;
  476. #ifdef _WIN32
  477. sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  478. #else
  479. sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
  480. #endif
  481. if(sudp < 0)
  482. {
  483. if(error)
  484. *error = MINISSDPC_SOCKET_ERROR;
  485. PRINT_SOCKET_ERROR("socket");
  486. return NULL;
  487. }
  488. /* reception */
  489. memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
  490. if(ipv6) {
  491. struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
  492. p->sin6_family = AF_INET6;
  493. if(localport > 0 && localport < 65536)
  494. p->sin6_port = htons((unsigned short)localport);
  495. p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
  496. } else {
  497. struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
  498. p->sin_family = AF_INET;
  499. if(localport > 0 && localport < 65536)
  500. p->sin_port = htons((unsigned short)localport);
  501. p->sin_addr.s_addr = INADDR_ANY;
  502. }
  503. #ifdef _WIN32
  504. /* This code could help us to use the right Network interface for
  505. * SSDP multicast traffic */
  506. /* Get IP associated with the index given in the ip_forward struct
  507. * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
  508. if(!ipv6
  509. && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
  510. DWORD dwRetVal = 0;
  511. PMIB_IPADDRTABLE pIPAddrTable;
  512. DWORD dwSize = 0;
  513. #ifdef DEBUG
  514. IN_ADDR IPAddr;
  515. #endif
  516. int i;
  517. #ifdef DEBUG
  518. printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
  519. #endif
  520. pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
  521. if(pIPAddrTable) {
  522. if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
  523. free(pIPAddrTable);
  524. pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
  525. }
  526. }
  527. if(pIPAddrTable) {
  528. dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
  529. if (dwRetVal == NO_ERROR) {
  530. #ifdef DEBUG
  531. printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
  532. #endif
  533. for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
  534. #ifdef DEBUG
  535. printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
  536. IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
  537. printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
  538. IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
  539. printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
  540. IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
  541. printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
  542. printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
  543. printf("\tType and State[%d]:", i);
  544. printf("\n");
  545. #endif
  546. if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
  547. /* Set the address of this interface to be used */
  548. struct in_addr mc_if;
  549. memset(&mc_if, 0, sizeof(mc_if));
  550. mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
  551. if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
  552. PRINT_SOCKET_ERROR("setsockopt");
  553. }
  554. ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
  555. #ifndef DEBUG
  556. break;
  557. #endif
  558. }
  559. }
  560. }
  561. free(pIPAddrTable);
  562. pIPAddrTable = NULL;
  563. }
  564. }
  565. #endif /* _WIN32 */
  566. #ifdef _WIN32
  567. if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
  568. #else
  569. if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
  570. #endif
  571. {
  572. if(error)
  573. *error = MINISSDPC_SOCKET_ERROR;
  574. PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)");
  575. return NULL;
  576. }
  577. #ifdef _WIN32
  578. if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0)
  579. #else /* _WIN32 */
  580. if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
  581. #endif /* _WIN32 */
  582. {
  583. /* not a fatal error */
  584. PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)");
  585. }
  586. if(multicastif)
  587. {
  588. if(ipv6) {
  589. #if !defined(_WIN32)
  590. /* according to MSDN, if_nametoindex() is supported since
  591. * MS Windows Vista and MS Windows Server 2008.
  592. * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
  593. unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
  594. if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0)
  595. {
  596. PRINT_SOCKET_ERROR("setsockopt");
  597. }
  598. #else
  599. #ifdef DEBUG
  600. printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
  601. #endif
  602. #endif
  603. } else {
  604. struct in_addr mc_if;
  605. mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
  606. if(mc_if.s_addr != INADDR_NONE)
  607. {
  608. ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
  609. if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
  610. {
  611. PRINT_SOCKET_ERROR("setsockopt");
  612. }
  613. } else {
  614. #ifdef HAS_IP_MREQN
  615. /* was not an ip address, try with an interface name */
  616. struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
  617. memset(&reqn, 0, sizeof(struct ip_mreqn));
  618. reqn.imr_ifindex = if_nametoindex(multicastif);
  619. if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
  620. {
  621. PRINT_SOCKET_ERROR("setsockopt");
  622. }
  623. #elif !defined(_WIN32)
  624. struct ifreq ifr;
  625. int ifrlen = sizeof(ifr);
  626. strncpy(ifr.ifr_name, multicastif, IFNAMSIZ);
  627. ifr.ifr_name[IFNAMSIZ-1] = '\0';
  628. if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0)
  629. {
  630. PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)");
  631. }
  632. mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
  633. if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
  634. {
  635. PRINT_SOCKET_ERROR("setsockopt");
  636. }
  637. #else /* _WIN32 */
  638. #ifdef DEBUG
  639. printf("Setting of multicast interface not supported with interface name.\n");
  640. #endif
  641. #endif /* #ifdef HAS_IP_MREQN / !defined(_WIN32) */
  642. }
  643. }
  644. }
  645. /* Before sending the packed, we first "bind" in order to be able
  646. * to receive the response */
  647. if (bind(sudp, (const struct sockaddr *)&sockudp_r,
  648. ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
  649. {
  650. if(error)
  651. *error = MINISSDPC_SOCKET_ERROR;
  652. PRINT_SOCKET_ERROR("bind");
  653. closesocket(sudp);
  654. return NULL;
  655. }
  656. if(error)
  657. *error = MINISSDPC_SUCCESS;
  658. /* Calculating maximum response time in seconds */
  659. mx = ((unsigned int)delay) / 1000u;
  660. if(mx == 0) {
  661. mx = 1;
  662. delay = 1000;
  663. }
  664. /* receiving SSDP response packet */
  665. for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
  666. /* sending the SSDP M-SEARCH packet */
  667. n = snprintf(bufr, sizeof(bufr),
  668. MSearchMsgFmt,
  669. ipv6 ?
  670. (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
  671. : UPNP_MCAST_ADDR,
  672. deviceTypes[deviceIndex], mx);
  673. if ((unsigned int)n >= sizeof(bufr)) {
  674. if(error)
  675. *error = MINISSDPC_MEMORY_ERROR;
  676. goto error;
  677. }
  678. #ifdef DEBUG
  679. /*printf("Sending %s", bufr);*/
  680. printf("Sending M-SEARCH request to %s with ST: %s\n",
  681. ipv6 ?
  682. (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
  683. : UPNP_MCAST_ADDR,
  684. deviceTypes[deviceIndex]);
  685. #endif
  686. #ifdef NO_GETADDRINFO
  687. /* the following code is not using getaddrinfo */
  688. /* emission */
  689. memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
  690. if(ipv6) {
  691. struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
  692. p->sin6_family = AF_INET6;
  693. p->sin6_port = htons(SSDP_PORT);
  694. inet_pton(AF_INET6,
  695. linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
  696. &(p->sin6_addr));
  697. } else {
  698. struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
  699. p->sin_family = AF_INET;
  700. p->sin_port = htons(SSDP_PORT);
  701. p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
  702. }
  703. n = sendto(sudp, bufr, n, 0, &sockudp_w,
  704. ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
  705. if (n < 0) {
  706. if(error)
  707. *error = MINISSDPC_SOCKET_ERROR;
  708. PRINT_SOCKET_ERROR("sendto");
  709. break;
  710. }
  711. #else /* #ifdef NO_GETADDRINFO */
  712. memset(&hints, 0, sizeof(hints));
  713. hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
  714. hints.ai_socktype = SOCK_DGRAM;
  715. /*hints.ai_flags = */
  716. if ((rv = getaddrinfo(ipv6
  717. ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
  718. : UPNP_MCAST_ADDR,
  719. XSTR(SSDP_PORT), &hints, &servinfo)) != 0) {
  720. if(error)
  721. *error = MINISSDPC_SOCKET_ERROR;
  722. #ifdef _WIN32
  723. fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
  724. #else
  725. fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
  726. #endif
  727. break;
  728. }
  729. for(p = servinfo; p; p = p->ai_next) {
  730. n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
  731. if (n < 0) {
  732. #ifdef DEBUG
  733. char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
  734. if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
  735. sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
  736. fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
  737. }
  738. #endif
  739. PRINT_SOCKET_ERROR("sendto");
  740. continue;
  741. }
  742. }
  743. freeaddrinfo(servinfo);
  744. if(n < 0) {
  745. if(error)
  746. *error = MINISSDPC_SOCKET_ERROR;
  747. break;
  748. }
  749. #endif /* #ifdef NO_GETADDRINFO */
  750. /* Waiting for SSDP REPLY packet to M-SEARCH
  751. * if searchalltypes is set, enter the loop only
  752. * when the last deviceType is reached */
  753. if(!searchalltypes || !deviceTypes[deviceIndex + 1]) do {
  754. n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
  755. if (n < 0) {
  756. /* error */
  757. if(error)
  758. *error = MINISSDPC_SOCKET_ERROR;
  759. goto error;
  760. } else if (n == 0) {
  761. /* no data or Time Out */
  762. #ifdef DEBUG
  763. printf("NODATA or TIMEOUT\n");
  764. #endif /* DEBUG */
  765. if (devlist && !searchalltypes) {
  766. /* found some devices, stop now*/
  767. if(error)
  768. *error = MINISSDPC_SUCCESS;
  769. goto error;
  770. }
  771. } else {
  772. const char * descURL=NULL;
  773. int urlsize=0;
  774. const char * st=NULL;
  775. int stsize=0;
  776. const char * usn=NULL;
  777. int usnsize=0;
  778. parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
  779. if(st&&descURL) {
  780. #ifdef DEBUG
  781. printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
  782. stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
  783. #endif /* DEBUG */
  784. for(tmp=devlist; tmp; tmp = tmp->pNext) {
  785. if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
  786. tmp->descURL[urlsize] == '\0' &&
  787. memcmp(tmp->st, st, stsize) == 0 &&
  788. tmp->st[stsize] == '\0' &&
  789. (usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) &&
  790. tmp->usn[usnsize] == '\0')
  791. break;
  792. }
  793. /* at the exit of the loop above, tmp is null if
  794. * no duplicate device was found */
  795. if(tmp)
  796. continue;
  797. tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
  798. if(!tmp) {
  799. /* memory allocation error */
  800. if(error)
  801. *error = MINISSDPC_MEMORY_ERROR;
  802. goto error;
  803. }
  804. tmp->pNext = devlist;
  805. tmp->descURL = tmp->buffer;
  806. tmp->st = tmp->buffer + 1 + urlsize;
  807. tmp->usn = tmp->st + 1 + stsize;
  808. memcpy(tmp->buffer, descURL, urlsize);
  809. tmp->buffer[urlsize] = '\0';
  810. memcpy(tmp->st, st, stsize);
  811. tmp->buffer[urlsize+1+stsize] = '\0';
  812. if(usn != NULL)
  813. memcpy(tmp->usn, usn, usnsize);
  814. tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
  815. tmp->scope_id = scope_id;
  816. devlist = tmp;
  817. }
  818. }
  819. } while(n > 0);
  820. if(ipv6) {
  821. /* switch linklocal flag */
  822. if(linklocal) {
  823. linklocal = 0;
  824. --deviceIndex;
  825. } else {
  826. linklocal = 1;
  827. }
  828. }
  829. }
  830. error:
  831. closesocket(sudp);
  832. return devlist;
  833. }