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 $
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.
Allow LAN interface to be given as interface names, instead of interface
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
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2012 Thomas Bernard
@ -26,8 +26,8 @@
/* SSDP ip/port */
#define SSDP_PORT (1900)
#define SSDP_MCAST_ADDR ("239.255.255.250")
#define LL_SSDP_MCAST_ADDR ("FF02::C")
#define SL_SSDP_MCAST_ADDR ("FF05::C")
#define LL_SSDP_MCAST_ADDR "FF02::C"
#define SL_SSDP_MCAST_ADDR "FF05::C"
/* AddMulticastMembership()
* param s socket
@ -216,28 +216,68 @@ OpenAndConfSSDPNotifySocket(in_addr_t addr)
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
OpenAndConfSSDPNotifySockets(int * sockets)
/*OpenAndConfSSDPNotifySockets(int * sockets,
struct lan_addr_s * lan_addr, int n_lan_addr)*/
{
int i, j;
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, 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);
if(sockets[i] < 0)
{
for(j=0; j<i; j++)
{
close(sockets[j]);
sockets[j] = -1;
}
return -1;
}
goto error;
i++;
#ifdef ENABLE_IPV6
sockets[i] = OpenAndConfSSDPNotifySocketIPv6(lan_addr->index);
if(sockets[i] < 0)
goto error;
i++;
#endif
}
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"
"SERVER: " MINIUPNPD_SERVER_STRING "\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 */
"BOOTID.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
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;
#endif
int l, n, i=0;
char bufr[512];
memset(&sockname, 0, sizeof(struct sockaddr_in));
sockname.sin_family = AF_INET;
sockname.sin_port = htons(SSDP_PORT);
sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
memset(&sockname, 0, sizeof(sockname));
#ifdef ENABLE_IPV6
if(ipv6)
{
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])
{
@ -354,12 +413,13 @@ SendSSDPNotifies(int s, const char * host, unsigned short port,
"NT: %s%s\r\n"
"USN: %s::%s%s\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 */
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
"\r\n",
SSDP_MCAST_ADDR, SSDP_PORT,
ipv6 ? "[" LL_SSDP_MCAST_ADDR "]" : SSDP_MCAST_ADDR,
SSDP_PORT,
lifetime,
host, port,
known_service_types[i], (i==0?"":"1"),
@ -371,7 +431,13 @@ SendSSDPNotifies(int s, const char * host, unsigned short port,
l = sizeof(bufr);
}
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)
{
/* XXX handle EINTR, EAGAIN, EWOULDBLOCK */
@ -388,9 +454,18 @@ SendSSDPNotifies2(int * sockets,
{
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, 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)
{
struct sockaddr_in sockname;
#ifdef ENABLE_IPV6
struct sockaddr_in6 sockname6;
#endif
int n, l;
int i, j;
char bufr[512];
int ret = 0;
int ipv6 = 0;
memset(&sockname, 0, sizeof(struct sockaddr_in));
sockname.sin_family = AF_INET;
sockname.sin_port = htons(SSDP_PORT);
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++)
{
#ifdef ENABLE_IPV6
ipv6 = j & 1;
#endif
for(i=0; known_service_types[i]; i++)
{
l = snprintf(bufr, sizeof(bufr),
@ -573,17 +661,19 @@ SendSSDPGoodbye(int * sockets, int n_sockets)
"NT: %s%s\r\n"
"USN: %s::%s%s\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 */
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
"\r\n",
SSDP_MCAST_ADDR, SSDP_PORT,
ipv6 ? "[" LL_SSDP_MCAST_ADDR "]" : SSDP_MCAST_ADDR,
SSDP_PORT,
known_service_types[i], (i==0?"":"1"),
uuidvalue, known_service_types[i], (i==0?"":"1"),
upnp_bootid, upnp_bootid, upnp_configid);
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)
{
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
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (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)
addr_count++;
if(addr_count > 0) {
#ifndef ENABLE_IPV6
snotify = calloc(addr_count, sizeof(int));
#else
/* one for IPv4, one for IPv6 */
snotify = calloc(addr_count * 2, sizeof(int));
#endif
}
#ifdef ENABLE_NATPMP
if(addr_count > 0) {
@ -1725,14 +1730,21 @@ shutdown:
}
#endif
/*if(SendSSDPGoodbye(snotify, v.n_lan_addr) < 0)*/
if (GETFLAG(ENABLEUPNPMASK))
{
#ifndef ENABLE_IPV6
if(SendSSDPGoodbye(snotify, addr_count) < 0)
#else
if(SendSSDPGoodbye(snotify, addr_count * 2) < 0)
#endif
{
syslog(LOG_ERR, "Failed to broadcast good-bye notifications");
}
#ifndef ENABLE_IPV6
for(i = 0; i < addr_count; i++)
#else
for(i = 0; i < addr_count * 2; i++)
#endif
close(snotify[i]);
}