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

version 1.1.1.1, 2012/02/21 23:16:02 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-2010 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"
 #include "upnphttp.h"  #include "upnphttp.h"
 #include "upnpglobalvars.h"  #include "upnpglobalvars.h"
 #include "minissdp.h"  #include "minissdp.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)
 /* Prototypes */  
 void ProcessSSDPData(int s, char *bufr, struct sockaddr_in sendername, int n, unsigned short port) ;  
   
   
 #define SSDP_MCAST_ADDR ("239.255.255.250")  #define SSDP_MCAST_ADDR ("239.255.255.250")
   #define LL_SSDP_MCAST_ADDR "FF02::C"
   #define SL_SSDP_MCAST_ADDR "FF05::C"
   
   /* AddMulticastMembership()
    * param s              socket
    * param ifaddr ip v4 address
    */
 static int  static int
 AddMulticastMembership(int s, in_addr_t ifaddr)  AddMulticastMembership(int s, in_addr_t ifaddr)
 {  {
Line 38  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 48  AddMulticastMembership(int s, in_addr_t ifaddr) Line 55  AddMulticastMembership(int s, in_addr_t ifaddr)
         return 0;          return 0;
 }  }
   
/* Open and configure the socket listening for /* AddMulticastMembershipIPv6()
 * SSDP udp packets sent on 239.255.255.250 port 1900 */ * param s      socket (IPv6)
  * To be improved to target specific network interfaces */
 #ifdef ENABLE_IPV6
 static int
 AddMulticastMembershipIPv6(int s)
 {
         struct ipv6_mreq mr;
         /*unsigned int ifindex;*/
 
         memset(&mr, 0, sizeof(mr));
         inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
         /*mr.ipv6mr_interface = ifindex;*/
         mr.ipv6mr_interface = 0; /* 0 : all interfaces */
 #ifndef IPV6_ADD_MEMBERSHIP
 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
 #endif
         if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
         {
                 syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
                 return -1;
         }
         inet_pton(AF_INET6, SL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
         if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
         {
                 syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
                 return -1;
         }
         return 0;
 }
 #endif
 
 /* Open and configure the socket listening for
  * SSDP udp packets sent on 239.255.255.250 port 1900
  * SSDP v6 udp packets sent on FF02::C, or FF05::C, port 1900 */
 int  int
OpenAndConfSSDPReceiveSocket()OpenAndConfSSDPReceiveSocket(int ipv6)
 {  {
         int s;          int s;
        int i;        struct sockaddr_storage sockname;
         socklen_t sockname_len;
         struct lan_addr_s * lan_addr;
         int j = 1;          int j = 1;
        struct sockaddr_in sockname;
                if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
        if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) 
         {          {
                syslog(LOG_ERR, "socket(udp): %m");                syslog(LOG_ERR, "%s: socket(udp): %m",
                        "OpenAndConfSSDPReceiveSocket");
                 return -1;                  return -1;
        }               }
         
        memset(&sockname, 0, sizeof(struct sockaddr_in)); 
    sockname.sin_family = AF_INET; 
    sockname.sin_port = htons(SSDP_PORT); 
        /* NOTE : it seems it doesnt work when binding on the specific address */ 
    /*sockname.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/ 
    sockname.sin_addr.s_addr = htonl(INADDR_ANY); 
    /*sockname.sin_addr.s_addr = inet_addr(ifaddr);*/ 
   
           memset(&sockname, 0, sizeof(struct sockaddr_storage));
           if(ipv6) {
                   struct sockaddr_in6 * saddr = (struct sockaddr_in6 *)&sockname;
                   saddr->sin6_family = AF_INET6;
                   saddr->sin6_port = htons(SSDP_PORT);
                   saddr->sin6_addr = in6addr_any;
                   sockname_len = sizeof(struct sockaddr_in6);
           } else {
                   struct sockaddr_in * saddr = (struct sockaddr_in *)&sockname;
                   saddr->sin_family = AF_INET;
                   saddr->sin_port = htons(SSDP_PORT);
                   /* NOTE : it seems it doesnt work when binding on the specific address */
                   /*saddr->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/
                   saddr->sin_addr.s_addr = htonl(INADDR_ANY);
                   /*saddr->sin_addr.s_addr = inet_addr(ifaddr);*/
                   sockname_len = sizeof(struct sockaddr_in);
           }
   
         if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j)) < 0)          if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j)) < 0)
         {          {
                 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, sizeof(struct sockaddr_in)) < 0)        if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0)
         {          {
                syslog(LOG_ERR, "bind(udp): %m");                syslog(LOG_ERR, "%s: bind(udp%s): %m",
                        "OpenAndConfSSDPReceiveSocket", ipv6 ? "6" : "");
                 close(s);                  close(s);
                 return -1;                  return -1;
    }        }
   
        i = n_lan_addr;#ifdef ENABLE_IPV6
        while(i>0)        if(ipv6)
         {          {
                i--;                AddMulticastMembershipIPv6(s);
                if(AddMulticastMembership(s, lan_addr[i].addr.s_addr) < 0)        }
         else
 #endif
         {
                 for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
                 {                  {
                        syslog(LOG_WARNING,                        if(AddMulticastMembership(s, lan_addr->addr.s_addr) < 0)
                               "Failed to add multicast membership for address %s",                         {
                               lan_addr[i].str );                                syslog(LOG_WARNING,
                                        "Failed to add multicast membership for interface %s",
                                        lan_addr->str ? lan_addr->str : "NULL");
                         }
                 }                  }
         }          }
   
Line 108  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 132  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 154  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;
        for(i=0; i<n_lan_addr; 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)
         {          {
                sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr[i].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 200  EXT: Line 316  EXT:
 /* not really an SSDP "announce" as it is the response  /* not really an SSDP "announce" as it is the response
  * to a SSDP "M-SEARCH" */   * to a SSDP "M-SEARCH" */
 static void  static void
SendSSDPAnnounce2(int s, struct sockaddr_in sockname,SendSSDPAnnounce2(int s, const struct sockaddr * addr,
                   const char * st, int st_len, const char * suffix,                    const char * st, int st_len, const char * suffix,
                   const char * host, unsigned short port)                    const char * host, unsigned short port)
 {  {
         int l, n;          int l, n;
         char buf[512];          char buf[512];
        /*         char addr_str[64];
         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 */
         l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"          l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"
                 "CACHE-CONTROL: max-age=120\r\n"                  "CACHE-CONTROL: max-age=120\r\n"
                 /*"DATE: ...\r\n"*/                  /*"DATE: ...\r\n"*/
Line 221  SendSSDPAnnounce2(int s, struct sockaddr_in sockname, Line 340  SendSSDPAnnounce2(int s, struct sockaddr_in sockname,
                 "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/\"; 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 */
                 "\r\n",                  "\r\n",
                 st_len, st, suffix,                  st_len, st, suffix,
                 uuidvalue, st_len, st, suffix,                  uuidvalue, st_len, st, suffix,
                host, (unsigned int)port);                host, (unsigned int)port,
                 upnp_bootid, upnp_bootid, upnp_configid);
         addrlen = (addr->sa_family == AF_INET6)
                   ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
         n = sendto(s, buf, l, 0,          n = sendto(s, buf, l, 0,
                   (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );                   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(sockname.sin_addr),        syslog(LOG_INFO, "SSDP Announce %d bytes to %s ST: %.*s",n,
                ntohs(sockname.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},
        "urn:schemas-upnp-org:service:Layer3Forwarding:",#ifdef ENABLE_L3F_SERVICE
        0        {"urn:schemas-upnp-org:service:Layer3Forwarding:", 1},
 #endif
 #ifdef ENABLE_6FC_SERVICE
         {"url:schemas-upnp-org:service:WANIPv6FirewallControl:", 1},
 #endif
         {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)
                                "NOTIFY * HTTP/1.1\r\n"                        ver_str[0] = '\0';
                                "HOST:%s:%d\r\n"                else
                                "Cache-Control:max-age=%u\r\n"                        snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version);
                                "Location:http://%s:%d" ROOTDESC_PATH"\r\n"                l = snprintf(bufr, sizeof(bufr),
                                /*"Server:miniupnpd/1.0 UPnP/1.0\r\n"*/                        "NOTIFY * HTTP/1.1\r\n"
                                "Server: " MINIUPNPD_SERVER_STRING "\r\n"                        "HOST: %s:%d\r\n"
                                "NT:%s%s\r\n"                        "CACHE-CONTROL: max-age=%u\r\n"
                                "USN:%s::%s%s\r\n"                        "lOCATION: http://%s:%d" ROOTDESC_PATH"\r\n"
                                "NTS:ssdp:alive\r\n"                        "SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
                                "\r\n",                        "NT: %s%s\r\n"
                                SSDP_MCAST_ADDR, SSDP_PORT,                        "USN: %s::%s%s\r\n"
                                lifetime,                        "NTS: ssdp:alive\r\n"
                                host, port,                        "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
                                known_service_types[i], (i==0?"":"1"),                        "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
                                uuidvalue, known_service_types[i], (i==0?"":"1") );                        "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
                if(l>=sizeof(bufr))                        "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
                         "\r\n",
                         ipv6 ? "[" LL_SSDP_MCAST_ADDR "]" : SSDP_MCAST_ADDR,
                         SSDP_PORT,
                         lifetime,
                         host, port,
                         known_service_types[i].s, ver_str,
                         uuidvalue, known_service_types[i].s, ver_str,
                         upnp_bootid, upnp_bootid, upnp_configid );
                 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 300  void Line 483  void
 SendSSDPNotifies2(int * sockets,  SendSSDPNotifies2(int * sockets,
                   unsigned short port,                    unsigned short port,
                   unsigned int lifetime)                    unsigned int lifetime)
 /*SendSSDPNotifies2(int * sockets, struct lan_addr_s * lan_addr, int n_lan_addr,  
                   unsigned short port,  
                   unsigned int lifetime)*/  
 {  {
         int i;          int i;
        for(i=0; i<n_lan_addr; 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)
         {          {
                SendSSDPNotifies(sockets[i], lan_addr[i].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 319  ProcessSSDPRequest(int s, unsigned short port) Line 509  ProcessSSDPRequest(int s, unsigned short port)
         int n;          int n;
         char bufr[1500];          char bufr[1500];
         socklen_t len_r;          socklen_t len_r;
   #ifdef ENABLE_IPV6
           struct sockaddr_storage sendername;
           len_r = sizeof(struct sockaddr_storage);
   #else
         struct sockaddr_in sendername;          struct sockaddr_in sendername;
         len_r = sizeof(struct sockaddr_in);          len_r = sizeof(struct sockaddr_in);
   #endif
   
         n = recvfrom(s, bufr, sizeof(bufr), 0,          n = recvfrom(s, bufr, sizeof(bufr), 0,
                      (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, sendername, n, port);        ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, port);
   
 }  }
   
void ProcessSSDPData(int s, char *bufr, struct sockaddr_in sendername, int n, unsigned short port) {void
 ProcessSSDPData(int s, const char *bufr, int n,
                 const struct sockaddr * sender, unsigned short port) {
         int i, l;          int i, l;
        int lan_addr_index = 0;        struct lan_addr_s * lan_addr = NULL;
        char * st = 0;        const char * st = NULL;
         int st_len = 0;          int st_len = 0;
           int st_ver = 0;
           char sender_str[64];
           char ver_str[4];
           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 */
           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 362  void ProcessSSDPData(int s, char *bufr, struct sockadd Line 584  void ProcessSSDPData(int s, char *bufr, struct sockadd
                                 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);*/
                         }                          }
                 }                  }
                /*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s:%d",                /*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
                   inet_ntoa(sendername.sin_addr),                   sender_str );*/
                   ntohs(sendername.sin_port) );*/ 
                 if(st && (st_len > 0))                  if(st && (st_len > 0))
                 {                  {
                         /* TODO : doesnt answer at once but wait for a random time */                          /* TODO : doesnt answer at once but wait for a random time */
                        syslog(LOG_INFO, "SSDP M-SEARCH from %s:%d ST: %.*s",                        syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s",
                           inet_ntoa(sendername.sin_addr),                               sender_str, st_len, st);
                           ntohs(sendername.sin_port), 
                                   st_len, st); 
                         /* find in which sub network the client is */                          /* find in which sub network the client is */
                        for(i = 0; i<n_lan_addr; i++)                        if(sender->sa_family == AF_INET)
                         {                          {
                                if( (sendername.sin_addr.s_addr & lan_addr[i].mask.s_addr)                                if (lan_addr == NULL)
                                   == (lan_addr[i].addr.s_addr & lan_addr[i].mask.s_addr)) 
                                 {                                  {
                                        lan_addr_index = i;                                        syslog(LOG_ERR, "Can't find in which sub network the client is");
                                        break;                                        return;
                                 }                                  }
                                   announced_host = lan_addr->str;
                         }                          }
   #ifdef ENABLE_IPV6
                           else
                           {
                                   /* 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;
   #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, sendername,                                        SendSSDPAnnounce2(s, sender,
                                                           st, st_len, "",                                                            st, st_len, "",
                                                          lan_addr[lan_addr_index].str, port);                                                          announced_host, port);
                                         break;                                          break;
                                 }                                  }
                         }                          }
Line 406  void ProcessSSDPData(int s, char *bufr, struct sockadd Line 672  void ProcessSSDPData(int s, char *bufr, struct sockadd
                         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)
                                        SendSSDPAnnounce2(s, sendername,                                                ver_str[0] = '\0';
                                                          known_service_types[i], l, i==0?"":"1",                                        else
                                                          lan_addr[lan_addr_index].str, port);                                                snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version);
                                         l = (int)strlen(known_service_types[i].s);
                                         SendSSDPAnnounce2(s, sender,
                                                           known_service_types[i].s, l, ver_str,
                                                           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);
                         if(l==st_len && (0 == memcmp(st, uuidvalue, l)))                          if(l==st_len && (0 == memcmp(st, uuidvalue, l)))
                         {                          {
                                 syslog(LOG_INFO, "ssdp:uuid found");                                  syslog(LOG_INFO, "ssdp:uuid found");
                                SendSSDPAnnounce2(s, sendername, st, st_len, "",                                SendSSDPAnnounce2(s, sender, st, st_len, "",
                                                  lan_addr[lan_addr_index].str, port);                                                  announced_host, port);
                         }                          }
                 }                  }
                 else                  else
                 {                  {
                        syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s:%d",                        syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s", sender_str);
                           inet_ntoa(sendername.sin_addr), ntohs(sendername.sin_port)); 
                 }                  }
         }          }
         else          else
         {          {
                syslog(LOG_NOTICE, "Unknown udp packet received from %s:%d",                syslog(LOG_NOTICE, "Unknown udp packet received from %s", sender_str);
                       inet_ntoa(sendername.sin_addr), ntohs(sendername.sin_port)); 
         }          }
 }  }
   
/* 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"
                         "\r\n",                                 "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
                         SSDP_MCAST_ADDR, SSDP_PORT,                                 "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
                                         known_service_types[i], (i==0?"":"1"),                                 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
                         uuidvalue, known_service_types[i], (i==0?"":"1"));                                 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
                  "\r\n",
                  ipv6 ? "[" LL_SSDP_MCAST_ADDR "]" : SSDP_MCAST_ADDR,
                              SSDP_PORT,
                                  known_service_types[i].s, ver_str,
                  uuidvalue, known_service_types[i].s, ver_str,
                  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 488  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 499  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 526  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.1  
changed lines
  Added in v.1.1.1.3


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