Diff for /embedaddon/miniupnpd/minissdp.c between versions 1.1.1.2 and 1.1.1.3

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

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>