|
version 1.1.1.2, 2012/05/29 12:55:57
|
version 1.1.1.3, 2013/07/22 00:32:35
|
|
Line 1
|
Line 1
|
| /* $Id$ */ |
/* $Id$ */ |
| /* MiniUPnP project |
/* MiniUPnP project |
| * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ |
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ |
| * (c) 2006-2011 Thomas Bernard | * (c) 2006-2013 Thomas Bernard |
| * This software is subject to the conditions detailed |
* This software is subject to the conditions detailed |
| * in the LICENCE file provided within the distribution */ |
* in the LICENCE file provided within the distribution */ |
| |
|
| #include <stdio.h> |
#include <stdio.h> |
| |
#include <stdlib.h> |
| #include <string.h> |
#include <string.h> |
| #include <unistd.h> |
#include <unistd.h> |
| #include <sys/socket.h> |
#include <sys/socket.h> |
| #include <sys/un.h> |
#include <sys/un.h> |
| #include <netinet/in.h> |
#include <netinet/in.h> |
| #include <arpa/inet.h> |
#include <arpa/inet.h> |
| |
#include <errno.h> |
| #include <syslog.h> |
#include <syslog.h> |
| |
|
| #include "config.h" |
#include "config.h" |
| #include "upnpdescstrings.h" |
#include "upnpdescstrings.h" |
| #include "miniupnpdpath.h" |
#include "miniupnpdpath.h" |
|
Line 20
|
Line 23
|
| #include "upnpglobalvars.h" |
#include "upnpglobalvars.h" |
| #include "minissdp.h" |
#include "minissdp.h" |
| #include "upnputils.h" |
#include "upnputils.h" |
| |
#include "getroute.h" |
| #include "codelength.h" |
#include "codelength.h" |
| |
|
| /* SSDP ip/port */ |
/* SSDP ip/port */ |
| #define SSDP_PORT (1900) |
#define SSDP_PORT (1900) |
| #define SSDP_MCAST_ADDR ("239.255.255.250") |
#define SSDP_MCAST_ADDR ("239.255.255.250") |
| #define LL_SSDP_MCAST_ADDR ("FF02::C") | #define LL_SSDP_MCAST_ADDR "FF02::C" |
| #define SL_SSDP_MCAST_ADDR ("FF05::C") | #define SL_SSDP_MCAST_ADDR "FF05::C" |
| |
|
| /* AddMulticastMembership() |
/* AddMulticastMembership() |
| * param s socket |
* param s socket |
|
Line 41 AddMulticastMembership(int s, in_addr_t ifaddr)
|
Line 45 AddMulticastMembership(int s, in_addr_t ifaddr)
|
| imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR); |
imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR); |
| /*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/ |
/*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/ |
| imr.imr_interface.s_addr = ifaddr; /*inet_addr(ifaddr);*/ |
imr.imr_interface.s_addr = ifaddr; /*inet_addr(ifaddr);*/ |
| | |
| if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreq)) < 0) |
if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreq)) < 0) |
| { |
{ |
| syslog(LOG_ERR, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m"); |
syslog(LOG_ERR, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m"); |
|
Line 83 AddMulticastMembershipIPv6(int s)
|
Line 87 AddMulticastMembershipIPv6(int s)
|
| } |
} |
| #endif |
#endif |
| |
|
| /* Open and configure the socket listening for | /* Open and configure the socket listening for |
| * SSDP udp packets sent on 239.255.255.250 port 1900 |
* SSDP udp packets sent on 239.255.255.250 port 1900 |
| * SSDP v6 udp packets sent on FF02::C, or FF05::C, port 1900 */ |
* SSDP v6 udp packets sent on FF02::C, or FF05::C, port 1900 */ |
| int |
int |
|
Line 97 OpenAndConfSSDPReceiveSocket(int ipv6)
|
Line 101 OpenAndConfSSDPReceiveSocket(int ipv6)
|
| |
|
| if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0) |
if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0) |
| { |
{ |
| syslog(LOG_ERR, "socket(udp): %m"); | syslog(LOG_ERR, "%s: socket(udp): %m", |
| | "OpenAndConfSSDPReceiveSocket"); |
| return -1; |
return -1; |
| } |
} |
| |
|
|
Line 124 OpenAndConfSSDPReceiveSocket(int ipv6)
|
Line 129 OpenAndConfSSDPReceiveSocket(int ipv6)
|
| syslog(LOG_WARNING, "setsockopt(udp, SO_REUSEADDR): %m"); |
syslog(LOG_WARNING, "setsockopt(udp, SO_REUSEADDR): %m"); |
| } |
} |
| |
|
| |
if(!set_non_blocking(s)) |
| |
{ |
| |
syslog(LOG_WARNING, "%s: set_non_blocking(): %m", |
| |
"OpenAndConfSSDPReceiveSocket"); |
| |
} |
| |
|
| if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0) |
if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0) |
| { |
{ |
| syslog(LOG_ERR, "bind(udp%s): %m", ipv6 ? "6" : ""); | syslog(LOG_ERR, "%s: bind(udp%s): %m", |
| | "OpenAndConfSSDPReceiveSocket", ipv6 ? "6" : ""); |
| close(s); |
close(s); |
| return -1; |
return -1; |
| } |
} |
|
Line 145 OpenAndConfSSDPReceiveSocket(int ipv6)
|
Line 156 OpenAndConfSSDPReceiveSocket(int ipv6)
|
| if(AddMulticastMembership(s, lan_addr->addr.s_addr) < 0) |
if(AddMulticastMembership(s, lan_addr->addr.s_addr) < 0) |
| { |
{ |
| syslog(LOG_WARNING, |
syslog(LOG_WARNING, |
| "Failed to add multicast membership for interface %s", | "Failed to add multicast membership for interface %s", |
| lan_addr->str); | lan_addr->str ? lan_addr->str : "NULL"); |
| } |
} |
| } |
} |
| } |
} |
|
Line 162 OpenAndConfSSDPNotifySocket(in_addr_t addr)
|
Line 173 OpenAndConfSSDPNotifySocket(in_addr_t addr)
|
| int s; |
int s; |
| unsigned char loopchar = 0; |
unsigned char loopchar = 0; |
| int bcast = 1; |
int bcast = 1; |
| |
unsigned char ttl = 2; /* UDA v1.1 says : |
| |
The TTL for the IP packet SHOULD default to 2 and |
| |
SHOULD be configurable. */ |
| |
/* TODO: Make TTL be configurable */ |
| struct in_addr mc_if; |
struct in_addr mc_if; |
| struct sockaddr_in sockname; |
struct sockaddr_in sockname; |
| | |
| if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) |
if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) |
| { |
{ |
| syslog(LOG_ERR, "socket(udp_notify): %m"); |
syslog(LOG_ERR, "socket(udp_notify): %m"); |
|
Line 186 OpenAndConfSSDPNotifySocket(in_addr_t addr)
|
Line 201 OpenAndConfSSDPNotifySocket(in_addr_t addr)
|
| close(s); |
close(s); |
| return -1; |
return -1; |
| } |
} |
| | |
| | if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) |
| | { |
| | syslog(LOG_WARNING, "setsockopt(udp_notify, IP_MULTICAST_TTL,): %m"); |
| | } |
| | |
| if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast)) < 0) |
if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast)) < 0) |
| { |
{ |
| syslog(LOG_ERR, "setsockopt(udp_notify, SO_BROADCAST): %m"); |
syslog(LOG_ERR, "setsockopt(udp_notify, SO_BROADCAST): %m"); |
|
Line 208 OpenAndConfSSDPNotifySocket(in_addr_t addr)
|
Line 228 OpenAndConfSSDPNotifySocket(in_addr_t addr)
|
| return s; |
return s; |
| } |
} |
| |
|
| |
#ifdef ENABLE_IPV6 |
| |
/* open the UDP socket used to send SSDP notifications to |
| |
* the multicast group reserved for them. IPv6 */ |
| |
static int |
| |
OpenAndConfSSDPNotifySocketIPv6(unsigned int if_index) |
| |
{ |
| |
int s; |
| |
unsigned int loop = 0; |
| |
|
| |
s = socket(PF_INET6, SOCK_DGRAM, 0); |
| |
if(s < 0) |
| |
{ |
| |
syslog(LOG_ERR, "socket(udp_notify IPv6): %m"); |
| |
return -1; |
| |
} |
| |
if(setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_index, sizeof(if_index)) < 0) |
| |
{ |
| |
syslog(LOG_ERR, "setsockopt(udp_notify IPv6, IPV6_MULTICAST_IF, %u): %m", if_index); |
| |
close(s); |
| |
return -1; |
| |
} |
| |
if(setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) |
| |
{ |
| |
syslog(LOG_ERR, "setsockopt(udp_notify, IPV6_MULTICAST_LOOP): %m"); |
| |
close(s); |
| |
return -1; |
| |
} |
| |
return s; |
| |
} |
| |
#endif |
| |
|
| int |
int |
| OpenAndConfSSDPNotifySockets(int * sockets) |
OpenAndConfSSDPNotifySockets(int * sockets) |
| /*OpenAndConfSSDPNotifySockets(int * sockets, |
/*OpenAndConfSSDPNotifySockets(int * sockets, |
| struct lan_addr_s * lan_addr, int n_lan_addr)*/ |
struct lan_addr_s * lan_addr, int n_lan_addr)*/ |
| { |
{ |
| int i, j; | int i; |
| struct lan_addr_s * lan_addr; |
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, i++) | for(i=0, lan_addr = lan_addrs.lh_first; |
| | lan_addr != NULL; |
| | lan_addr = lan_addr->list.le_next) |
| { |
{ |
| sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr->addr.s_addr); |
sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr->addr.s_addr); |
| if(sockets[i] < 0) |
if(sockets[i] < 0) |
| { | goto error; |
| for(j=0; j<i; j++) | i++; |
| { | #ifdef ENABLE_IPV6 |
| close(sockets[j]); | sockets[i] = OpenAndConfSSDPNotifySocketIPv6(lan_addr->index); |
| sockets[j] = -1; | if(sockets[i] < 0) |
| } | goto error; |
| return -1; | i++; |
| } | #endif |
| } |
} |
| return 0; |
return 0; |
| |
error: |
| |
while(--i >= 0) |
| |
{ |
| |
close(sockets[i]); |
| |
sockets[i] = -1; |
| |
} |
| |
return -1; |
| } |
} |
| |
|
| /* |
/* |
|
Line 262 SendSSDPAnnounce2(int s, const struct sockaddr * addr,
|
Line 322 SendSSDPAnnounce2(int s, const struct sockaddr * addr,
|
| { |
{ |
| int l, n; |
int l, n; |
| char buf[512]; |
char buf[512]; |
| |
char addr_str[64]; |
| socklen_t addrlen; |
socklen_t addrlen; |
| /* | /* |
| * follow guideline from document "UPnP Device Architecture 1.0" |
* follow guideline from document "UPnP Device Architecture 1.0" |
| * uppercase is recommended. |
* uppercase is recommended. |
| * DATE: is recommended |
* DATE: is recommended |
| * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0 |
* SERVER: OS/ver UPnP/1.0 miniupnpd/1.0 |
| * - check what to put in the 'Cache-Control' header | * - check what to put in the 'Cache-Control' header |
| * |
* |
| * have a look at the document "UPnP Device Architecture v1.1 */ |
* have a look at the document "UPnP Device Architecture v1.1 */ |
| l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n" |
l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n" |
|
Line 279 SendSSDPAnnounce2(int s, const struct sockaddr * addr,
|
Line 340 SendSSDPAnnounce2(int s, const struct sockaddr * addr,
|
| "EXT:\r\n" |
"EXT:\r\n" |
| "SERVER: " MINIUPNPD_SERVER_STRING "\r\n" |
"SERVER: " MINIUPNPD_SERVER_STRING "\r\n" |
| "LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n" |
"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n" |
| "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */ | "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */ |
| "01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */ |
"01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */ |
| "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
| "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
|
Line 292 SendSSDPAnnounce2(int s, const struct sockaddr * addr,
|
Line 353 SendSSDPAnnounce2(int s, const struct sockaddr * addr,
|
| ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); |
? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); |
| n = sendto(s, buf, l, 0, |
n = sendto(s, buf, l, 0, |
| addr, addrlen); |
addr, addrlen); |
| syslog(LOG_INFO, "SSDP Announce %d bytes to %s:%d ST: %.*s",n, | sockaddr_to_string(addr, addr_str, sizeof(addr_str)); |
| inet_ntoa(((const struct sockaddr_in *)addr)->sin_addr), | syslog(LOG_INFO, "SSDP Announce %d bytes to %s ST: %.*s",n, |
| ntohs(((const struct sockaddr_in *)addr)->sin_port), | addr_str, |
| l, buf); |
l, buf); |
| if(n < 0) |
if(n < 0) |
| { |
{ |
| |
/* XXX handle EINTR, EAGAIN, EWOULDBLOCK */ |
| syslog(LOG_ERR, "sendto(udp): %m"); |
syslog(LOG_ERR, "sendto(udp): %m"); |
| } |
} |
| } |
} |
| |
|
| static const char * const known_service_types[] = | #ifndef IGD_V2 |
| | #define IGD_VER 1 |
| | #define WANIPC_VER 1 |
| | #else |
| | #define IGD_VER 2 |
| | #define WANIPC_VER 2 |
| | #endif |
| | |
| | static struct { |
| | const char * s; |
| | const int version; |
| | } const known_service_types[] = |
| { |
{ |
| "upnp:rootdevice", | {"upnp:rootdevice", 0}, |
| "urn:schemas-upnp-org:device:InternetGatewayDevice:", | {"urn:schemas-upnp-org:device:InternetGatewayDevice:", IGD_VER}, |
| "urn:schemas-upnp-org:device:WANConnectionDevice:", | {"urn:schemas-upnp-org:device:WANConnectionDevice:", 1}, |
| "urn:schemas-upnp-org:device:WANDevice:", | {"urn:schemas-upnp-org:device:WANDevice:", 1}, |
| "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:", | {"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:", 1}, |
| "urn:schemas-upnp-org:service:WANIPConnection:", | {"urn:schemas-upnp-org:service:WANIPConnection:", WANIPC_VER}, |
| "urn:schemas-upnp-org:service:WANPPPConnection:", | {"urn:schemas-upnp-org:service:WANPPPConnection:", 1}, |
| #ifdef ENABLE_L3F_SERVICE |
#ifdef ENABLE_L3F_SERVICE |
| "urn:schemas-upnp-org:service:Layer3Forwarding:", | {"urn:schemas-upnp-org:service:Layer3Forwarding:", 1}, |
| #endif |
#endif |
| #ifdef ENABLE_6FC_SERVICE |
#ifdef ENABLE_6FC_SERVICE |
| "url:schemas-upnp-org:service:WANIPv6FirewallControl:", | {"url:schemas-upnp-org:service:WANIPv6FirewallControl:", 1}, |
| #endif |
#endif |
| 0 | {0, 0} |
| }; |
}; |
| |
|
| static void |
static void |
| SendSSDPNotifies(int s, const char * host, unsigned short port, |
SendSSDPNotifies(int s, const char * host, unsigned short port, |
| unsigned int lifetime) | unsigned int lifetime, int ipv6) |
| { |
{ |
| |
#ifdef ENABLE_IPV6 |
| |
struct sockaddr_storage sockname; |
| |
#else |
| struct sockaddr_in sockname; |
struct sockaddr_in sockname; |
| |
#endif |
| int l, n, i=0; |
int l, n, i=0; |
| char bufr[512]; |
char bufr[512]; |
| |
char ver_str[4]; |
| |
|
| memset(&sockname, 0, sizeof(struct sockaddr_in)); | memset(&sockname, 0, sizeof(sockname)); |
| sockname.sin_family = AF_INET; | #ifdef ENABLE_IPV6 |
| sockname.sin_port = htons(SSDP_PORT); | if(ipv6) |
| sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); | { |
| | struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockname; |
| | p->sin6_family = AF_INET6; |
| | p->sin6_port = htons(SSDP_PORT); |
| | inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &(p->sin6_addr)); |
| | } |
| | else |
| | #endif |
| | { |
| | struct sockaddr_in *p = (struct sockaddr_in *)&sockname; |
| | p->sin_family = AF_INET; |
| | p->sin_port = htons(SSDP_PORT); |
| | p->sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); |
| | } |
| |
|
| while(known_service_types[i]) | while(known_service_types[i].s) |
| { |
{ |
| l = snprintf(bufr, sizeof(bufr), | if(i==0) |
| | ver_str[0] = '\0'; |
| | else |
| | snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version); |
| | l = snprintf(bufr, sizeof(bufr), |
| "NOTIFY * HTTP/1.1\r\n" |
"NOTIFY * HTTP/1.1\r\n" |
| "HOST: %s:%d\r\n" |
"HOST: %s:%d\r\n" |
| "CACHE-CONTROL: max-age=%u\r\n" |
"CACHE-CONTROL: max-age=%u\r\n" |
|
Line 344 SendSSDPNotifies(int s, const char * host, unsigned sh
|
Line 439 SendSSDPNotifies(int s, const char * host, unsigned sh
|
| "NT: %s%s\r\n" |
"NT: %s%s\r\n" |
| "USN: %s::%s%s\r\n" |
"USN: %s::%s%s\r\n" |
| "NTS: ssdp:alive\r\n" |
"NTS: ssdp:alive\r\n" |
| "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */ | "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */ |
| "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */ |
"01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */ |
| "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
| "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
| "\r\n", |
"\r\n", |
| SSDP_MCAST_ADDR, SSDP_PORT, | ipv6 ? "[" LL_SSDP_MCAST_ADDR "]" : SSDP_MCAST_ADDR, |
| | SSDP_PORT, |
| lifetime, |
lifetime, |
| host, port, |
host, port, |
| known_service_types[i], (i==0?"":"1"), | known_service_types[i].s, ver_str, |
| uuidvalue, known_service_types[i], (i==0?"":"1"), | uuidvalue, known_service_types[i].s, ver_str, |
| upnp_bootid, upnp_bootid, upnp_configid ); |
upnp_bootid, upnp_bootid, upnp_configid ); |
| if(l>=sizeof(bufr)) | if(l<0) |
| { |
{ |
| |
syslog(LOG_ERR, "SendSSDPNotifies() snprintf error"); |
| |
continue; |
| |
} |
| |
if((unsigned int)l >= sizeof(bufr)) |
| |
{ |
| syslog(LOG_WARNING, "SendSSDPNotifies(): truncated output"); |
syslog(LOG_WARNING, "SendSSDPNotifies(): truncated output"); |
| l = sizeof(bufr); |
l = sizeof(bufr); |
| } |
} |
| n = sendto(s, bufr, l, 0, |
n = sendto(s, bufr, l, 0, |
| (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) ); | (struct sockaddr *)&sockname, |
| | #ifdef ENABLE_IPV6 |
| | ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in) |
| | #else |
| | sizeof(struct sockaddr_in) |
| | #endif |
| | ); |
| if(n < 0) |
if(n < 0) |
| { |
{ |
| syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s, host); | /* XXX handle EINTR, EAGAIN, EWOULDBLOCK */ |
| | syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s, |
| | host ? host : "NULL"); |
| } |
} |
| i++; |
i++; |
| } |
} |
|
Line 377 SendSSDPNotifies2(int * sockets,
|
Line 486 SendSSDPNotifies2(int * sockets,
|
| { |
{ |
| int i; |
int i; |
| struct lan_addr_s * lan_addr; |
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, i++) | 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, port, lifetime); | SendSSDPNotifies(sockets[i], lan_addr->str, port, |
| | lifetime, 0); |
| | i++; |
| | #ifdef ENABLE_IPV6 |
| | SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, port, |
| | lifetime, 1); |
| | i++; |
| | #endif |
| } |
} |
| } |
} |
| |
|
|
Line 403 ProcessSSDPRequest(int s, unsigned short port)
|
Line 521 ProcessSSDPRequest(int s, unsigned short port)
|
| (struct sockaddr *)&sendername, &len_r); |
(struct sockaddr *)&sendername, &len_r); |
| if(n < 0) |
if(n < 0) |
| { |
{ |
| syslog(LOG_ERR, "recvfrom(udp): %m"); | /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time) |
| | * other errors : log to LOG_ERR */ |
| | if(errno != EAGAIN && |
| | errno != EWOULDBLOCK && |
| | errno != EINTR) |
| | { |
| | syslog(LOG_ERR, "recvfrom(udp): %m"); |
| | } |
| return; |
return; |
| } |
} |
| ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, port); |
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, port); |
|
Line 417 ProcessSSDPData(int s, const char *bufr, int n,
|
Line 542 ProcessSSDPData(int s, const char *bufr, int n,
|
| struct lan_addr_s * lan_addr = NULL; |
struct lan_addr_s * lan_addr = NULL; |
| const char * st = NULL; |
const char * st = NULL; |
| int st_len = 0; |
int st_len = 0; |
| |
int st_ver = 0; |
| char sender_str[64]; |
char sender_str[64]; |
| |
char ver_str[4]; |
| const char * announced_host = NULL; |
const char * announced_host = NULL; |
| |
#ifdef ENABLE_IPV6 |
| |
#ifdef UPNP_STRICT |
| |
char announced_host_buf[64]; |
| |
#endif |
| |
#endif |
| |
|
| /* get the string representation of the sender address */ |
/* get the string representation of the sender address */ |
| sockaddr_to_string(sender, sender_str, sizeof(sender_str)); |
sockaddr_to_string(sender, sender_str, sizeof(sender_str)); |
| |
lan_addr = get_lan_for_peer(sender); |
| |
if(lan_addr == NULL) |
| |
{ |
| |
syslog(LOG_WARNING, "SSDP packet sender %s not from a LAN, ignoring", |
| |
sender_str); |
| |
return; |
| |
} |
| |
|
| if(memcmp(bufr, "NOTIFY", 6) == 0) |
if(memcmp(bufr, "NOTIFY", 6) == 0) |
| { |
{ |
|
Line 445 ProcessSSDPData(int s, const char *bufr, int n,
|
Line 584 ProcessSSDPData(int s, const char *bufr, int n,
|
| while(st[st_len]!='\r' && st[st_len]!='\n' |
while(st[st_len]!='\r' && st[st_len]!='\n' |
| && (st + st_len < bufr + n)) |
&& (st + st_len < bufr + n)) |
| st_len++; |
st_len++; |
| /*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/ | l = st_len; |
| | while(l > 0 && st[l-1] != ':') |
| | l--; |
| | st_ver = atoi(st+l); |
| | syslog(LOG_DEBUG, "ST: %.*s (ver=%d)", st_len, st, st_ver); |
| /*j = 0;*/ |
/*j = 0;*/ |
| /*while(bufr[i+j]!='\r') j++;*/ |
/*while(bufr[i+j]!='\r') j++;*/ |
| /*syslog(LOG_INFO, "%.*s", j, bufr+i);*/ |
/*syslog(LOG_INFO, "%.*s", j, bufr+i);*/ |
|
Line 461 ProcessSSDPData(int s, const char *bufr, int n,
|
Line 604 ProcessSSDPData(int s, const char *bufr, int n,
|
| /* find in which sub network the client is */ |
/* find in which sub network the client is */ |
| if(sender->sa_family == AF_INET) |
if(sender->sa_family == AF_INET) |
| { |
{ |
| for(lan_addr = lan_addrs.lh_first; |
|
| lan_addr != NULL; |
|
| lan_addr = lan_addr->list.le_next) |
|
| { |
|
| if( (((const struct sockaddr_in *)sender)->sin_addr.s_addr & lan_addr->mask.s_addr) |
|
| == (lan_addr->addr.s_addr & lan_addr->mask.s_addr)) |
|
| break; |
|
| } |
|
| if (lan_addr == NULL) |
if (lan_addr == NULL) |
| { |
{ |
| syslog(LOG_ERR, "Can't find in which sub network the client is"); |
syslog(LOG_ERR, "Can't find in which sub network the client is"); |
|
Line 480 ProcessSSDPData(int s, const char *bufr, int n,
|
Line 615 ProcessSSDPData(int s, const char *bufr, int n,
|
| else |
else |
| { |
{ |
| /* IPv6 address with brackets */ |
/* IPv6 address with brackets */ |
| |
#ifdef UPNP_STRICT |
| |
int index; |
| |
struct in6_addr addr6; |
| |
size_t addr6_len = sizeof(addr6); |
| |
/* retrieve the IPv6 address which |
| |
* will be used locally to reach sender */ |
| |
memset(&addr6, 0, sizeof(addr6)); |
| |
if(get_src_for_route_to (sender, &addr6, &addr6_len, &index) < 0) { |
| |
syslog(LOG_WARNING, "get_src_for_route_to() failed, using %s", ipv6_addr_for_http_with_brackets); |
| |
announced_host = ipv6_addr_for_http_with_brackets; |
| |
} else { |
| |
if(inet_ntop(AF_INET6, &addr6, |
| |
announced_host_buf+1, |
| |
sizeof(announced_host_buf) - 2)) { |
| |
announced_host_buf[0] = '['; |
| |
i = strlen(announced_host_buf); |
| |
if(i < (int)sizeof(announced_host_buf) - 1) { |
| |
announced_host_buf[i] = ']'; |
| |
announced_host_buf[i+1] = '\0'; |
| |
} else { |
| |
syslog(LOG_NOTICE, "cannot suffix %s with ']'", |
| |
announced_host_buf); |
| |
} |
| |
announced_host = announced_host_buf; |
| |
} else { |
| |
syslog(LOG_NOTICE, "inet_ntop() failed %m"); |
| |
announced_host = ipv6_addr_for_http_with_brackets; |
| |
} |
| |
} |
| |
#else |
| announced_host = ipv6_addr_for_http_with_brackets; |
announced_host = ipv6_addr_for_http_with_brackets; |
| |
#endif |
| } |
} |
| #endif |
#endif |
| /* Responds to request with a device as ST header */ |
/* Responds to request with a device as ST header */ |
| for(i = 0; known_service_types[i]; i++) | for(i = 0; known_service_types[i].s; i++) |
| { |
{ |
| l = (int)strlen(known_service_types[i]); | l = (int)strlen(known_service_types[i].s); |
| if(l<=st_len && (0 == memcmp(st, known_service_types[i], l))) | if(l<=st_len && (0 == memcmp(st, known_service_types[i].s, l)) |
| | #ifdef UPNP_STRICT |
| | && (st_ver <= known_service_types[i].version) |
| | /* only answer for service version lower or equal of supported one */ |
| | #endif |
| | ) |
| { |
{ |
| syslog(LOG_INFO, "Single search found"); |
syslog(LOG_INFO, "Single search found"); |
| SendSSDPAnnounce2(s, sender, |
SendSSDPAnnounce2(s, sender, |
|
Line 501 ProcessSSDPData(int s, const char *bufr, int n,
|
Line 672 ProcessSSDPData(int s, const char *bufr, int n,
|
| if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8))) |
if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8))) |
| { |
{ |
| syslog(LOG_INFO, "ssdp:all found"); |
syslog(LOG_INFO, "ssdp:all found"); |
| for(i=0; known_service_types[i]; i++) | for(i=0; known_service_types[i].s; i++) |
| { |
{ |
| l = (int)strlen(known_service_types[i]); | if(i==0) |
| | ver_str[0] = '\0'; |
| | else |
| | snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version); |
| | l = (int)strlen(known_service_types[i].s); |
| SendSSDPAnnounce2(s, sender, |
SendSSDPAnnounce2(s, sender, |
| known_service_types[i], l, i==0?"":"1", | known_service_types[i].s, l, ver_str, |
| announced_host, port); |
announced_host, port); |
| } |
} |
| |
/* also answer for uuid */ |
| |
SendSSDPAnnounce2(s, sender, uuidvalue, strlen(uuidvalue), "", |
| |
announced_host, port); |
| } |
} |
| /* responds to request by UUID value */ |
/* responds to request by UUID value */ |
| l = (int)strlen(uuidvalue); |
l = (int)strlen(uuidvalue); |
|
Line 529 ProcessSSDPData(int s, const char *bufr, int n,
|
Line 707 ProcessSSDPData(int s, const char *bufr, int n,
|
| } |
} |
| } |
} |
| |
|
| /* This will broadcast ssdp:byebye notifications to inform | /* This will broadcast ssdp:byebye notifications to inform |
| * the network that UPnP is going down. */ |
* the network that UPnP is going down. */ |
| int |
int |
| SendSSDPGoodbye(int * sockets, int n_sockets) |
SendSSDPGoodbye(int * sockets, int n_sockets) |
| { |
{ |
| struct sockaddr_in sockname; |
struct sockaddr_in sockname; |
| |
#ifdef ENABLE_IPV6 |
| |
struct sockaddr_in6 sockname6; |
| |
#endif |
| int n, l; |
int n, l; |
| int i, j; |
int i, j; |
| char bufr[512]; |
char bufr[512]; |
| |
char ver_str[4]; |
| |
int ret = 0; |
| |
int ipv6 = 0; |
| |
|
| memset(&sockname, 0, sizeof(struct sockaddr_in)); |
memset(&sockname, 0, sizeof(struct sockaddr_in)); |
| sockname.sin_family = AF_INET; |
sockname.sin_family = AF_INET; |
| sockname.sin_port = htons(SSDP_PORT); |
sockname.sin_port = htons(SSDP_PORT); |
| sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); |
sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); |
| |
#ifdef ENABLE_IPV6 |
| |
memset(&sockname6, 0, sizeof(struct sockaddr_in6)); |
| |
sockname6.sin6_family = AF_INET6; |
| |
sockname6.sin6_port = htons(SSDP_PORT); |
| |
inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &(sockname6.sin6_addr)); |
| |
#endif |
| |
|
| for(j=0; j<n_sockets; j++) |
for(j=0; j<n_sockets; j++) |
| { |
{ |
| for(i=0; known_service_types[i]; i++) | #ifdef ENABLE_IPV6 |
| | ipv6 = j & 1; |
| | #endif |
| | 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); |
| l = snprintf(bufr, sizeof(bufr), |
l = snprintf(bufr, sizeof(bufr), |
| "NOTIFY * HTTP/1.1\r\n" |
"NOTIFY * HTTP/1.1\r\n" |
| "HOST: %s:%d\r\n" |
"HOST: %s:%d\r\n" |
| "NT: %s%s\r\n" |
"NT: %s%s\r\n" |
| "USN: %s::%s%s\r\n" |
"USN: %s::%s%s\r\n" |
| "NTS: ssdp:byebye\r\n" |
"NTS: ssdp:byebye\r\n" |
| "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */ | "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */ |
| "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */ |
"01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */ |
| "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
| "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ |
| "\r\n", |
"\r\n", |
| SSDP_MCAST_ADDR, SSDP_PORT, | ipv6 ? "[" LL_SSDP_MCAST_ADDR "]" : SSDP_MCAST_ADDR, |
| known_service_types[i], (i==0?"":"1"), | SSDP_PORT, |
| uuidvalue, known_service_types[i], (i==0?"":"1"), | known_service_types[i].s, ver_str, |
| | uuidvalue, known_service_types[i].s, ver_str, |
| upnp_bootid, upnp_bootid, upnp_configid); |
upnp_bootid, upnp_bootid, upnp_configid); |
| n = sendto(sockets[j], bufr, l, 0, |
n = sendto(sockets[j], bufr, l, 0, |
| (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) ); | #ifdef ENABLE_IPV6 |
| | ipv6 ? (struct sockaddr *)&sockname6 : (struct sockaddr *)&sockname, |
| | ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in) |
| | #else |
| | (struct sockaddr *)&sockname, |
| | sizeof(struct sockaddr_in) |
| | #endif |
| | ); |
| if(n < 0) |
if(n < 0) |
| { |
{ |
| syslog(LOG_ERR, "SendSSDPGoodbye: sendto(udp_shutdown=%d): %m", |
syslog(LOG_ERR, "SendSSDPGoodbye: sendto(udp_shutdown=%d): %m", |
| sockets[j]); |
sockets[j]); |
| return -1; | ret = -1; |
| } |
} |
| } |
} |
| } |
} |
| return 0; | return ret; |
| } |
} |
| |
|
| /* SubmitServicesToMiniSSDPD() : |
/* SubmitServicesToMiniSSDPD() : |
|
Line 586 SubmitServicesToMiniSSDPD(const char * host, unsigned
|
Line 791 SubmitServicesToMiniSSDPD(const char * host, unsigned
|
| unsigned char buffer[2048]; |
unsigned char buffer[2048]; |
| char strbuf[256]; |
char strbuf[256]; |
| unsigned char * p; |
unsigned char * p; |
| int i, l; | int i, l, n; |
| | char ver_str[4]; |
| |
|
| s = socket(AF_UNIX, SOCK_STREAM, 0); |
s = socket(AF_UNIX, SOCK_STREAM, 0); |
| if(s < 0) { |
if(s < 0) { |
|
Line 597 SubmitServicesToMiniSSDPD(const char * host, unsigned
|
Line 803 SubmitServicesToMiniSSDPD(const char * host, unsigned
|
| strncpy(addr.sun_path, minissdpdsocketpath, sizeof(addr.sun_path)); |
strncpy(addr.sun_path, minissdpdsocketpath, sizeof(addr.sun_path)); |
| if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { |
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { |
| syslog(LOG_ERR, "connect(\"%s\"): %m", minissdpdsocketpath); |
syslog(LOG_ERR, "connect(\"%s\"): %m", minissdpdsocketpath); |
| |
close(s); |
| return -1; |
return -1; |
| } |
} |
| for(i = 0; known_service_types[i]; i++) { | for(i = 0; known_service_types[i].s; i++) { |
| buffer[0] = 4; | buffer[0] = 4; /* request type 4 : submit service */ |
| | /* 4 strings following : ST (service type), USN, Server, Location */ |
| p = buffer + 1; |
p = buffer + 1; |
| l = (int)strlen(known_service_types[i]); | l = (int)strlen(known_service_types[i].s); |
| if(i > 0) |
if(i > 0) |
| l++; |
l++; |
| CODELENGTH(l, p); |
CODELENGTH(l, p); |
| memcpy(p, known_service_types[i], l); | memcpy(p, known_service_types[i].s, l); |
| if(i > 0) |
if(i > 0) |
| p[l-1] = '1'; |
p[l-1] = '1'; |
| p += l; |
p += l; |
| l = snprintf(strbuf, sizeof(strbuf), "%s::%s%s", | if(i==0) |
| uuidvalue, known_service_types[i], (i==0)?"":"1"); | ver_str[0] = '\0'; |
| | else |
| | snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version); |
| | l = snprintf(strbuf, sizeof(strbuf), "%s::%s%s", |
| | uuidvalue, known_service_types[i].s, ver_str); |
| CODELENGTH(l, p); |
CODELENGTH(l, p); |
| memcpy(p, strbuf, l); |
memcpy(p, strbuf, l); |
| p += l; |
p += l; |
|
Line 624 SubmitServicesToMiniSSDPD(const char * host, unsigned
|
Line 836 SubmitServicesToMiniSSDPD(const char * host, unsigned
|
| CODELENGTH(l, p); |
CODELENGTH(l, p); |
| memcpy(p, strbuf, l); |
memcpy(p, strbuf, l); |
| p += l; |
p += l; |
| if(write(s, buffer, p - buffer) < 0) { | /* now write the encoded data */ |
| syslog(LOG_ERR, "write(): %m"); | n = p - buffer; /* bytes to send */ |
| return -1; | p = buffer; /* start */ |
| | while(n > 0) { |
| | l = write(s, p, n); |
| | if (l < 0) { |
| | syslog(LOG_ERR, "write(): %m"); |
| | close(s); |
| | return -1; |
| | } else if (l == 0) { |
| | syslog(LOG_ERR, "write() returned 0"); |
| | close(s); |
| | return -1; |
| | } |
| | p += l; |
| | n -= l; |
| } |
} |
| } |
} |
| close(s); |
close(s); |