Send SSDP NOTIFY ssdp:alive and ssdp:goodbye in IPv6 too

This commit is contained in:
Thomas Bernard 2012-04-06 19:30:19 +02:00
parent c28d256b30
commit 593dc26608
3 changed files with 134 additions and 30 deletions

View File

@ -1,6 +1,8 @@
$Id: Changelog.txt,v 1.267 2012/04/06 17:24:36 nanard Exp $ $Id: Changelog.txt,v 1.267 2012/04/06 17:24:36 nanard Exp $
2012/04/06: 2012/04/06:
Implementing IPv6 support :
Send SSDP NOTIFY ssdp:alive and ssdp:goodbye messages in IPv6.
Use UPnP/1.1 in SERVER: string as required in UPnP Device architecture 1.1. Use UPnP/1.1 in SERVER: string as required in UPnP Device architecture 1.1.
Allow LAN interface to be given as interface names, instead of interface Allow LAN interface to be given as interface names, instead of interface
IP addresses. It will allow IPv6 operations. IP addresses. It will allow IPv6 operations.

View File

@ -1,4 +1,4 @@
/* $Id: minissdp.c,v 1.29 2012/02/09 20:15:24 nanard Exp $ */ /* $Id: minissdp.c,v 1.31 2012/04/06 17:24:37 nanard Exp $ */
/* MiniUPnP project /* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2012 Thomas Bernard * (c) 2006-2012 Thomas Bernard
@ -26,8 +26,8 @@
/* 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
@ -216,28 +216,68 @@ 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;
} }
/* /*
@ -288,7 +328,7 @@ 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 */
@ -332,16 +372,35 @@ static const char * const known_service_types[] =
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];
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);
#ifdef ENABLE_IPV6
}
#endif
while(known_service_types[i]) while(known_service_types[i])
{ {
@ -354,12 +413,13 @@ SendSSDPNotifies(int s, const char * host, unsigned short port,
"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], (i==0?"":"1"),
@ -371,7 +431,13 @@ SendSSDPNotifies(int s, const char * host, unsigned short port,
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)
{ {
/* XXX handle EINTR, EAGAIN, EWOULDBLOCK */ /* XXX handle EINTR, EAGAIN, EWOULDBLOCK */
@ -388,9 +454,18 @@ 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
} }
} }
@ -553,18 +628,31 @@ 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];
int ret = 0; 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++)
{ {
#ifdef ENABLE_IPV6
ipv6 = j & 1;
#endif
for(i=0; known_service_types[i]; i++) for(i=0; known_service_types[i]; i++)
{ {
l = snprintf(bufr, sizeof(bufr), l = snprintf(bufr, sizeof(bufr),
@ -573,17 +661,19 @@ SendSSDPGoodbye(int * sockets, int n_sockets)
"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,
SSDP_PORT,
known_service_types[i], (i==0?"":"1"), known_service_types[i], (i==0?"":"1"),
uuidvalue, known_service_types[i], (i==0?"":"1"), uuidvalue, known_service_types[i], (i==0?"":"1"),
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) ); ipv6 ? (struct sockaddr *)&sockname6 : (struct sockaddr *)&sockname,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in) );
if(n < 0) if(n < 0)
{ {
syslog(LOG_ERR, "SendSSDPGoodbye: sendto(udp_shutdown=%d): %m", syslog(LOG_ERR, "SendSSDPGoodbye: sendto(udp_shutdown=%d): %m",

View File

@ -1,4 +1,4 @@
/* $Id: miniupnpd.c,v 1.150 2012/04/06 15:27:20 nanard Exp $ */ /* $Id: miniupnpd.c,v 1.151 2012/04/06 17:24:37 nanard Exp $ */
/* MiniUPnP project /* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2012 Thomas Bernard * (c) 2006-2012 Thomas Bernard
@ -1167,7 +1167,12 @@ main(int argc, char * * argv)
for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
addr_count++; addr_count++;
if(addr_count > 0) { if(addr_count > 0) {
#ifndef ENABLE_IPV6
snotify = calloc(addr_count, sizeof(int)); snotify = calloc(addr_count, sizeof(int));
#else
/* one for IPv4, one for IPv6 */
snotify = calloc(addr_count * 2, sizeof(int));
#endif
} }
#ifdef ENABLE_NATPMP #ifdef ENABLE_NATPMP
if(addr_count > 0) { if(addr_count > 0) {
@ -1725,14 +1730,21 @@ shutdown:
} }
#endif #endif
/*if(SendSSDPGoodbye(snotify, v.n_lan_addr) < 0)*/
if (GETFLAG(ENABLEUPNPMASK)) if (GETFLAG(ENABLEUPNPMASK))
{ {
#ifndef ENABLE_IPV6
if(SendSSDPGoodbye(snotify, addr_count) < 0) if(SendSSDPGoodbye(snotify, addr_count) < 0)
#else
if(SendSSDPGoodbye(snotify, addr_count * 2) < 0)
#endif
{ {
syslog(LOG_ERR, "Failed to broadcast good-bye notifications"); syslog(LOG_ERR, "Failed to broadcast good-bye notifications");
} }
for(i=0; i<addr_count; i++) #ifndef ENABLE_IPV6
for(i = 0; i < addr_count; i++)
#else
for(i = 0; i < addr_count * 2; i++)
#endif
close(snotify[i]); close(snotify[i]);
} }