static void SendSSDPNotifies(int s, const char * host, unsigned short http_port, unsigned int lifetime, int ipv6) #endif { #ifdef ENABLE_IPV6 struct sockaddr_storage sockname; #else struct sockaddr_in sockname; #endif socklen_t sockname_len; const char * dest_str; int i=0; char ver_str[4]; memset(&sockname, 0, sizeof(sockname)); #ifdef ENABLE_IPV6 if(ipv6) { struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockname; sockname_len = sizeof(struct sockaddr_in6); p->sin6_family = AF_INET6; p->sin6_port = htons(SSDP_PORT); inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &(p->sin6_addr)); dest_str = "[" LL_SSDP_MCAST_ADDR "]"; /* TODO : also send to SL_SSDP_MCAST_ADDR and GL_SSDP_MCAST_ADDR ? */ /* UPnP Device Architecture 1.1 : * Devices MUST multicast SSDP messages for each of the UPnP-enabled * interfaces. The scope of multicast SSDP messages MUST be * link local FF02::C if the message is sent from a link local address. * If the message is sent from a global address it MUST be multicast * using either global scope FF0E::C or site local scope FF05::C. * In networks with complex topologies and overlapping sites, use of * global scope is RECOMMENDED. */ } else #endif { struct sockaddr_in *p = (struct sockaddr_in *)&sockname; sockname_len = sizeof(struct sockaddr_in); p->sin_family = AF_INET; p->sin_port = htons(SSDP_PORT); p->sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); dest_str = SSDP_MCAST_ADDR; } while(known_service_types[i].s) { if(i==0) ver_str[0] = '\0'; else snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version); SendSSDPNotify(s, (struct sockaddr *)&sockname, sockname_len, dest_str, host, http_port, #ifdef ENABLE_HTTPS https_port, #endif known_service_types[i].s, ver_str, /* NT: */ known_service_types[i].uuid, "::", known_service_types[i].s, /* ver_str, USN: */ lifetime); if(0==memcmp(known_service_types[i].s, "urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1)) { SendSSDPNotify(s, (struct sockaddr *)&sockname, sockname_len, dest_str, host, http_port, #ifdef ENABLE_HTTPS https_port, #endif known_service_types[i].uuid, "", /* NT: */ known_service_types[i].uuid, "", "", /* ver_str, USN: */ lifetime); } i++; } }
static void SendSSDPNotifies(int s, const char * host, unsigned short http_port, unsigned int lifetime, int ipv6) #endif { #ifdef ENABLE_IPV6 struct sockaddr_storage sockname; /* UDA 1.1 AnnexA and UDA 2.0 only allow/define the use of * Link-Local and Site-Local multicast scopes */ static struct { const char * p1, * p2; } const mcast_addrs[] = { { LL_SSDP_MCAST_ADDR, "[" LL_SSDP_MCAST_ADDR "]" }, /* Link Local */ { SL_SSDP_MCAST_ADDR, "[" SL_SSDP_MCAST_ADDR "]" }, /* Site Local */ #ifndef UPNP_STRICT { GL_SSDP_MCAST_ADDR, "[" GL_SSDP_MCAST_ADDR "]" }, /* Global */ #endif /* ! UPNP_STRICT */ { NULL, NULL } }; int j; #else /* ENABLE_IPV6 */ struct sockaddr_in sockname; #endif /* ENABLE_IPV6 */ socklen_t sockname_len; const char * dest_str; int i; char ver_str[4]; #ifndef ENABLE_IPV6 UNUSED(ipv6); #endif /* ENABLE_IPV6 */ memset(&sockname, 0, sizeof(sockname)); #ifdef ENABLE_IPV6 /* first iterate destinations for this LAN interface (only 1 for IPv4) */ for(j = 0; (mcast_addrs[j].p1 != 0 && ipv6) || j < 1; j++) { if(ipv6) { struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockname; sockname_len = sizeof(struct sockaddr_in6); p->sin6_family = AF_INET6; p->sin6_port = htons(SSDP_PORT); inet_pton(AF_INET6, mcast_addrs[j].p1, &(p->sin6_addr)); dest_str = mcast_addrs[j].p2; /* UPnP Device Architecture 1.1 : * Devices MUST multicast SSDP messages for each of the UPnP-enabled * interfaces. The scope of multicast SSDP messages MUST be * link local FF02::C if the message is sent from a link local address. * If the message is sent from a global address it MUST be multicast * using either global scope FF0E::C or site local scope FF05::C. * In networks with complex topologies and overlapping sites, use of * global scope is RECOMMENDED. */ } else { #else /* ENABLE_IPV6 */ { #endif /* ENABLE_IPV6 */ /* IPv4 */ struct sockaddr_in *p = (struct sockaddr_in *)&sockname; sockname_len = sizeof(struct sockaddr_in); p->sin_family = AF_INET; p->sin_port = htons(SSDP_PORT); p->sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); dest_str = SSDP_MCAST_ADDR; } /* iterate all services / devices */ for(i = 0; known_service_types[i].s; i++) { if(i==0) ver_str[0] = '\0'; else snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version); SendSSDPNotify(s, (struct sockaddr *)&sockname, sockname_len, dest_str, host, http_port, #ifdef ENABLE_HTTPS https_port, #endif known_service_types[i].s, ver_str, /* NT: */ known_service_types[i].uuid, "::", known_service_types[i].s, /* ver_str, USN: */ lifetime); /* for devices, also send NOTIFY on the uuid */ if(0==memcmp(known_service_types[i].s, "urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1)) { SendSSDPNotify(s, (struct sockaddr *)&sockname, sockname_len, dest_str, host, http_port, #ifdef ENABLE_HTTPS https_port, #endif known_service_types[i].uuid, "", /* NT: */ known_service_types[i].uuid, "", "", /* ver_str, USN: */ lifetime); } } /* for(i = 0; known_service_types[i].s; i++) */ #ifdef ENABLE_IPV6 } /* for(j = 0; (mcast_addrs[j].p1 != 0 && ipv6) || j < 1; j++) */ #endif /* ENABLE_IPV6 */ } /* SendSSDPNotifies2() sends SSDP NOTIFY packets on all interfaces * for all destinations, all devices / services */ void SendSSDPNotifies2(int * sockets, unsigned short http_port, #ifdef ENABLE_HTTPS unsigned short https_port, #endif unsigned int lifetime) { int i; struct lan_addr_s * lan_addr; for(i = 0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) { SendSSDPNotifies(sockets[i], lan_addr->str, http_port, #ifdef ENABLE_HTTPS https_port, #endif lifetime, 0); i++; #ifdef ENABLE_IPV6 if(sockets[i] >= 0) { SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, http_port, #ifdef ENABLE_HTTPS https_port, #endif lifetime, 1); } i++; #endif /* ENABLE_IPV6 */ } }