Annotation of embedaddon/miniupnpd/minissdp.c, revision 1.1.1.2

1.1.1.2 ! misho       1: /* $Id: minissdp.c,v 1.27 2011/05/23 12:39:41 nanard Exp $ */
1.1       misho       2: /* MiniUPnP project
                      3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
1.1.1.2 ! misho       4:  * (c) 2006-2011 Thomas Bernard
1.1       misho       5:  * This software is subject to the conditions detailed
                      6:  * in the LICENCE file provided within the distribution */
                      7: 
                      8: #include <stdio.h>
                      9: #include <string.h>
                     10: #include <unistd.h>
                     11: #include <sys/socket.h>
                     12: #include <sys/un.h>
                     13: #include <netinet/in.h>
                     14: #include <arpa/inet.h>
                     15: #include <syslog.h>
                     16: #include "config.h"
                     17: #include "upnpdescstrings.h"
                     18: #include "miniupnpdpath.h"
                     19: #include "upnphttp.h"
                     20: #include "upnpglobalvars.h"
                     21: #include "minissdp.h"
1.1.1.2 ! misho      22: #include "upnputils.h"
1.1       misho      23: #include "codelength.h"
                     24: 
                     25: /* SSDP ip/port */
                     26: #define SSDP_PORT (1900)
                     27: #define SSDP_MCAST_ADDR ("239.255.255.250")
1.1.1.2 ! misho      28: #define LL_SSDP_MCAST_ADDR ("FF02::C")
        !            29: #define SL_SSDP_MCAST_ADDR ("FF05::C")
1.1       misho      30: 
1.1.1.2 ! misho      31: /* AddMulticastMembership()
        !            32:  * param s             socket
        !            33:  * param ifaddr        ip v4 address
        !            34:  */
1.1       misho      35: static int
                     36: AddMulticastMembership(int s, in_addr_t ifaddr)
                     37: {
                     38:        struct ip_mreq imr;     /* Ip multicast membership */
                     39: 
                     40:     /* setting up imr structure */
                     41:     imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR);
                     42:     /*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/
                     43:     imr.imr_interface.s_addr = ifaddr; /*inet_addr(ifaddr);*/
                     44:        
                     45:        if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreq)) < 0)
                     46:        {
                     47:         syslog(LOG_ERR, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m");
                     48:                return -1;
                     49:     }
                     50: 
                     51:        return 0;
                     52: }
                     53: 
1.1.1.2 ! misho      54: /* AddMulticastMembershipIPv6()
        !            55:  * param s     socket (IPv6)
        !            56:  * To be improved to target specific network interfaces */
        !            57: #ifdef ENABLE_IPV6
        !            58: static int
        !            59: AddMulticastMembershipIPv6(int s)
        !            60: {
        !            61:        struct ipv6_mreq mr;
        !            62:        /*unsigned int ifindex;*/
        !            63: 
        !            64:        memset(&mr, 0, sizeof(mr));
        !            65:        inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
        !            66:        /*mr.ipv6mr_interface = ifindex;*/
        !            67:        mr.ipv6mr_interface = 0; /* 0 : all interfaces */
        !            68: #ifndef IPV6_ADD_MEMBERSHIP
        !            69: #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
        !            70: #endif
        !            71:        if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
        !            72:        {
        !            73:                syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
        !            74:                return -1;
        !            75:        }
        !            76:        inet_pton(AF_INET6, SL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
        !            77:        if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
        !            78:        {
        !            79:                syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
        !            80:                return -1;
        !            81:        }
        !            82:        return 0;
        !            83: }
        !            84: #endif
        !            85: 
1.1       misho      86: /* Open and configure the socket listening for 
1.1.1.2 ! misho      87:  * SSDP udp packets sent on 239.255.255.250 port 1900
        !            88:  * SSDP v6 udp packets sent on FF02::C, or FF05::C, port 1900 */
1.1       misho      89: int
1.1.1.2 ! misho      90: OpenAndConfSSDPReceiveSocket(int ipv6)
1.1       misho      91: {
                     92:        int s;
1.1.1.2 ! misho      93:        struct sockaddr_storage sockname;
        !            94:        socklen_t sockname_len;
        !            95:        struct lan_addr_s * lan_addr;
1.1       misho      96:        int j = 1;
1.1.1.2 ! misho      97: 
        !            98:        if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
1.1       misho      99:        {
                    100:                syslog(LOG_ERR, "socket(udp): %m");
                    101:                return -1;
1.1.1.2 ! misho     102:        }
        !           103: 
        !           104:        memset(&sockname, 0, sizeof(struct sockaddr_storage));
        !           105:        if(ipv6) {
        !           106:                struct sockaddr_in6 * saddr = (struct sockaddr_in6 *)&sockname;
        !           107:                saddr->sin6_family = AF_INET6;
        !           108:                saddr->sin6_port = htons(SSDP_PORT);
        !           109:                saddr->sin6_addr = in6addr_any;
        !           110:                sockname_len = sizeof(struct sockaddr_in6);
        !           111:        } else {
        !           112:                struct sockaddr_in * saddr = (struct sockaddr_in *)&sockname;
        !           113:                saddr->sin_family = AF_INET;
        !           114:                saddr->sin_port = htons(SSDP_PORT);
        !           115:                /* NOTE : it seems it doesnt work when binding on the specific address */
        !           116:                /*saddr->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/
        !           117:                saddr->sin_addr.s_addr = htonl(INADDR_ANY);
        !           118:                /*saddr->sin_addr.s_addr = inet_addr(ifaddr);*/
        !           119:                sockname_len = sizeof(struct sockaddr_in);
        !           120:        }
1.1       misho     121: 
                    122:        if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j)) < 0)
                    123:        {
                    124:                syslog(LOG_WARNING, "setsockopt(udp, SO_REUSEADDR): %m");
                    125:        }
                    126: 
                    127: 
1.1.1.2 ! misho     128:        if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0)
1.1       misho     129:        {
1.1.1.2 ! misho     130:                syslog(LOG_ERR, "bind(udp%s): %m", ipv6 ? "6" : "");
1.1       misho     131:                close(s);
                    132:                return -1;
1.1.1.2 ! misho     133:        }
1.1       misho     134: 
1.1.1.2 ! misho     135: #ifdef ENABLE_IPV6
        !           136:        if(ipv6)
        !           137:        {
        !           138:                AddMulticastMembershipIPv6(s);
        !           139:        }
        !           140:        else
        !           141: #endif
1.1       misho     142:        {
1.1.1.2 ! misho     143:                for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
1.1       misho     144:                {
1.1.1.2 ! misho     145:                        if(AddMulticastMembership(s, lan_addr->addr.s_addr) < 0)
        !           146:                        {
        !           147:                                syslog(LOG_WARNING,
        !           148:                                       "Failed to add multicast membership for interface %s", 
        !           149:                                       lan_addr->str);
        !           150:                        }
1.1       misho     151:                }
                    152:        }
                    153: 
                    154:        return s;
                    155: }
                    156: 
                    157: /* open the UDP socket used to send SSDP notifications to
                    158:  * the multicast group reserved for them */
                    159: static int
                    160: OpenAndConfSSDPNotifySocket(in_addr_t addr)
                    161: {
                    162:        int s;
                    163:        unsigned char loopchar = 0;
                    164:        int bcast = 1;
                    165:        struct in_addr mc_if;
                    166:        struct sockaddr_in sockname;
                    167:        
                    168:        if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
                    169:        {
                    170:                syslog(LOG_ERR, "socket(udp_notify): %m");
                    171:                return -1;
                    172:        }
                    173: 
                    174:        mc_if.s_addr = addr;    /*inet_addr(addr);*/
                    175: 
                    176:        if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopchar, sizeof(loopchar)) < 0)
                    177:        {
                    178:                syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_LOOP): %m");
                    179:                close(s);
                    180:                return -1;
                    181:        }
                    182: 
                    183:        if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *)&mc_if, sizeof(mc_if)) < 0)
                    184:        {
                    185:                syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_IF): %m");
                    186:                close(s);
                    187:                return -1;
                    188:        }
                    189:        
                    190:        if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast)) < 0)
                    191:        {
                    192:                syslog(LOG_ERR, "setsockopt(udp_notify, SO_BROADCAST): %m");
                    193:                close(s);
                    194:                return -1;
                    195:        }
                    196: 
                    197:        memset(&sockname, 0, sizeof(struct sockaddr_in));
                    198:     sockname.sin_family = AF_INET;
                    199:     sockname.sin_addr.s_addr = addr;   /*inet_addr(addr);*/
                    200: 
                    201:     if (bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0)
                    202:        {
                    203:                syslog(LOG_ERR, "bind(udp_notify): %m");
                    204:                close(s);
                    205:                return -1;
                    206:     }
                    207: 
                    208:        return s;
                    209: }
                    210: 
                    211: int
                    212: OpenAndConfSSDPNotifySockets(int * sockets)
                    213: /*OpenAndConfSSDPNotifySockets(int * sockets,
                    214:                              struct lan_addr_s * lan_addr, int n_lan_addr)*/
                    215: {
                    216:        int i, j;
1.1.1.2 ! misho     217:        struct lan_addr_s * lan_addr;
        !           218: 
        !           219:        for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
1.1       misho     220:        {
1.1.1.2 ! misho     221:                sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr->addr.s_addr);
1.1       misho     222:                if(sockets[i] < 0)
                    223:                {
                    224:                        for(j=0; j<i; j++)
                    225:                        {
                    226:                                close(sockets[j]);
                    227:                                sockets[j] = -1;
                    228:                        }
                    229:                        return -1;
                    230:                }
                    231:        }
                    232:        return 0;
                    233: }
                    234: 
                    235: /*
                    236:  * response from a LiveBox (Wanadoo)
                    237: HTTP/1.1 200 OK
                    238: CACHE-CONTROL: max-age=1800
                    239: DATE: Thu, 01 Jan 1970 04:03:23 GMT
                    240: EXT:
                    241: LOCATION: http://192.168.0.1:49152/gatedesc.xml
                    242: SERVER: Linux/2.4.17, UPnP/1.0, Intel SDK for UPnP devices /1.2
                    243: ST: upnp:rootdevice
                    244: USN: uuid:75802409-bccb-40e7-8e6c-fa095ecce13e::upnp:rootdevice
                    245: 
                    246:  * response from a Linksys 802.11b :
                    247: HTTP/1.1 200 OK
                    248: Cache-Control:max-age=120
                    249: Location:http://192.168.5.1:5678/rootDesc.xml
                    250: Server:NT/5.0 UPnP/1.0
                    251: ST:upnp:rootdevice
                    252: USN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777::upnp:rootdevice
                    253: EXT:
                    254:  */
                    255: 
                    256: /* not really an SSDP "announce" as it is the response
                    257:  * to a SSDP "M-SEARCH" */
                    258: static void
1.1.1.2 ! misho     259: SendSSDPAnnounce2(int s, const struct sockaddr * addr,
1.1       misho     260:                   const char * st, int st_len, const char * suffix,
                    261:                   const char * host, unsigned short port)
                    262: {
                    263:        int l, n;
                    264:        char buf[512];
1.1.1.2 ! misho     265:        socklen_t addrlen;
1.1       misho     266:        /* 
                    267:         * follow guideline from document "UPnP Device Architecture 1.0"
                    268:         * uppercase is recommended.
                    269:         * DATE: is recommended
                    270:         * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
                    271:         * - check what to put in the 'Cache-Control' header 
1.1.1.2 ! misho     272:         *
        !           273:         * have a look at the document "UPnP Device Architecture v1.1 */
1.1       misho     274:        l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"
                    275:                "CACHE-CONTROL: max-age=120\r\n"
                    276:                /*"DATE: ...\r\n"*/
                    277:                "ST: %.*s%s\r\n"
                    278:                "USN: %s::%.*s%s\r\n"
                    279:                "EXT:\r\n"
                    280:                "SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
                    281:                "LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
1.1.1.2 ! misho     282:                "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
        !           283:                "01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
        !           284:                "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
        !           285:                "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
1.1       misho     286:                "\r\n",
                    287:                st_len, st, suffix,
                    288:                uuidvalue, st_len, st, suffix,
1.1.1.2 ! misho     289:                host, (unsigned int)port,
        !           290:                upnp_bootid, upnp_bootid, upnp_configid);
        !           291:        addrlen = (addr->sa_family == AF_INET6)
        !           292:                  ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
1.1       misho     293:        n = sendto(s, buf, l, 0,
1.1.1.2 ! misho     294:                   addr, addrlen);
1.1       misho     295:        syslog(LOG_INFO, "SSDP Announce %d bytes to %s:%d ST: %.*s",n,
1.1.1.2 ! misho     296:                        inet_ntoa(((const struct sockaddr_in *)addr)->sin_addr),
        !           297:                ntohs(((const struct sockaddr_in *)addr)->sin_port),
1.1       misho     298:                l, buf);
                    299:        if(n < 0)
                    300:        {
                    301:                syslog(LOG_ERR, "sendto(udp): %m");
                    302:        }
                    303: }
                    304: 
                    305: static const char * const known_service_types[] =
                    306: {
                    307:        "upnp:rootdevice",
                    308:        "urn:schemas-upnp-org:device:InternetGatewayDevice:",
                    309:        "urn:schemas-upnp-org:device:WANConnectionDevice:",
                    310:        "urn:schemas-upnp-org:device:WANDevice:",
                    311:        "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:",
                    312:        "urn:schemas-upnp-org:service:WANIPConnection:",
                    313:        "urn:schemas-upnp-org:service:WANPPPConnection:",
1.1.1.2 ! misho     314: #ifdef ENABLE_L3F_SERVICE
1.1       misho     315:        "urn:schemas-upnp-org:service:Layer3Forwarding:",
1.1.1.2 ! misho     316: #endif
        !           317: #ifdef ENABLE_6FC_SERVICE
        !           318:        "url:schemas-upnp-org:service:WANIPv6FirewallControl:",
        !           319: #endif
1.1       misho     320:        0
                    321: };
                    322: 
                    323: static void
                    324: SendSSDPNotifies(int s, const char * host, unsigned short port,
                    325:                  unsigned int lifetime)
                    326: {
                    327:        struct sockaddr_in sockname;
                    328:        int l, n, i=0;
                    329:        char bufr[512];
                    330: 
                    331:        memset(&sockname, 0, sizeof(struct sockaddr_in));
                    332:        sockname.sin_family = AF_INET;
                    333:        sockname.sin_port = htons(SSDP_PORT);
                    334:        sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
                    335: 
                    336:        while(known_service_types[i])
                    337:        {
                    338:                l = snprintf(bufr, sizeof(bufr), 
1.1.1.2 ! misho     339:                        "NOTIFY * HTTP/1.1\r\n"
        !           340:                        "HOST: %s:%d\r\n"
        !           341:                        "CACHE-CONTROL: max-age=%u\r\n"
        !           342:                        "lOCATION: http://%s:%d" ROOTDESC_PATH"\r\n"
        !           343:                        "SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
        !           344:                        "NT: %s%s\r\n"
        !           345:                        "USN: %s::%s%s\r\n"
        !           346:                        "NTS: ssdp:alive\r\n"
        !           347:                        "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
        !           348:                        "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
        !           349:                        "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
        !           350:                        "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
        !           351:                        "\r\n",
        !           352:                        SSDP_MCAST_ADDR, SSDP_PORT,
        !           353:                        lifetime,
        !           354:                        host, port,
        !           355:                        known_service_types[i], (i==0?"":"1"),
        !           356:                        uuidvalue, known_service_types[i], (i==0?"":"1"),
        !           357:                        upnp_bootid, upnp_bootid, upnp_configid );
1.1       misho     358:                if(l>=sizeof(bufr))
                    359:                {
                    360:                        syslog(LOG_WARNING, "SendSSDPNotifies(): truncated output");
                    361:                        l = sizeof(bufr);
                    362:                }
                    363:                n = sendto(s, bufr, l, 0,
                    364:                        (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
                    365:                if(n < 0)
                    366:                {
                    367:                        syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s, host);
                    368:                }
                    369:                i++;
                    370:        }
                    371: }
                    372: 
                    373: void
                    374: SendSSDPNotifies2(int * sockets,
                    375:                   unsigned short port,
                    376:                   unsigned int lifetime)
                    377: {
                    378:        int i;
1.1.1.2 ! misho     379:        struct lan_addr_s * lan_addr;
        !           380:        for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
1.1       misho     381:        {
1.1.1.2 ! misho     382:                SendSSDPNotifies(sockets[i], lan_addr->str, port, lifetime);
1.1       misho     383:        }
                    384: }
                    385: 
                    386: /* ProcessSSDPRequest()
                    387:  * process SSDP M-SEARCH requests and responds to them */
                    388: void
                    389: ProcessSSDPRequest(int s, unsigned short port)
                    390: {
                    391:        int n;
                    392:        char bufr[1500];
                    393:        socklen_t len_r;
1.1.1.2 ! misho     394: #ifdef ENABLE_IPV6
        !           395:        struct sockaddr_storage sendername;
        !           396:        len_r = sizeof(struct sockaddr_storage);
        !           397: #else
1.1       misho     398:        struct sockaddr_in sendername;
                    399:        len_r = sizeof(struct sockaddr_in);
1.1.1.2 ! misho     400: #endif
1.1       misho     401: 
                    402:        n = recvfrom(s, bufr, sizeof(bufr), 0,
                    403:                     (struct sockaddr *)&sendername, &len_r);
                    404:        if(n < 0)
                    405:        {
                    406:                syslog(LOG_ERR, "recvfrom(udp): %m");
                    407:                return;
                    408:        }
1.1.1.2 ! misho     409:        ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, port);
1.1       misho     410: 
                    411: }
                    412: 
1.1.1.2 ! misho     413: void
        !           414: ProcessSSDPData(int s, const char *bufr, int n,
        !           415:                 const struct sockaddr * sender, unsigned short port) {
1.1       misho     416:        int i, l;
1.1.1.2 ! misho     417:        struct lan_addr_s * lan_addr = NULL;
        !           418:        const char * st = NULL;
1.1       misho     419:        int st_len = 0;
1.1.1.2 ! misho     420:        char sender_str[64];
        !           421:        const char * announced_host = NULL;
1.1       misho     422: 
1.1.1.2 ! misho     423:        /* get the string representation of the sender address */
        !           424:        sockaddr_to_string(sender, sender_str, sizeof(sender_str));
1.1       misho     425: 
                    426:        if(memcmp(bufr, "NOTIFY", 6) == 0)
                    427:        {
                    428:                /* ignore NOTIFY packets. We could log the sender and device type */
                    429:                return;
                    430:        }
                    431:        else if(memcmp(bufr, "M-SEARCH", 8) == 0)
                    432:        {
                    433:                i = 0;
                    434:                while(i < n)
                    435:                {
                    436:                        while((i < n - 1) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
                    437:                                i++;
                    438:                        i += 2;
                    439:                        if((i < n - 3) && (strncasecmp(bufr+i, "st:", 3) == 0))
                    440:                        {
                    441:                                st = bufr+i+3;
                    442:                                st_len = 0;
                    443:                                while((*st == ' ' || *st == '\t') && (st < bufr + n))
                    444:                                        st++;
                    445:                                while(st[st_len]!='\r' && st[st_len]!='\n'
                    446:                                     && (st + st_len < bufr + n))
                    447:                                        st_len++;
                    448:                                /*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
                    449:                                /*j = 0;*/
                    450:                                /*while(bufr[i+j]!='\r') j++;*/
                    451:                                /*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
                    452:                        }
                    453:                }
1.1.1.2 ! misho     454:                /*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
        !           455:                   sender_str );*/
1.1       misho     456:                if(st && (st_len > 0))
                    457:                {
                    458:                        /* TODO : doesnt answer at once but wait for a random time */
1.1.1.2 ! misho     459:                        syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s",
        !           460:                               sender_str, st_len, st);
1.1       misho     461:                        /* find in which sub network the client is */
1.1.1.2 ! misho     462:                        if(sender->sa_family == AF_INET)
1.1       misho     463:                        {
1.1.1.2 ! misho     464:                                for(lan_addr = lan_addrs.lh_first;
        !           465:                                    lan_addr != NULL;
        !           466:                                    lan_addr = lan_addr->list.le_next)
1.1       misho     467:                                {
1.1.1.2 ! misho     468:                                        if( (((const struct sockaddr_in *)sender)->sin_addr.s_addr & lan_addr->mask.s_addr)
        !           469:                                   == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
        !           470:                                                break;
        !           471:                                }
        !           472:                                if (lan_addr == NULL)
        !           473:                                {
        !           474:                                        syslog(LOG_ERR, "Can't find in which sub network the client is");
        !           475:                                        return;
1.1       misho     476:                                }
1.1.1.2 ! misho     477:                                announced_host = lan_addr->str;
        !           478:                        }
        !           479: #ifdef ENABLE_IPV6
        !           480:                        else
        !           481:                        {
        !           482:                                /* IPv6 address with brackets */
        !           483:                                announced_host = ipv6_addr_for_http_with_brackets;
1.1       misho     484:                        }
1.1.1.2 ! misho     485: #endif
1.1       misho     486:                        /* Responds to request with a device as ST header */
                    487:                        for(i = 0; known_service_types[i]; i++)
                    488:                        {
                    489:                                l = (int)strlen(known_service_types[i]);
                    490:                                if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
                    491:                                {
                    492:                                        syslog(LOG_INFO, "Single search found");
1.1.1.2 ! misho     493:                                        SendSSDPAnnounce2(s, sender,
1.1       misho     494:                                                          st, st_len, "",
1.1.1.2 ! misho     495:                                                          announced_host, port);
1.1       misho     496:                                        break;
                    497:                                }
                    498:                        }
                    499:                        /* Responds to request with ST: ssdp:all */
                    500:                        /* strlen("ssdp:all") == 8 */
                    501:                        if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
                    502:                        {
                    503:                                syslog(LOG_INFO, "ssdp:all found");
                    504:                                for(i=0; known_service_types[i]; i++)
                    505:                                {
                    506:                                        l = (int)strlen(known_service_types[i]);
1.1.1.2 ! misho     507:                                        SendSSDPAnnounce2(s, sender,
1.1       misho     508:                                                          known_service_types[i], l, i==0?"":"1",
1.1.1.2 ! misho     509:                                                          announced_host, port);
1.1       misho     510:                                }
                    511:                        }
                    512:                        /* responds to request by UUID value */
                    513:                        l = (int)strlen(uuidvalue);
                    514:                        if(l==st_len && (0 == memcmp(st, uuidvalue, l)))
                    515:                        {
                    516:                                syslog(LOG_INFO, "ssdp:uuid found");
1.1.1.2 ! misho     517:                                SendSSDPAnnounce2(s, sender, st, st_len, "",
        !           518:                                                  announced_host, port);
1.1       misho     519:                        }
                    520:                }
                    521:                else
                    522:                {
1.1.1.2 ! misho     523:                        syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s", sender_str);
1.1       misho     524:                }
                    525:        }
                    526:        else
                    527:        {
1.1.1.2 ! misho     528:                syslog(LOG_NOTICE, "Unknown udp packet received from %s", sender_str);
1.1       misho     529:        }
                    530: }
                    531: 
                    532: /* This will broadcast ssdp:byebye notifications to inform 
                    533:  * the network that UPnP is going down. */
                    534: int
                    535: SendSSDPGoodbye(int * sockets, int n_sockets)
                    536: {
                    537:        struct sockaddr_in sockname;
                    538:        int n, l;
                    539:        int i, j;
                    540:        char bufr[512];
                    541: 
                    542:     memset(&sockname, 0, sizeof(struct sockaddr_in));
                    543:     sockname.sin_family = AF_INET;
                    544:     sockname.sin_port = htons(SSDP_PORT);
                    545:     sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
                    546: 
                    547:        for(j=0; j<n_sockets; j++)
                    548:        {
                    549:            for(i=0; known_service_types[i]; i++)
                    550:            {
                    551:                l = snprintf(bufr, sizeof(bufr),
1.1.1.2 ! misho     552:                  "NOTIFY * HTTP/1.1\r\n"
        !           553:                  "HOST: %s:%d\r\n"
        !           554:                  "NT: %s%s\r\n"
        !           555:                  "USN: %s::%s%s\r\n"
        !           556:                  "NTS: ssdp:byebye\r\n"
        !           557:                                 "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
        !           558:                                 "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
        !           559:                                 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
        !           560:                                 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
        !           561:                  "\r\n",
        !           562:                  SSDP_MCAST_ADDR, SSDP_PORT,
        !           563:                                 known_service_types[i], (i==0?"":"1"),
        !           564:                  uuidvalue, known_service_types[i], (i==0?"":"1"),
        !           565:                  upnp_bootid, upnp_bootid, upnp_configid);
1.1       misho     566:                n = sendto(sockets[j], bufr, l, 0,
                    567:                           (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
                    568:                        if(n < 0)
                    569:                        {
                    570:                                syslog(LOG_ERR, "SendSSDPGoodbye: sendto(udp_shutdown=%d): %m",
                    571:                                       sockets[j]);
                    572:                                return -1;
                    573:                        }
                    574:        }
                    575:        }
                    576:        return 0;
                    577: }
                    578: 
                    579: /* SubmitServicesToMiniSSDPD() :
                    580:  * register services offered by MiniUPnPd to a running instance of
                    581:  * MiniSSDPd */
                    582: int
                    583: SubmitServicesToMiniSSDPD(const char * host, unsigned short port) {
                    584:        struct sockaddr_un addr;
                    585:        int s;
                    586:        unsigned char buffer[2048];
                    587:        char strbuf[256];
                    588:        unsigned char * p;
                    589:        int i, l;
                    590: 
                    591:        s = socket(AF_UNIX, SOCK_STREAM, 0);
                    592:        if(s < 0) {
                    593:                syslog(LOG_ERR, "socket(unix): %m");
                    594:                return -1;
                    595:        }
                    596:        addr.sun_family = AF_UNIX;
                    597:        strncpy(addr.sun_path, minissdpdsocketpath, sizeof(addr.sun_path));
                    598:        if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
                    599:                syslog(LOG_ERR, "connect(\"%s\"): %m", minissdpdsocketpath);
                    600:                return -1;
                    601:        }
                    602:        for(i = 0; known_service_types[i]; i++) {
                    603:                buffer[0] = 4;
                    604:                p = buffer + 1;
                    605:                l = (int)strlen(known_service_types[i]);
                    606:                if(i > 0)
                    607:                        l++;
                    608:                CODELENGTH(l, p);
                    609:                memcpy(p, known_service_types[i], l);
                    610:                if(i > 0)
                    611:                        p[l-1] = '1';
                    612:                p += l;
                    613:                l = snprintf(strbuf, sizeof(strbuf), "%s::%s%s", 
                    614:                             uuidvalue, known_service_types[i], (i==0)?"":"1");
                    615:                CODELENGTH(l, p);
                    616:                memcpy(p, strbuf, l);
                    617:                p += l;
                    618:                l = (int)strlen(MINIUPNPD_SERVER_STRING);
                    619:                CODELENGTH(l, p);
                    620:                memcpy(p, MINIUPNPD_SERVER_STRING, l);
                    621:                p += l;
                    622:                l = snprintf(strbuf, sizeof(strbuf), "http://%s:%u" ROOTDESC_PATH,
                    623:                             host, (unsigned int)port);
                    624:                CODELENGTH(l, p);
                    625:                memcpy(p, strbuf, l);
                    626:                p += l;
                    627:                if(write(s, buffer, p - buffer) < 0) {
                    628:                        syslog(LOG_ERR, "write(): %m");
                    629:                        return -1;
                    630:                }
                    631:        }
                    632:        close(s);
                    633:        return 0;
                    634: }
                    635: 

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