Annotation of embedaddon/miniupnpd/minissdp.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* $Id: minissdp.c,v 1.27 2011/05/23 12:39:41 nanard Exp $ */
1.1 misho 2: /* MiniUPnP project
3: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
1.1.1.2 ! misho 4: * (c) 2006-2011 Thomas Bernard
1.1 misho 5: * This software is subject to the conditions detailed
6: * in the LICENCE file provided within the distribution */
7:
8: #include <stdio.h>
9: #include <string.h>
10: #include <unistd.h>
11: #include <sys/socket.h>
12: #include <sys/un.h>
13: #include <netinet/in.h>
14: #include <arpa/inet.h>
15: #include <syslog.h>
16: #include "config.h"
17: #include "upnpdescstrings.h"
18: #include "miniupnpdpath.h"
19: #include "upnphttp.h"
20: #include "upnpglobalvars.h"
21: #include "minissdp.h"
1.1.1.2 ! misho 22: #include "upnputils.h"
1.1 misho 23: #include "codelength.h"
24:
25: /* SSDP ip/port */
26: #define SSDP_PORT (1900)
27: #define SSDP_MCAST_ADDR ("239.255.255.250")
1.1.1.2 ! misho 28: #define LL_SSDP_MCAST_ADDR ("FF02::C")
! 29: #define SL_SSDP_MCAST_ADDR ("FF05::C")
1.1 misho 30:
1.1.1.2 ! misho 31: /* AddMulticastMembership()
! 32: * param s socket
! 33: * param ifaddr ip v4 address
! 34: */
1.1 misho 35: static int
36: AddMulticastMembership(int s, in_addr_t ifaddr)
37: {
38: struct ip_mreq imr; /* Ip multicast membership */
39:
40: /* setting up imr structure */
41: imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR);
42: /*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/
43: imr.imr_interface.s_addr = ifaddr; /*inet_addr(ifaddr);*/
44:
45: if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreq)) < 0)
46: {
47: syslog(LOG_ERR, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m");
48: return -1;
49: }
50:
51: return 0;
52: }
53:
1.1.1.2 ! misho 54: /* AddMulticastMembershipIPv6()
! 55: * param s socket (IPv6)
! 56: * To be improved to target specific network interfaces */
! 57: #ifdef ENABLE_IPV6
! 58: static int
! 59: AddMulticastMembershipIPv6(int s)
! 60: {
! 61: struct ipv6_mreq mr;
! 62: /*unsigned int ifindex;*/
! 63:
! 64: memset(&mr, 0, sizeof(mr));
! 65: inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
! 66: /*mr.ipv6mr_interface = ifindex;*/
! 67: mr.ipv6mr_interface = 0; /* 0 : all interfaces */
! 68: #ifndef IPV6_ADD_MEMBERSHIP
! 69: #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
! 70: #endif
! 71: if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
! 72: {
! 73: syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
! 74: return -1;
! 75: }
! 76: inet_pton(AF_INET6, SL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
! 77: if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
! 78: {
! 79: syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
! 80: return -1;
! 81: }
! 82: return 0;
! 83: }
! 84: #endif
! 85:
1.1 misho 86: /* Open and configure the socket listening for
1.1.1.2 ! misho 87: * SSDP udp packets sent on 239.255.255.250 port 1900
! 88: * SSDP v6 udp packets sent on FF02::C, or FF05::C, port 1900 */
1.1 misho 89: int
1.1.1.2 ! misho 90: OpenAndConfSSDPReceiveSocket(int ipv6)
1.1 misho 91: {
92: int s;
1.1.1.2 ! misho 93: struct sockaddr_storage sockname;
! 94: socklen_t sockname_len;
! 95: struct lan_addr_s * lan_addr;
1.1 misho 96: int j = 1;
1.1.1.2 ! misho 97:
! 98: if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
1.1 misho 99: {
100: syslog(LOG_ERR, "socket(udp): %m");
101: return -1;
1.1.1.2 ! misho 102: }
! 103:
! 104: memset(&sockname, 0, sizeof(struct sockaddr_storage));
! 105: if(ipv6) {
! 106: struct sockaddr_in6 * saddr = (struct sockaddr_in6 *)&sockname;
! 107: saddr->sin6_family = AF_INET6;
! 108: saddr->sin6_port = htons(SSDP_PORT);
! 109: saddr->sin6_addr = in6addr_any;
! 110: sockname_len = sizeof(struct sockaddr_in6);
! 111: } else {
! 112: struct sockaddr_in * saddr = (struct sockaddr_in *)&sockname;
! 113: saddr->sin_family = AF_INET;
! 114: saddr->sin_port = htons(SSDP_PORT);
! 115: /* NOTE : it seems it doesnt work when binding on the specific address */
! 116: /*saddr->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/
! 117: saddr->sin_addr.s_addr = htonl(INADDR_ANY);
! 118: /*saddr->sin_addr.s_addr = inet_addr(ifaddr);*/
! 119: sockname_len = sizeof(struct sockaddr_in);
! 120: }
1.1 misho 121:
122: if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j)) < 0)
123: {
124: syslog(LOG_WARNING, "setsockopt(udp, SO_REUSEADDR): %m");
125: }
126:
127:
1.1.1.2 ! misho 128: if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0)
1.1 misho 129: {
1.1.1.2 ! misho 130: syslog(LOG_ERR, "bind(udp%s): %m", ipv6 ? "6" : "");
1.1 misho 131: close(s);
132: return -1;
1.1.1.2 ! misho 133: }
1.1 misho 134:
1.1.1.2 ! misho 135: #ifdef ENABLE_IPV6
! 136: if(ipv6)
! 137: {
! 138: AddMulticastMembershipIPv6(s);
! 139: }
! 140: else
! 141: #endif
1.1 misho 142: {
1.1.1.2 ! misho 143: for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
1.1 misho 144: {
1.1.1.2 ! misho 145: if(AddMulticastMembership(s, lan_addr->addr.s_addr) < 0)
! 146: {
! 147: syslog(LOG_WARNING,
! 148: "Failed to add multicast membership for interface %s",
! 149: lan_addr->str);
! 150: }
1.1 misho 151: }
152: }
153:
154: return s;
155: }
156:
157: /* open the UDP socket used to send SSDP notifications to
158: * the multicast group reserved for them */
159: static int
160: OpenAndConfSSDPNotifySocket(in_addr_t addr)
161: {
162: int s;
163: unsigned char loopchar = 0;
164: int bcast = 1;
165: struct in_addr mc_if;
166: struct sockaddr_in sockname;
167:
168: if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
169: {
170: syslog(LOG_ERR, "socket(udp_notify): %m");
171: return -1;
172: }
173:
174: mc_if.s_addr = addr; /*inet_addr(addr);*/
175:
176: if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopchar, sizeof(loopchar)) < 0)
177: {
178: syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_LOOP): %m");
179: close(s);
180: return -1;
181: }
182:
183: if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *)&mc_if, sizeof(mc_if)) < 0)
184: {
185: syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_IF): %m");
186: close(s);
187: return -1;
188: }
189:
190: if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast)) < 0)
191: {
192: syslog(LOG_ERR, "setsockopt(udp_notify, SO_BROADCAST): %m");
193: close(s);
194: return -1;
195: }
196:
197: memset(&sockname, 0, sizeof(struct sockaddr_in));
198: sockname.sin_family = AF_INET;
199: sockname.sin_addr.s_addr = addr; /*inet_addr(addr);*/
200:
201: if (bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0)
202: {
203: syslog(LOG_ERR, "bind(udp_notify): %m");
204: close(s);
205: return -1;
206: }
207:
208: return s;
209: }
210:
211: int
212: OpenAndConfSSDPNotifySockets(int * sockets)
213: /*OpenAndConfSSDPNotifySockets(int * sockets,
214: struct lan_addr_s * lan_addr, int n_lan_addr)*/
215: {
216: int i, j;
1.1.1.2 ! misho 217: struct lan_addr_s * lan_addr;
! 218:
! 219: for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
1.1 misho 220: {
1.1.1.2 ! misho 221: sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr->addr.s_addr);
1.1 misho 222: if(sockets[i] < 0)
223: {
224: for(j=0; j<i; j++)
225: {
226: close(sockets[j]);
227: sockets[j] = -1;
228: }
229: return -1;
230: }
231: }
232: return 0;
233: }
234:
235: /*
236: * response from a LiveBox (Wanadoo)
237: HTTP/1.1 200 OK
238: CACHE-CONTROL: max-age=1800
239: DATE: Thu, 01 Jan 1970 04:03:23 GMT
240: EXT:
241: LOCATION: http://192.168.0.1:49152/gatedesc.xml
242: SERVER: Linux/2.4.17, UPnP/1.0, Intel SDK for UPnP devices /1.2
243: ST: upnp:rootdevice
244: USN: uuid:75802409-bccb-40e7-8e6c-fa095ecce13e::upnp:rootdevice
245:
246: * response from a Linksys 802.11b :
247: HTTP/1.1 200 OK
248: Cache-Control:max-age=120
249: Location:http://192.168.5.1:5678/rootDesc.xml
250: Server:NT/5.0 UPnP/1.0
251: ST:upnp:rootdevice
252: USN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777::upnp:rootdevice
253: EXT:
254: */
255:
256: /* not really an SSDP "announce" as it is the response
257: * to a SSDP "M-SEARCH" */
258: static void
1.1.1.2 ! misho 259: SendSSDPAnnounce2(int s, const struct sockaddr * addr,
1.1 misho 260: const char * st, int st_len, const char * suffix,
261: const char * host, unsigned short port)
262: {
263: int l, n;
264: char buf[512];
1.1.1.2 ! misho 265: socklen_t addrlen;
1.1 misho 266: /*
267: * follow guideline from document "UPnP Device Architecture 1.0"
268: * uppercase is recommended.
269: * DATE: is recommended
270: * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
271: * - check what to put in the 'Cache-Control' header
1.1.1.2 ! misho 272: *
! 273: * have a look at the document "UPnP Device Architecture v1.1 */
1.1 misho 274: l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"
275: "CACHE-CONTROL: max-age=120\r\n"
276: /*"DATE: ...\r\n"*/
277: "ST: %.*s%s\r\n"
278: "USN: %s::%.*s%s\r\n"
279: "EXT:\r\n"
280: "SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
281: "LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
1.1.1.2 ! misho 282: "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
! 283: "01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
! 284: "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
! 285: "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
1.1 misho 286: "\r\n",
287: st_len, st, suffix,
288: uuidvalue, st_len, st, suffix,
1.1.1.2 ! misho 289: host, (unsigned int)port,
! 290: upnp_bootid, upnp_bootid, upnp_configid);
! 291: addrlen = (addr->sa_family == AF_INET6)
! 292: ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
1.1 misho 293: n = sendto(s, buf, l, 0,
1.1.1.2 ! misho 294: addr, addrlen);
1.1 misho 295: syslog(LOG_INFO, "SSDP Announce %d bytes to %s:%d ST: %.*s",n,
1.1.1.2 ! misho 296: inet_ntoa(((const struct sockaddr_in *)addr)->sin_addr),
! 297: ntohs(((const struct sockaddr_in *)addr)->sin_port),
1.1 misho 298: l, buf);
299: if(n < 0)
300: {
301: syslog(LOG_ERR, "sendto(udp): %m");
302: }
303: }
304:
305: static const char * const known_service_types[] =
306: {
307: "upnp:rootdevice",
308: "urn:schemas-upnp-org:device:InternetGatewayDevice:",
309: "urn:schemas-upnp-org:device:WANConnectionDevice:",
310: "urn:schemas-upnp-org:device:WANDevice:",
311: "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:",
312: "urn:schemas-upnp-org:service:WANIPConnection:",
313: "urn:schemas-upnp-org:service:WANPPPConnection:",
1.1.1.2 ! misho 314: #ifdef ENABLE_L3F_SERVICE
1.1 misho 315: "urn:schemas-upnp-org:service:Layer3Forwarding:",
1.1.1.2 ! misho 316: #endif
! 317: #ifdef ENABLE_6FC_SERVICE
! 318: "url:schemas-upnp-org:service:WANIPv6FirewallControl:",
! 319: #endif
1.1 misho 320: 0
321: };
322:
323: static void
324: SendSSDPNotifies(int s, const char * host, unsigned short port,
325: unsigned int lifetime)
326: {
327: struct sockaddr_in sockname;
328: int l, n, i=0;
329: char bufr[512];
330:
331: memset(&sockname, 0, sizeof(struct sockaddr_in));
332: sockname.sin_family = AF_INET;
333: sockname.sin_port = htons(SSDP_PORT);
334: sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
335:
336: while(known_service_types[i])
337: {
338: l = snprintf(bufr, sizeof(bufr),
1.1.1.2 ! misho 339: "NOTIFY * HTTP/1.1\r\n"
! 340: "HOST: %s:%d\r\n"
! 341: "CACHE-CONTROL: max-age=%u\r\n"
! 342: "lOCATION: http://%s:%d" ROOTDESC_PATH"\r\n"
! 343: "SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
! 344: "NT: %s%s\r\n"
! 345: "USN: %s::%s%s\r\n"
! 346: "NTS: ssdp:alive\r\n"
! 347: "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
! 348: "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
! 349: "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
! 350: "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
! 351: "\r\n",
! 352: SSDP_MCAST_ADDR, SSDP_PORT,
! 353: lifetime,
! 354: host, port,
! 355: known_service_types[i], (i==0?"":"1"),
! 356: uuidvalue, known_service_types[i], (i==0?"":"1"),
! 357: upnp_bootid, upnp_bootid, upnp_configid );
1.1 misho 358: if(l>=sizeof(bufr))
359: {
360: syslog(LOG_WARNING, "SendSSDPNotifies(): truncated output");
361: l = sizeof(bufr);
362: }
363: n = sendto(s, bufr, l, 0,
364: (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
365: if(n < 0)
366: {
367: syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s, host);
368: }
369: i++;
370: }
371: }
372:
373: void
374: SendSSDPNotifies2(int * sockets,
375: unsigned short port,
376: unsigned int lifetime)
377: {
378: int i;
1.1.1.2 ! misho 379: struct lan_addr_s * lan_addr;
! 380: for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
1.1 misho 381: {
1.1.1.2 ! misho 382: SendSSDPNotifies(sockets[i], lan_addr->str, port, lifetime);
1.1 misho 383: }
384: }
385:
386: /* ProcessSSDPRequest()
387: * process SSDP M-SEARCH requests and responds to them */
388: void
389: ProcessSSDPRequest(int s, unsigned short port)
390: {
391: int n;
392: char bufr[1500];
393: socklen_t len_r;
1.1.1.2 ! misho 394: #ifdef ENABLE_IPV6
! 395: struct sockaddr_storage sendername;
! 396: len_r = sizeof(struct sockaddr_storage);
! 397: #else
1.1 misho 398: struct sockaddr_in sendername;
399: len_r = sizeof(struct sockaddr_in);
1.1.1.2 ! misho 400: #endif
1.1 misho 401:
402: n = recvfrom(s, bufr, sizeof(bufr), 0,
403: (struct sockaddr *)&sendername, &len_r);
404: if(n < 0)
405: {
406: syslog(LOG_ERR, "recvfrom(udp): %m");
407: return;
408: }
1.1.1.2 ! misho 409: ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, port);
1.1 misho 410:
411: }
412:
1.1.1.2 ! misho 413: void
! 414: ProcessSSDPData(int s, const char *bufr, int n,
! 415: const struct sockaddr * sender, unsigned short port) {
1.1 misho 416: int i, l;
1.1.1.2 ! misho 417: struct lan_addr_s * lan_addr = NULL;
! 418: const char * st = NULL;
1.1 misho 419: int st_len = 0;
1.1.1.2 ! misho 420: char sender_str[64];
! 421: const char * announced_host = NULL;
1.1 misho 422:
1.1.1.2 ! misho 423: /* get the string representation of the sender address */
! 424: sockaddr_to_string(sender, sender_str, sizeof(sender_str));
1.1 misho 425:
426: if(memcmp(bufr, "NOTIFY", 6) == 0)
427: {
428: /* ignore NOTIFY packets. We could log the sender and device type */
429: return;
430: }
431: else if(memcmp(bufr, "M-SEARCH", 8) == 0)
432: {
433: i = 0;
434: while(i < n)
435: {
436: while((i < n - 1) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
437: i++;
438: i += 2;
439: if((i < n - 3) && (strncasecmp(bufr+i, "st:", 3) == 0))
440: {
441: st = bufr+i+3;
442: st_len = 0;
443: while((*st == ' ' || *st == '\t') && (st < bufr + n))
444: st++;
445: while(st[st_len]!='\r' && st[st_len]!='\n'
446: && (st + st_len < bufr + n))
447: st_len++;
448: /*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
449: /*j = 0;*/
450: /*while(bufr[i+j]!='\r') j++;*/
451: /*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
452: }
453: }
1.1.1.2 ! misho 454: /*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
! 455: sender_str );*/
1.1 misho 456: if(st && (st_len > 0))
457: {
458: /* TODO : doesnt answer at once but wait for a random time */
1.1.1.2 ! misho 459: syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s",
! 460: sender_str, st_len, st);
1.1 misho 461: /* find in which sub network the client is */
1.1.1.2 ! misho 462: if(sender->sa_family == AF_INET)
1.1 misho 463: {
1.1.1.2 ! misho 464: for(lan_addr = lan_addrs.lh_first;
! 465: lan_addr != NULL;
! 466: lan_addr = lan_addr->list.le_next)
1.1 misho 467: {
1.1.1.2 ! misho 468: if( (((const struct sockaddr_in *)sender)->sin_addr.s_addr & lan_addr->mask.s_addr)
! 469: == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
! 470: break;
! 471: }
! 472: if (lan_addr == NULL)
! 473: {
! 474: syslog(LOG_ERR, "Can't find in which sub network the client is");
! 475: return;
1.1 misho 476: }
1.1.1.2 ! misho 477: announced_host = lan_addr->str;
! 478: }
! 479: #ifdef ENABLE_IPV6
! 480: else
! 481: {
! 482: /* IPv6 address with brackets */
! 483: announced_host = ipv6_addr_for_http_with_brackets;
1.1 misho 484: }
1.1.1.2 ! misho 485: #endif
1.1 misho 486: /* Responds to request with a device as ST header */
487: for(i = 0; known_service_types[i]; i++)
488: {
489: l = (int)strlen(known_service_types[i]);
490: if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
491: {
492: syslog(LOG_INFO, "Single search found");
1.1.1.2 ! misho 493: SendSSDPAnnounce2(s, sender,
1.1 misho 494: st, st_len, "",
1.1.1.2 ! misho 495: announced_host, port);
1.1 misho 496: break;
497: }
498: }
499: /* Responds to request with ST: ssdp:all */
500: /* strlen("ssdp:all") == 8 */
501: if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
502: {
503: syslog(LOG_INFO, "ssdp:all found");
504: for(i=0; known_service_types[i]; i++)
505: {
506: l = (int)strlen(known_service_types[i]);
1.1.1.2 ! misho 507: SendSSDPAnnounce2(s, sender,
1.1 misho 508: known_service_types[i], l, i==0?"":"1",
1.1.1.2 ! misho 509: announced_host, port);
1.1 misho 510: }
511: }
512: /* responds to request by UUID value */
513: l = (int)strlen(uuidvalue);
514: if(l==st_len && (0 == memcmp(st, uuidvalue, l)))
515: {
516: syslog(LOG_INFO, "ssdp:uuid found");
1.1.1.2 ! misho 517: SendSSDPAnnounce2(s, sender, st, st_len, "",
! 518: announced_host, port);
1.1 misho 519: }
520: }
521: else
522: {
1.1.1.2 ! misho 523: syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s", sender_str);
1.1 misho 524: }
525: }
526: else
527: {
1.1.1.2 ! misho 528: syslog(LOG_NOTICE, "Unknown udp packet received from %s", sender_str);
1.1 misho 529: }
530: }
531:
532: /* This will broadcast ssdp:byebye notifications to inform
533: * the network that UPnP is going down. */
534: int
535: SendSSDPGoodbye(int * sockets, int n_sockets)
536: {
537: struct sockaddr_in sockname;
538: int n, l;
539: int i, j;
540: char bufr[512];
541:
542: memset(&sockname, 0, sizeof(struct sockaddr_in));
543: sockname.sin_family = AF_INET;
544: sockname.sin_port = htons(SSDP_PORT);
545: sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
546:
547: for(j=0; j<n_sockets; j++)
548: {
549: for(i=0; known_service_types[i]; i++)
550: {
551: l = snprintf(bufr, sizeof(bufr),
1.1.1.2 ! misho 552: "NOTIFY * HTTP/1.1\r\n"
! 553: "HOST: %s:%d\r\n"
! 554: "NT: %s%s\r\n"
! 555: "USN: %s::%s%s\r\n"
! 556: "NTS: ssdp:byebye\r\n"
! 557: "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
! 558: "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
! 559: "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
! 560: "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
! 561: "\r\n",
! 562: SSDP_MCAST_ADDR, SSDP_PORT,
! 563: known_service_types[i], (i==0?"":"1"),
! 564: uuidvalue, known_service_types[i], (i==0?"":"1"),
! 565: upnp_bootid, upnp_bootid, upnp_configid);
1.1 misho 566: n = sendto(sockets[j], bufr, l, 0,
567: (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
568: if(n < 0)
569: {
570: syslog(LOG_ERR, "SendSSDPGoodbye: sendto(udp_shutdown=%d): %m",
571: sockets[j]);
572: return -1;
573: }
574: }
575: }
576: return 0;
577: }
578:
579: /* SubmitServicesToMiniSSDPD() :
580: * register services offered by MiniUPnPd to a running instance of
581: * MiniSSDPd */
582: int
583: SubmitServicesToMiniSSDPD(const char * host, unsigned short port) {
584: struct sockaddr_un addr;
585: int s;
586: unsigned char buffer[2048];
587: char strbuf[256];
588: unsigned char * p;
589: int i, l;
590:
591: s = socket(AF_UNIX, SOCK_STREAM, 0);
592: if(s < 0) {
593: syslog(LOG_ERR, "socket(unix): %m");
594: return -1;
595: }
596: addr.sun_family = AF_UNIX;
597: strncpy(addr.sun_path, minissdpdsocketpath, sizeof(addr.sun_path));
598: if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
599: syslog(LOG_ERR, "connect(\"%s\"): %m", minissdpdsocketpath);
600: return -1;
601: }
602: for(i = 0; known_service_types[i]; i++) {
603: buffer[0] = 4;
604: p = buffer + 1;
605: l = (int)strlen(known_service_types[i]);
606: if(i > 0)
607: l++;
608: CODELENGTH(l, p);
609: memcpy(p, known_service_types[i], l);
610: if(i > 0)
611: p[l-1] = '1';
612: p += l;
613: l = snprintf(strbuf, sizeof(strbuf), "%s::%s%s",
614: uuidvalue, known_service_types[i], (i==0)?"":"1");
615: CODELENGTH(l, p);
616: memcpy(p, strbuf, l);
617: p += l;
618: l = (int)strlen(MINIUPNPD_SERVER_STRING);
619: CODELENGTH(l, p);
620: memcpy(p, MINIUPNPD_SERVER_STRING, l);
621: p += l;
622: l = snprintf(strbuf, sizeof(strbuf), "http://%s:%u" ROOTDESC_PATH,
623: host, (unsigned int)port);
624: CODELENGTH(l, p);
625: memcpy(p, strbuf, l);
626: p += l;
627: if(write(s, buffer, p - buffer) < 0) {
628: syslog(LOG_ERR, "write(): %m");
629: return -1;
630: }
631: }
632: close(s);
633: return 0;
634: }
635:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>