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); |