Annotation of embedaddon/miniupnpd/minissdpd/minissdpd.c, revision 1.1

1.1     ! misho       1: /* $Id: minissdpd.c,v 1.61 2021/11/04 23:27:28 nanard Exp $ */
        !             2: /* vim: tabstop=4 shiftwidth=4 noexpandtab
        !             3:  * MiniUPnP project
        !             4:  * (c) 2007-2022 Thomas Bernard
        !             5:  * website : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
        !             6:  * This software is subject to the conditions detailed
        !             7:  * in the LICENCE file provided within the distribution */
        !             8: 
        !             9: #include "config.h"
        !            10: 
        !            11: #include <stdlib.h>
        !            12: #include <stdio.h>
        !            13: #include <string.h>
        !            14: #include <signal.h>
        !            15: #include <errno.h>
        !            16: #include <sys/time.h>
        !            17: #include <sys/types.h>
        !            18: #include <sys/socket.h>
        !            19: #include <unistd.h>
        !            20: #include <netinet/in.h>
        !            21: #include <arpa/inet.h>
        !            22: #include <syslog.h>
        !            23: #include <ctype.h>
        !            24: #include <time.h>
        !            25: #include <sys/queue.h>
        !            26: /* for chmod : */
        !            27: #include <sys/stat.h>
        !            28: /* unix sockets */
        !            29: #include <sys/un.h>
        !            30: /* for getpwnam() and getgrnam() */
        !            31: #if 0
        !            32: #include <pwd.h>
        !            33: #include <grp.h>
        !            34: #endif
        !            35: 
        !            36: /* LOG_PERROR does not exist on Solaris */
        !            37: #ifndef LOG_PERROR
        !            38: #define LOG_PERROR 0
        !            39: #endif /* LOG_PERROR */
        !            40: 
        !            41: #include "getifaddr.h"
        !            42: #include "upnputils.h"
        !            43: #include "openssdpsocket.h"
        !            44: #include "daemonize.h"
        !            45: #include "codelength.h"
        !            46: #include "ifacewatch.h"
        !            47: #include "minissdpdtypes.h"
        !            48: #include "asyncsendto.h"
        !            49: 
        !            50: #define SET_MAX(max, x)    if((x) > (max)) (max) = (x)
        !            51: #ifndef MIN
        !            52: #define MIN(x,y) (((x)<(y))?(x):(y))
        !            53: #endif
        !            54: 
        !            55: /* current request management structure */
        !            56: struct reqelem {
        !            57:    int socket;
        !            58:    int is_notify;  /* has subscribed to notifications */
        !            59:    LIST_ENTRY(reqelem) entries;
        !            60:    unsigned char * output_buffer;
        !            61:    int output_buffer_offset;
        !            62:    int output_buffer_len;
        !            63: };
        !            64: 
        !            65: /* device data structures */
        !            66: struct header {
        !            67:    const char * p; /* string pointer */
        !            68:    int l;          /* string length */
        !            69: };
        !            70: 
        !            71: #define HEADER_NT  0
        !            72: #define HEADER_USN 1
        !            73: #define HEADER_LOCATION    2
        !            74: 
        !            75: struct device {
        !            76:    struct device * next;
        !            77:    time_t t;                 /* validity time */
        !            78:    struct header headers[3]; /* NT, USN and LOCATION headers */
        !            79:    char data[];
        !            80: };
        !            81: 
        !            82: /* Services stored for answering to M-SEARCH */
        !            83: struct service {
        !            84:    char * st;  /* Service type */
        !            85:    char * usn; /* Unique identifier */
        !            86:    char * server;  /* Server string */
        !            87:    char * location;    /* URL */
        !            88:    LIST_ENTRY(service) entries;
        !            89: };
        !            90: LIST_HEAD(servicehead, service) servicelisthead;
        !            91: 
        !            92: #define NTS_SSDP_ALIVE 1
        !            93: #define NTS_SSDP_BYEBYE    2
        !            94: #define NTS_SSDP_UPDATE    3
        !            95: 
        !            96: /* request types */
        !            97: enum request_type {
        !            98:    MINISSDPD_GET_VERSION = 0,
        !            99:    MINISSDPD_SEARCH_TYPE = 1,
        !           100:    MINISSDPD_SEARCH_USN = 2,
        !           101:    MINISSDPD_SEARCH_ALL = 3,
        !           102:    MINISSDPD_SUBMIT = 4,
        !           103:    MINISSDPD_NOTIF = 5
        !           104: };
        !           105: 
        !           106: /* discovered device list kept in memory */
        !           107: struct device * devlist = 0;
        !           108: 
        !           109: /* bootid and configid */
        !           110: unsigned int upnp_bootid = 1;
        !           111: unsigned int upnp_configid = 1337;
        !           112: 
        !           113: /* LAN interfaces/addresses */
        !           114: struct lan_addr_list lan_addrs;
        !           115: 
        !           116: /* connected clients */
        !           117: LIST_HEAD(reqstructhead, reqelem) reqlisthead;
        !           118: 
        !           119: /* functions prototypes */
        !           120: 
        !           121: #define NOTIF_NEW    1
        !           122: #define NOTIF_UPDATE 2
        !           123: #define NOTIF_REMOVE 3
        !           124: static void
        !           125: sendNotifications(int notif_type, const struct device * dev, const struct service * serv);
        !           126: 
        !           127: /* functions */
        !           128: 
        !           129: /* parselanaddr()
        !           130:  * parse address with mask
        !           131:  * ex: 192.168.1.1/24 or 192.168.1.1/255.255.255.0
        !           132:  *
        !           133:  * Can also use the interface name (ie eth0)
        !           134:  *
        !           135:  * return value :
        !           136:  *    0 : ok
        !           137:  *   -1 : error */
        !           138: static int
        !           139: parselanaddr(struct lan_addr_s * lan_addr, const char * str)
        !           140: {
        !           141:    const char * p;
        !           142:    int n;
        !           143:    char tmp[16];
        !           144: 
        !           145:    memset(lan_addr, 0, sizeof(struct lan_addr_s));
        !           146:    p = str;
        !           147:    while(*p && *p != '/' && !isspace(*p))
        !           148:        p++;
        !           149:    n = p - str;
        !           150:    if(!isdigit(str[0]) && n < (int)sizeof(lan_addr->ifname)) {
        !           151:        /* not starting with a digit : suppose it is an interface name */
        !           152:        memcpy(lan_addr->ifname, str, n);
        !           153:        lan_addr->ifname[n] = '\0';
        !           154:        if(getifaddr(lan_addr->ifname, lan_addr->str, sizeof(lan_addr->str),
        !           155:                     &lan_addr->addr, &lan_addr->mask) < 0)
        !           156:            goto parselan_error;
        !           157:        /*printf("%s => %s\n", lan_addr->ifname, lan_addr->str);*/
        !           158:    } else {
        !           159:        if(n>15)
        !           160:            goto parselan_error;
        !           161:        memcpy(lan_addr->str, str, n);
        !           162:        lan_addr->str[n] = '\0';
        !           163:        if(!inet_aton(lan_addr->str, &lan_addr->addr))
        !           164:            goto parselan_error;
        !           165:    }
        !           166:    if(*p == '/') {
        !           167:        const char * q = ++p;
        !           168:        while(*p && isdigit(*p))
        !           169:            p++;
        !           170:        if(*p=='.') {
        !           171:            /* parse mask in /255.255.255.0 format */
        !           172:            while(*p && (*p=='.' || isdigit(*p)))
        !           173:                p++;
        !           174:            n = p - q;
        !           175:            if(n>15)
        !           176:                goto parselan_error;
        !           177:            memcpy(tmp, q, n);
        !           178:            tmp[n] = '\0';
        !           179:            if(!inet_aton(tmp, &lan_addr->mask))
        !           180:                goto parselan_error;
        !           181:        } else {
        !           182:            /* it is a /24 format */
        !           183:            int nbits = atoi(q);
        !           184:            if(nbits > 32 || nbits < 0)
        !           185:                goto parselan_error;
        !           186:            lan_addr->mask.s_addr = htonl(nbits ? (0xffffffffu << (32 - nbits)) : 0);
        !           187:        }
        !           188:    } else if(lan_addr->mask.s_addr == 0) {
        !           189:        /* by default, networks are /24 */
        !           190:        lan_addr->mask.s_addr = htonl(0xffffff00u);
        !           191:    }
        !           192: #ifdef ENABLE_IPV6
        !           193:    if(lan_addr->ifname[0] != '\0') {
        !           194:        lan_addr->index = if_nametoindex(lan_addr->ifname);
        !           195:        if(lan_addr->index == 0)
        !           196:            fprintf(stderr, "Cannot get index for network interface %s\n",
        !           197:                    lan_addr->ifname);
        !           198:    } else {
        !           199:        fprintf(stderr,
        !           200:                "Error: please specify LAN network interface by name instead of IPv4 address : %s\n",
        !           201:                str);
        !           202:        return -1;
        !           203:    }
        !           204: #endif /* ENABLE_IPV6 */
        !           205:    return 0;
        !           206: parselan_error:
        !           207:    fprintf(stderr, "Error parsing address/mask (or interface name) : %s\n",
        !           208:            str);
        !           209:    return -1;
        !           210: }
        !           211: 
        !           212: static int
        !           213: write_buffer(struct reqelem * req)
        !           214: {
        !           215:    if(req->output_buffer && req->output_buffer_len > 0) {
        !           216:        int n = write(req->socket,
        !           217:                      req->output_buffer + req->output_buffer_offset,
        !           218:                      req->output_buffer_len);
        !           219:        if(n >= 0) {
        !           220:            req->output_buffer_offset += n;
        !           221:            req->output_buffer_len -= n;
        !           222:        } else if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
        !           223:            return 0;
        !           224:        }
        !           225:        return n;
        !           226:    } else {
        !           227:        return 0;
        !           228:    }
        !           229: }
        !           230: 
        !           231: static int
        !           232: add_to_buffer(struct reqelem * req, const unsigned char * data, int len)
        !           233: {
        !           234:    unsigned char * tmp;
        !           235:    if(req->output_buffer_offset > 0) {
        !           236:        memmove(req->output_buffer, req->output_buffer + req->output_buffer_offset, req->output_buffer_len);
        !           237:        req->output_buffer_offset = 0;
        !           238:    }
        !           239:    tmp = realloc(req->output_buffer, req->output_buffer_len + len);
        !           240:    if(tmp == NULL) {
        !           241:        syslog(LOG_ERR, "%s: failed to allocate %d bytes",
        !           242:               __func__, req->output_buffer_len + len);
        !           243:        return -1;
        !           244:    }
        !           245:    req->output_buffer = tmp;
        !           246:    memcpy(req->output_buffer + req->output_buffer_len, data, len);
        !           247:    req->output_buffer_len += len;
        !           248:    return len;
        !           249: }
        !           250: 
        !           251: static int
        !           252: write_or_buffer(struct reqelem * req, const unsigned char * data, int len)
        !           253: {
        !           254:    if(write_buffer(req) < 0)
        !           255:        return -1;
        !           256:    if(req->output_buffer && req->output_buffer_len > 0) {
        !           257:        return add_to_buffer(req, data, len);
        !           258:    } else {
        !           259:        int n = write(req->socket, data, len);
        !           260:        if(n == len)
        !           261:            return len;
        !           262:        if(n < 0) {
        !           263:            if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
        !           264:                n = add_to_buffer(req, data, len);
        !           265:                if(n < 0) return n;
        !           266:            } else {
        !           267:                return n;
        !           268:            }
        !           269:        } else {
        !           270:            n = add_to_buffer(req, data + n, len - n);
        !           271:            if(n < 0) return n;
        !           272:        }
        !           273:    }
        !           274:    return len;
        !           275: }
        !           276: 
        !           277: static const char *
        !           278: nts_to_str(int nts)
        !           279: {
        !           280:    switch(nts)
        !           281:    {
        !           282:    case NTS_SSDP_ALIVE:
        !           283:        return "ssdp:alive";
        !           284:    case NTS_SSDP_BYEBYE:
        !           285:        return "ssdp:byebye";
        !           286:    case NTS_SSDP_UPDATE:
        !           287:        return "ssdp:update";
        !           288:    }
        !           289:    return "unknown";
        !           290: }
        !           291: 
        !           292: /* updateDevice() :
        !           293:  * adds or updates the device to the list.
        !           294:  * return value :
        !           295:  *   0 : the device was updated (or nothing done)
        !           296:  *   1 : the device was new    */
        !           297: static int
        !           298: updateDevice(const struct header * headers, time_t t)
        !           299: {
        !           300:    struct device ** pp = &devlist;
        !           301:    struct device * p = *pp;    /* = devlist; */
        !           302:    while(p)
        !           303:    {
        !           304:        if(  p->headers[HEADER_NT].l == headers[HEADER_NT].l
        !           305:          && (0==memcmp(p->headers[HEADER_NT].p, headers[HEADER_NT].p, headers[HEADER_NT].l))
        !           306:          && p->headers[HEADER_USN].l == headers[HEADER_USN].l
        !           307:          && (0==memcmp(p->headers[HEADER_USN].p, headers[HEADER_USN].p, headers[HEADER_USN].l)) )
        !           308:        {
        !           309:            /*printf("found! %d\n", (int)(t - p->t));*/
        !           310:            syslog(LOG_DEBUG, "device updated : %.*s", headers[HEADER_USN].l, headers[HEADER_USN].p);
        !           311:            p->t = t;
        !           312:            /* update Location ! */
        !           313:            if(headers[HEADER_LOCATION].l > p->headers[HEADER_LOCATION].l)
        !           314:            {
        !           315:                struct device * tmp;
        !           316:                tmp = realloc(p, sizeof(struct device)
        !           317:                    + headers[0].l+headers[1].l+headers[2].l);
        !           318:                if(!tmp)    /* allocation error */
        !           319:                {
        !           320:                    syslog(LOG_ERR, "updateDevice() : memory allocation error");
        !           321:                    *pp = p->next;  /* remove "p" from the list */
        !           322:                    free(p);
        !           323:                    return 0;
        !           324:                }
        !           325:                p = tmp;
        !           326:                *pp = p;
        !           327:            }
        !           328:            memcpy(p->data + p->headers[0].l + p->headers[1].l,
        !           329:                   headers[2].p, headers[2].l);
        !           330:            /* TODO : check p->headers[HEADER_LOCATION].l */
        !           331:            return 0;
        !           332:        }
        !           333:        pp = &p->next;
        !           334:        p = *pp;    /* p = p->next; */
        !           335:    }
        !           336:    syslog(LOG_INFO, "new device discovered : %.*s",
        !           337:           headers[HEADER_USN].l, headers[HEADER_USN].p);
        !           338:    /* add */
        !           339:    {
        !           340:        char * pc;
        !           341:        int i;
        !           342:        p = malloc(  sizeof(struct device)
        !           343:                   + headers[0].l+headers[1].l+headers[2].l );
        !           344:        if(!p) {
        !           345:            syslog(LOG_ERR, "updateDevice(): cannot allocate memory");
        !           346:            return -1;
        !           347:        }
        !           348:        p->next = devlist;
        !           349:        p->t = t;
        !           350:        pc = p->data;
        !           351:        for(i = 0; i < 3; i++)
        !           352:        {
        !           353:            p->headers[i].p = pc;
        !           354:            p->headers[i].l = headers[i].l;
        !           355:            memcpy(pc, headers[i].p, headers[i].l);
        !           356:            pc += headers[i].l;
        !           357:        }
        !           358:        devlist = p;
        !           359:        sendNotifications(NOTIF_NEW, p, NULL);
        !           360:    }
        !           361:    return 1;
        !           362: }
        !           363: 
        !           364: /* removeDevice() :
        !           365:  * remove a device from the list
        !           366:  * return value :
        !           367:  *    0 : no device removed
        !           368:  *   -1 : device removed */
        !           369: static int
        !           370: removeDevice(const struct header * headers)
        !           371: {
        !           372:    struct device ** pp = &devlist;
        !           373:    struct device * p = *pp;    /* = devlist */
        !           374:    while(p)
        !           375:    {
        !           376:        if(  p->headers[HEADER_NT].l == headers[HEADER_NT].l
        !           377:          && (0==memcmp(p->headers[HEADER_NT].p, headers[HEADER_NT].p, headers[HEADER_NT].l))
        !           378:          && p->headers[HEADER_USN].l == headers[HEADER_USN].l
        !           379:          && (0==memcmp(p->headers[HEADER_USN].p, headers[HEADER_USN].p, headers[HEADER_USN].l)) )
        !           380:        {
        !           381:            syslog(LOG_INFO, "remove device : %.*s", headers[HEADER_USN].l, headers[HEADER_USN].p);
        !           382:            sendNotifications(NOTIF_REMOVE, p, NULL);
        !           383:            *pp = p->next;
        !           384:            free(p);
        !           385:            return -1;
        !           386:        }
        !           387:        pp = &p->next;
        !           388:        p = *pp;    /* p = p->next; */
        !           389:    }
        !           390:    syslog(LOG_WARNING, "device not found for removing : %.*s", headers[HEADER_USN].l, headers[HEADER_USN].p);
        !           391:    return 0;
        !           392: }
        !           393: 
        !           394: /* sent notifications to client having subscribed */
        !           395: static void
        !           396: sendNotifications(int notif_type, const struct device * dev, const struct service * serv)
        !           397: {
        !           398:    struct reqelem * req;
        !           399:    unsigned int m;
        !           400:    unsigned char rbuf[RESPONSE_BUFFER_SIZE];
        !           401:    unsigned char * rp;
        !           402: 
        !           403:    for(req = reqlisthead.lh_first; req; req = req->entries.le_next) {
        !           404:        if(!req->is_notify) continue;
        !           405:        rbuf[0] = '\xff'; /* special code for notifications */
        !           406:        rbuf[1] = (unsigned char)notif_type;
        !           407:        rbuf[2] = 0;
        !           408:        rp = rbuf + 3;
        !           409:        if(dev) {
        !           410:            /* response :
        !           411:             * 1 - Location
        !           412:             * 2 - NT (device/service type)
        !           413:             * 3 - usn */
        !           414:            m = dev->headers[HEADER_LOCATION].l;
        !           415:            CODELENGTH(m, rp);
        !           416:            memcpy(rp, dev->headers[HEADER_LOCATION].p, dev->headers[HEADER_LOCATION].l);
        !           417:            rp += dev->headers[HEADER_LOCATION].l;
        !           418:            m = dev->headers[HEADER_NT].l;
        !           419:            CODELENGTH(m, rp);
        !           420:            memcpy(rp, dev->headers[HEADER_NT].p, dev->headers[HEADER_NT].l);
        !           421:            rp += dev->headers[HEADER_NT].l;
        !           422:            m = dev->headers[HEADER_USN].l;
        !           423:            CODELENGTH(m, rp);
        !           424:            memcpy(rp, dev->headers[HEADER_USN].p, dev->headers[HEADER_USN].l);
        !           425:            rp += dev->headers[HEADER_USN].l;
        !           426:            rbuf[2]++;
        !           427:        }
        !           428:        if(serv) {
        !           429:            /* response :
        !           430:             * 1 - Location
        !           431:             * 2 - NT (device/service type)
        !           432:             * 3 - usn */
        !           433:            m = strlen(serv->location);
        !           434:            CODELENGTH(m, rp);
        !           435:            memcpy(rp, serv->location, m);
        !           436:            rp += m;
        !           437:            m = strlen(serv->st);
        !           438:            CODELENGTH(m, rp);
        !           439:            memcpy(rp, serv->st, m);
        !           440:            rp += m;
        !           441:            m = strlen(serv->usn);
        !           442:            CODELENGTH(m, rp);
        !           443:            memcpy(rp, serv->usn, m);
        !           444:            rp += m;
        !           445:            rbuf[2]++;
        !           446:        }
        !           447:        if(rbuf[2] > 0) {
        !           448:            if(write_or_buffer(req, rbuf, rp - rbuf) < 0) {
        !           449:                syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
        !           450:                /*goto error;*/
        !           451:            }
        !           452:        }
        !           453:    }
        !           454: }
        !           455: 
        !           456: /* SendSSDPMSEARCHResponse() :
        !           457:  * build and send response to M-SEARCH SSDP packets. */
        !           458: static void
        !           459: SendSSDPMSEARCHResponse(int s, const struct sockaddr * sockname,
        !           460:                         const char * st, size_t st_len, const char * usn,
        !           461:                         const char * server, const char * location)
        !           462: {
        !           463:    int l, n;
        !           464:    char buf[1024];
        !           465:    socklen_t sockname_len;
        !           466:    /*
        !           467:     * follow guideline from document "UPnP Device Architecture 1.0"
        !           468:     * uppercase is recommended.
        !           469:     * DATE: is recommended
        !           470:     * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
        !           471:     * - check what to put in the 'Cache-Control' header
        !           472:     *
        !           473:     * have a look at the document "UPnP Device Architecture v1.1 */
        !           474:    l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"
        !           475:        "CACHE-CONTROL: max-age=120\r\n"
        !           476:        /*"DATE: ...\r\n"*/
        !           477:        "ST: %.*s\r\n"
        !           478:        "USN: %s\r\n"
        !           479:        "EXT:\r\n"
        !           480:        "SERVER: %s\r\n"
        !           481:        "LOCATION: %s\r\n"
        !           482:        "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
        !           483:        "01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
        !           484:        "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
        !           485:        "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
        !           486:        "\r\n",
        !           487:        (int)st_len, st, usn,
        !           488:        server, location,
        !           489:        upnp_bootid, upnp_bootid, upnp_configid);
        !           490: #ifdef ENABLE_IPV6
        !           491:    sockname_len = (sockname->sa_family == PF_INET6)
        !           492:                 ? sizeof(struct sockaddr_in6)
        !           493:                 : sizeof(struct sockaddr_in);
        !           494: #else  /* ENABLE_IPV6 */
        !           495:    sockname_len = sizeof(struct sockaddr_in);
        !           496: #endif /* ENABLE_IPV6 */
        !           497:    n = sendto_or_schedule(s, buf, l, 0, sockname, sockname_len);
        !           498:    if(n < 0) {
        !           499:        syslog(LOG_ERR, "%s: sendto(udp): %m", __func__);
        !           500:    }
        !           501: }
        !           502: 
        !           503: /* Process M-SEARCH requests */
        !           504: static void
        !           505: processMSEARCH(int s, const char * st, size_t st_len,
        !           506:                const struct sockaddr * addr)
        !           507: {
        !           508:    struct service * serv;
        !           509: #ifdef ENABLE_IPV6
        !           510:    char buf[64];
        !           511: #endif /* ENABLE_IPV6 */
        !           512: 
        !           513:    if(!st || st_len==0)
        !           514:        return;
        !           515: #ifdef ENABLE_IPV6
        !           516:    sockaddr_to_string(addr, buf, sizeof(buf));
        !           517:    syslog(LOG_INFO, "SSDP M-SEARCH from %s ST:%.*s",
        !           518:           buf, (int)st_len, st);
        !           519: #else  /* ENABLE_IPV6 */
        !           520:    syslog(LOG_INFO, "SSDP M-SEARCH from %s:%d ST: %.*s",
        !           521:           inet_ntoa(((const struct sockaddr_in *)addr)->sin_addr),
        !           522:           ntohs(((const struct sockaddr_in *)addr)->sin_port),
        !           523:           (int)st_len, st);
        !           524: #endif /* ENABLE_IPV6 */
        !           525:    if(st_len==8 && (0==memcmp(st, "ssdp:all", 8))) {
        !           526:        /* send a response for all services */
        !           527:        for(serv = servicelisthead.lh_first;
        !           528:            serv;
        !           529:            serv = serv->entries.le_next) {
        !           530:            SendSSDPMSEARCHResponse(s, addr,
        !           531:                                    serv->st, strlen(serv->st), serv->usn,
        !           532:                                    serv->server, serv->location);
        !           533:        }
        !           534:    } else if(st_len > 5 && (0==memcmp(st, "uuid:", 5))) {
        !           535:        /* find a matching UUID value */
        !           536:        for(serv = servicelisthead.lh_first;
        !           537:            serv;
        !           538:            serv = serv->entries.le_next) {
        !           539:            if(0 == strncmp(serv->usn, st, st_len)) {
        !           540:                SendSSDPMSEARCHResponse(s, addr,
        !           541:                                        serv->st, strlen(serv->st), serv->usn,
        !           542:                                        serv->server, serv->location);
        !           543:            }
        !           544:        }
        !           545:    } else {
        !           546:        size_t l;
        !           547:        int st_ver = 0;
        !           548:        char atoi_buffer[8];
        !           549: 
        !           550:        /* remove version at the end of the ST string */
        !           551:        for (l = st_len; l > 0; l--) {
        !           552:            if (st[l-1] == ':') {
        !           553:                memset(atoi_buffer, 0, sizeof(atoi_buffer));
        !           554:                memcpy(atoi_buffer, st + l, MIN((sizeof(atoi_buffer) - 1), st_len - l));
        !           555:                st_ver = atoi(atoi_buffer);
        !           556:                break;
        !           557:            }
        !           558:        }
        !           559:        if (l == 0)
        !           560:            l = st_len;
        !           561:        /* answer for each matching service */
        !           562:        /* From UPnP Device Architecture v1.1 :
        !           563:         * 1.3.2 [...] Updated versions of device and service types
        !           564:         * are REQUIRED to be full backward compatible with
        !           565:         * previous versions. Devices MUST respond to M-SEARCH
        !           566:         * requests for any supported version. For example, if a
        !           567:         * device implements “urn:schemas-upnporg:service:xyz:2”,
        !           568:         * it MUST respond to search requests for both that type
        !           569:         * and “urn:schemas-upnp-org:service:xyz:1”. The response
        !           570:         * MUST specify the same version as was contained in the
        !           571:         * search request. [...] */
        !           572:        for(serv = servicelisthead.lh_first;
        !           573:            serv;
        !           574:            serv = serv->entries.le_next) {
        !           575:            if(0 == strncmp(serv->st, st, l)) {
        !           576:                syslog(LOG_DEBUG, "Found matching service : %s %s (v %d)", serv->st, serv->location, st_ver);
        !           577:                SendSSDPMSEARCHResponse(s, addr,
        !           578:                                        st, st_len, serv->usn,
        !           579:                                        serv->server, serv->location);
        !           580:            }
        !           581:        }
        !           582:    }
        !           583: }
        !           584: 
        !           585: /**
        !           586:  * helper function.
        !           587:  * reject any non ASCII or non printable character.
        !           588:  */
        !           589: static int
        !           590: containsForbiddenChars(const unsigned char * p, int len)
        !           591: {
        !           592:    while(len > 0) {
        !           593:        if(*p < ' ' || *p >= '\x7f')
        !           594:            return 1;
        !           595:        p++;
        !           596:        len--;
        !           597:    }
        !           598:    return 0;
        !           599: }
        !           600: 
        !           601: #define METHOD_MSEARCH 1
        !           602: #define METHOD_NOTIFY 2
        !           603: 
        !           604: /* ParseSSDPPacket() :
        !           605:  * parse a received SSDP Packet and call
        !           606:  * updateDevice() or removeDevice() as needed
        !           607:  * return value :
        !           608:  *    -1 : a device was removed
        !           609:  *     0 : no device removed nor added
        !           610:  *     1 : a device was added.  */
        !           611: static int
        !           612: ParseSSDPPacket(int s, const char * p, ssize_t n,
        !           613:                 const struct sockaddr * addr,
        !           614:                 const char * searched_device)
        !           615: {
        !           616:    const char * linestart;
        !           617:    const char * lineend;
        !           618:    const char * nameend;
        !           619:    const char * valuestart;
        !           620:    struct header headers[3];
        !           621:    int i, r = 0;
        !           622:    int methodlen;
        !           623:    int nts = -1;
        !           624:    int method = -1;
        !           625:    unsigned int lifetime = 180;    /* 3 minutes by default */
        !           626:    const char * st = NULL;
        !           627:    int st_len = 0;
        !           628: 
        !           629:    /* first check from what subnet is the sender */
        !           630:    if(get_lan_for_peer(addr) == NULL) {
        !           631:        char addr_str[64];
        !           632:        sockaddr_to_string(addr, addr_str, sizeof(addr_str));
        !           633:        syslog(LOG_WARNING, "peer %s is not from a LAN",
        !           634:               addr_str);
        !           635:        return 0;
        !           636:    }
        !           637: 
        !           638:    /* do the parsing */
        !           639:    memset(headers, 0, sizeof(headers));
        !           640:    for(methodlen = 0;
        !           641:        methodlen < n && (isalpha(p[methodlen]) || p[methodlen]=='-');
        !           642:        methodlen++);
        !           643:    if(methodlen==8 && 0==memcmp(p, "M-SEARCH", 8))
        !           644:        method = METHOD_MSEARCH;
        !           645:    else if(methodlen==6 && 0==memcmp(p, "NOTIFY", 6))
        !           646:        method = METHOD_NOTIFY;
        !           647:    else if(methodlen==4 && 0==memcmp(p, "HTTP", 4)) {
        !           648:        /* answer to a M-SEARCH => process it as a NOTIFY
        !           649:         * with NTS: ssdp:alive */
        !           650:        method = METHOD_NOTIFY;
        !           651:        nts = NTS_SSDP_ALIVE;
        !           652:    }
        !           653:    linestart = p;
        !           654:    while(linestart < p + n - 2) {
        !           655:        /* start parsing the line : detect line end */
        !           656:        lineend = linestart;
        !           657:        while(lineend < p + n && *lineend != '\n' && *lineend != '\r')
        !           658:            lineend++;
        !           659:        /*printf("line: '%.*s'\n", lineend - linestart, linestart);*/
        !           660:        /* detect name end : ':' character */
        !           661:        nameend = linestart;
        !           662:        while(nameend < lineend && *nameend != ':')
        !           663:            nameend++;
        !           664:        /* detect value */
        !           665:        if(nameend < lineend)
        !           666:            valuestart = nameend + 1;
        !           667:        else
        !           668:            valuestart = nameend;
        !           669:        /* trim spaces */
        !           670:        while(valuestart < lineend && isspace(*valuestart))
        !           671:            valuestart++;
        !           672:        /* suppress leading " if needed */
        !           673:        if(valuestart < lineend && *valuestart=='\"')
        !           674:            valuestart++;
        !           675:        if(nameend > linestart && valuestart < lineend) {
        !           676:            int l = nameend - linestart;    /* header name length */
        !           677:            int m = lineend - valuestart;   /* header value length */
        !           678:            /* suppress tailing spaces */
        !           679:            while(m>0 && isspace(valuestart[m-1]))
        !           680:                m--;
        !           681:            /* suppress tailing ' if needed */
        !           682:            if(m>0 && valuestart[m-1] == '\"')
        !           683:                m--;
        !           684:            i = -1;
        !           685:            /*printf("--%.*s: (%d)%.*s--\n", l, linestart,
        !           686:                                       m, m, valuestart);*/
        !           687:            if(l==2 && 0==strncasecmp(linestart, "nt", 2))
        !           688:                i = HEADER_NT;
        !           689:            else if(l==3 && 0==strncasecmp(linestart, "usn", 3))
        !           690:                i = HEADER_USN;
        !           691:            else if(l==3 && 0==strncasecmp(linestart, "nts", 3)) {
        !           692:                if(m==10 && 0==strncasecmp(valuestart, "ssdp:alive", 10))
        !           693:                    nts = NTS_SSDP_ALIVE;
        !           694:                else if(m==11 && 0==strncasecmp(valuestart, "ssdp:byebye", 11))
        !           695:                    nts = NTS_SSDP_BYEBYE;
        !           696:                else if(m==11 && 0==strncasecmp(valuestart, "ssdp:update", 11))
        !           697:                    nts = NTS_SSDP_UPDATE;
        !           698:            }
        !           699:            else if(l==8 && 0==strncasecmp(linestart, "location", 8))
        !           700:                i = HEADER_LOCATION;
        !           701:            else if(l==13 && 0==strncasecmp(linestart, "cache-control", 13)) {
        !           702:                /* parse "name1=value1, name_alone, name2=value2" string */
        !           703:                const char * name = valuestart; /* name */
        !           704:                const char * val;               /* value */
        !           705:                int rem = m;    /* remaining bytes to process */
        !           706:                while(rem > 0) {
        !           707:                    val = name;
        !           708:                    while(val < name + rem && *val != '=' && *val != ',')
        !           709:                        val++;
        !           710:                    if(val >= name + rem)
        !           711:                        break;
        !           712:                    if(*val == '=') {
        !           713:                        while(val < name + rem && (*val == '=' || isspace(*val)))
        !           714:                            val++;
        !           715:                        if(val >= name + rem)
        !           716:                            break;
        !           717:                        if(0==strncasecmp(name, "max-age", 7))
        !           718:                            lifetime = (unsigned int)strtoul(val, 0, 0);
        !           719:                        /* move to the next name=value pair */
        !           720:                        while(rem > 0 && *name != ',') {
        !           721:                            rem--;
        !           722:                            name++;
        !           723:                        }
        !           724:                        /* skip spaces */
        !           725:                        while(rem > 0 && (*name == ',' || isspace(*name))) {
        !           726:                            rem--;
        !           727:                            name++;
        !           728:                        }
        !           729:                    } else {
        !           730:                        rem -= (val - name);
        !           731:                        name = val;
        !           732:                        while(rem > 0 && (*name == ',' || isspace(*name))) {
        !           733:                            rem--;
        !           734:                            name++;
        !           735:                        }
        !           736:                    }
        !           737:                }
        !           738:                /*syslog(LOG_DEBUG, "**%.*s**%u", m, valuestart, lifetime);*/
        !           739:            } else if(l==2 && 0==strncasecmp(linestart, "st", 2)) {
        !           740:                st = valuestart;
        !           741:                st_len = m;
        !           742:                if(method == METHOD_NOTIFY)
        !           743:                    i = HEADER_NT;  /* it was a M-SEARCH response */
        !           744:            }
        !           745:            if(i>=0) {
        !           746:                headers[i].p = valuestart;
        !           747:                headers[i].l = m;
        !           748:            }
        !           749:        }
        !           750:        linestart = lineend;
        !           751:        while((linestart < p + n) && (*linestart == '\n' || *linestart == '\r'))
        !           752:            linestart++;
        !           753:    }
        !           754: #if 0
        !           755:    printf("NTS=%d\n", nts);
        !           756:    for(i=0; i<3; i++) {
        !           757:        if(headers[i].p)
        !           758:            printf("%d-'%.*s'\n", i, headers[i].l, headers[i].p);
        !           759:    }
        !           760: #endif
        !           761:    syslog(LOG_DEBUG,"SSDP request: '%.*s' (%d) %s %s=%.*s",
        !           762:           methodlen, p, method, nts_to_str(nts),
        !           763:           (method==METHOD_NOTIFY)?"nt":"st",
        !           764:           (method==METHOD_NOTIFY)?headers[HEADER_NT].l:st_len,
        !           765:           (method==METHOD_NOTIFY)?headers[HEADER_NT].p:st);
        !           766:    switch(method) {
        !           767:    case METHOD_NOTIFY:
        !           768:        if(nts==NTS_SSDP_ALIVE || nts==NTS_SSDP_UPDATE) {
        !           769:            if(headers[HEADER_NT].p && headers[HEADER_USN].p && headers[HEADER_LOCATION].p) {
        !           770:                /* filter if needed */
        !           771:                if(searched_device &&
        !           772:                   0 != memcmp(headers[HEADER_NT].p, searched_device, headers[HEADER_NT].l))
        !           773:                    break;
        !           774:                r = updateDevice(headers, time(NULL) + lifetime);
        !           775:            } else {
        !           776:                syslog(LOG_WARNING, "missing header nt=%p usn=%p location=%p",
        !           777:                       headers[HEADER_NT].p, headers[HEADER_USN].p,
        !           778:                       headers[HEADER_LOCATION].p);
        !           779:            }
        !           780:        } else if(nts==NTS_SSDP_BYEBYE) {
        !           781:            if(headers[HEADER_NT].p && headers[HEADER_USN].p) {
        !           782:                r = removeDevice(headers);
        !           783:            } else {
        !           784:                syslog(LOG_WARNING, "missing header nt=%p usn=%p",
        !           785:                       headers[HEADER_NT].p, headers[HEADER_USN].p);
        !           786:            }
        !           787:        }
        !           788:        break;
        !           789:    case METHOD_MSEARCH:
        !           790:        processMSEARCH(s, st, st_len, addr);
        !           791:        break;
        !           792:    default:
        !           793:        {
        !           794:            char addr_str[64];
        !           795:            sockaddr_to_string(addr, addr_str, sizeof(addr_str));
        !           796:            syslog(LOG_WARNING, "method %.*s, don't know what to do (from %s)",
        !           797:                   methodlen, p, addr_str);
        !           798:        }
        !           799:    }
        !           800:    return r;
        !           801: }
        !           802: 
        !           803: /* OpenUnixSocket()
        !           804:  * open the unix socket and call bind() and listen()
        !           805:  * return -1 in case of error */
        !           806: static int
        !           807: OpenUnixSocket(const char * path)
        !           808: {
        !           809:    struct sockaddr_un addr;
        !           810:    int s;
        !           811:    int rv;
        !           812:    s = socket(AF_UNIX, SOCK_STREAM, 0);
        !           813:    if(s < 0)
        !           814:    {
        !           815:        syslog(LOG_ERR, "socket(AF_UNIX): %m");
        !           816:        return -1;
        !           817:    }
        !           818:    /* unlink the socket pseudo file before binding */
        !           819:    rv = unlink(path);
        !           820:    if(rv < 0 && errno != ENOENT)
        !           821:    {
        !           822:        syslog(LOG_ERR, "unlink(unixsocket, \"%s\"): %m", path);
        !           823:        close(s);
        !           824:        return -1;
        !           825:    }
        !           826:    addr.sun_family = AF_UNIX;
        !           827:    strncpy(addr.sun_path, path, sizeof(addr.sun_path));
        !           828:    if(bind(s, (struct sockaddr *)&addr,
        !           829:               sizeof(struct sockaddr_un)) < 0)
        !           830:    {
        !           831:        syslog(LOG_ERR, "bind(unixsocket, \"%s\"): %m", path);
        !           832:        close(s);
        !           833:        return -1;
        !           834:    }
        !           835:    else if(listen(s, 5) < 0)
        !           836:    {
        !           837:        syslog(LOG_ERR, "listen(unixsocket): %m");
        !           838:        close(s);
        !           839:        return -1;
        !           840:    }
        !           841:    /* Change rights so everyone can communicate with us */
        !           842:    if(chmod(path, 0666) < 0)
        !           843:    {
        !           844:        syslog(LOG_WARNING, "chmod(\"%s\"): %m", path);
        !           845:    }
        !           846:    return s;
        !           847: }
        !           848: 
        !           849: static ssize_t processRequestSub(struct reqelem * req, const unsigned char * buf, ssize_t n);
        !           850: 
        !           851: /* processRequest() :
        !           852:  * process the request coming from a unix socket */
        !           853: void processRequest(struct reqelem * req)
        !           854: {
        !           855:    ssize_t n, r;
        !           856:    unsigned char buf[2048];
        !           857:    const unsigned char * p;
        !           858: 
        !           859:    n = read(req->socket, buf, sizeof(buf));
        !           860:    if(n<0) {
        !           861:        if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
        !           862:            return; /* try again later */
        !           863:        syslog(LOG_ERR, "(s=%d) processRequest(): read(): %m", req->socket);
        !           864:        goto error;
        !           865:    }
        !           866:    if(n==0) {
        !           867:        syslog(LOG_INFO, "(s=%d) request connection closed", req->socket);
        !           868:        goto error;
        !           869:    }
        !           870:    p = buf;
        !           871:    while (n > 0)
        !           872:    {
        !           873:        r = processRequestSub(req, p, n);
        !           874:        if (r < 0)
        !           875:            goto error;
        !           876:        p += r;
        !           877:        n -= r;
        !           878:    }
        !           879:    return;
        !           880: error:
        !           881:    close(req->socket);
        !           882:    req->socket = -1;
        !           883: }
        !           884: 
        !           885: static ssize_t processRequestSub(struct reqelem * req, const unsigned char * buf, ssize_t n)
        !           886: {
        !           887:    unsigned int l, m;
        !           888:    unsigned int baselen;   /* without the version */
        !           889:    const unsigned char * p;
        !           890:    enum request_type type;
        !           891:    struct device * d = devlist;
        !           892:    unsigned char rbuf[RESPONSE_BUFFER_SIZE];
        !           893:    unsigned char * rp;
        !           894:    unsigned char nrep = 0;
        !           895:    time_t t;
        !           896:    struct service * newserv = NULL;
        !           897:    struct service * serv;
        !           898: 
        !           899:    t = time(NULL);
        !           900:    type = buf[0];
        !           901:    p = buf + 1;
        !           902:    DECODELENGTH_CHECKLIMIT(l, p, buf + n);
        !           903:    if(l > (unsigned)(buf+n-p)) {
        !           904:        syslog(LOG_WARNING, "bad request (length encoding l=%u n=%u)",
        !           905:               l, (unsigned)n);
        !           906:        goto error;
        !           907:    }
        !           908:    if(l == 0 && type != MINISSDPD_SEARCH_ALL
        !           909:       && type != MINISSDPD_GET_VERSION && type != MINISSDPD_NOTIF) {
        !           910:        syslog(LOG_WARNING, "bad request (length=0, type=%d)", type);
        !           911:        goto error;
        !           912:    }
        !           913:    syslog(LOG_INFO, "(s=%d) request type=%d str='%.*s'",
        !           914:           req->socket, type, l, p);
        !           915:    switch(type) {
        !           916:    case MINISSDPD_GET_VERSION:
        !           917:        rp = rbuf;
        !           918:        CODELENGTH((sizeof(MINISSDPD_VERSION) - 1), rp);
        !           919:        memcpy(rp, MINISSDPD_VERSION, sizeof(MINISSDPD_VERSION) - 1);
        !           920:        rp += (sizeof(MINISSDPD_VERSION) - 1);
        !           921:        if(write_or_buffer(req, rbuf, rp - rbuf) < 0) {
        !           922:            syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
        !           923:            goto error;
        !           924:        }
        !           925:        p += l;
        !           926:        break;
        !           927:    case MINISSDPD_SEARCH_TYPE: /* request by type */
        !           928:    case MINISSDPD_SEARCH_USN:  /* request by USN (unique id) */
        !           929:    case MINISSDPD_SEARCH_ALL:  /* everything */
        !           930:        rp = rbuf+1;
        !           931:        /* From UPnP Device Architecture v1.1 :
        !           932:         * 1.3.2 [...] Updated versions of device and service types
        !           933:         * are REQUIRED to be full backward compatible with
        !           934:         * previous versions. Devices MUST respond to M-SEARCH
        !           935:         * requests for any supported version. For example, if a
        !           936:         * device implements “urn:schemas-upnporg:service:xyz:2”,
        !           937:         * it MUST respond to search requests for both that type
        !           938:         * and “urn:schemas-upnp-org:service:xyz:1”. The response
        !           939:         * MUST specify the same version as was contained in the
        !           940:         * search request. [...] */
        !           941:        baselen = l;    /* remove the version */
        !           942:        while(baselen > 0) {
        !           943:            if(p[baselen-1] == ':')
        !           944:                break;
        !           945:            if(!(p[baselen-1] >= '0' && p[baselen-1] <= '9'))
        !           946:                break;
        !           947:            baselen--;
        !           948:        }
        !           949:        while(d && (nrep < 255)) {
        !           950:            if(d->t < t) {
        !           951:                syslog(LOG_INFO, "outdated device");
        !           952:            } else {
        !           953:                /* test if we can put more responses in the buffer */
        !           954:                if(d->headers[HEADER_LOCATION].l + d->headers[HEADER_NT].l
        !           955:                  + d->headers[HEADER_USN].l + 6
        !           956:                  + (rp - rbuf) >= (int)sizeof(rbuf))
        !           957:                    break;
        !           958:                if( (type==MINISSDPD_SEARCH_TYPE && 0==memcmp(d->headers[HEADER_NT].p, p, baselen))
        !           959:                  ||(type==MINISSDPD_SEARCH_USN && 0==memcmp(d->headers[HEADER_USN].p, p, l))
        !           960:                  ||(type==MINISSDPD_SEARCH_ALL) ) {
        !           961:                    /* response :
        !           962:                     * 1 - Location
        !           963:                     * 2 - NT (device/service type)
        !           964:                     * 3 - usn */
        !           965:                    m = d->headers[HEADER_LOCATION].l;
        !           966:                    CODELENGTH(m, rp);
        !           967:                    memcpy(rp, d->headers[HEADER_LOCATION].p, d->headers[HEADER_LOCATION].l);
        !           968:                    rp += d->headers[HEADER_LOCATION].l;
        !           969:                    m = d->headers[HEADER_NT].l;
        !           970:                    CODELENGTH(m, rp);
        !           971:                    memcpy(rp, d->headers[HEADER_NT].p, d->headers[HEADER_NT].l);
        !           972:                    rp += d->headers[HEADER_NT].l;
        !           973:                    m = d->headers[HEADER_USN].l;
        !           974:                    CODELENGTH(m, rp);
        !           975:                    memcpy(rp, d->headers[HEADER_USN].p, d->headers[HEADER_USN].l);
        !           976:                    rp += d->headers[HEADER_USN].l;
        !           977:                    nrep++;
        !           978:                }
        !           979:            }
        !           980:            d = d->next;
        !           981:        }
        !           982:        /* Also look in service list */
        !           983:        for(serv = servicelisthead.lh_first;
        !           984:            serv && (nrep < 255);
        !           985:            serv = serv->entries.le_next) {
        !           986:            /* test if we can put more responses in the buffer */
        !           987:            if(strlen(serv->location) + strlen(serv->st)
        !           988:              + strlen(serv->usn) + 6 + (rp - rbuf) >= sizeof(rbuf))
        !           989:                break;
        !           990:            if( (type==MINISSDPD_SEARCH_TYPE && 0==strncmp(serv->st, (const char *)p, l))
        !           991:              ||(type==MINISSDPD_SEARCH_USN && 0==strncmp(serv->usn, (const char *)p, l))
        !           992:              ||(type==MINISSDPD_SEARCH_ALL) ) {
        !           993:                /* response :
        !           994:                 * 1 - Location
        !           995:                 * 2 - NT (device/service type)
        !           996:                 * 3 - usn */
        !           997:                m = strlen(serv->location);
        !           998:                CODELENGTH(m, rp);
        !           999:                memcpy(rp, serv->location, m);
        !          1000:                rp += m;
        !          1001:                m = strlen(serv->st);
        !          1002:                CODELENGTH(m, rp);
        !          1003:                memcpy(rp, serv->st, m);
        !          1004:                rp += m;
        !          1005:                m = strlen(serv->usn);
        !          1006:                CODELENGTH(m, rp);
        !          1007:                memcpy(rp, serv->usn, m);
        !          1008:                rp += m;
        !          1009:                nrep++;
        !          1010:            }
        !          1011:        }
        !          1012:        rbuf[0] = nrep;
        !          1013:        syslog(LOG_DEBUG, "(s=%d) response : %d device%s",
        !          1014:               req->socket, nrep, (nrep > 1) ? "s" : "");
        !          1015:        if(write_or_buffer(req, rbuf, rp - rbuf) < 0) {
        !          1016:            syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
        !          1017:            goto error;
        !          1018:        }
        !          1019:        p += l;
        !          1020:        break;
        !          1021:    case MINISSDPD_SUBMIT:  /* submit service */
        !          1022:        newserv = malloc(sizeof(struct service));
        !          1023:        if(!newserv) {
        !          1024:            syslog(LOG_ERR, "cannot allocate memory");
        !          1025:            goto error;
        !          1026:        }
        !          1027:        memset(newserv, 0, sizeof(struct service)); /* set pointers to NULL */
        !          1028:        if(containsForbiddenChars(p, l)) {
        !          1029:            syslog(LOG_ERR, "bad request (st contains forbidden chars)");
        !          1030:            goto error;
        !          1031:        }
        !          1032:        newserv->st = malloc(l + 1);
        !          1033:        if(!newserv->st) {
        !          1034:            syslog(LOG_ERR, "cannot allocate memory");
        !          1035:            goto error;
        !          1036:        }
        !          1037:        memcpy(newserv->st, p, l);
        !          1038:        newserv->st[l] = '\0';
        !          1039:        p += l;
        !          1040:        if(p >= buf + n) {
        !          1041:            syslog(LOG_WARNING, "bad request (missing usn)");
        !          1042:            goto error;
        !          1043:        }
        !          1044:        DECODELENGTH_CHECKLIMIT(l, p, buf + n);
        !          1045:        if(l > (unsigned)(buf+n-p)) {
        !          1046:            syslog(LOG_WARNING, "bad request (length encoding)");
        !          1047:            goto error;
        !          1048:        }
        !          1049:        if(containsForbiddenChars(p, l)) {
        !          1050:            syslog(LOG_ERR, "bad request (usn contains forbidden chars)");
        !          1051:            goto error;
        !          1052:        }
        !          1053:        syslog(LOG_INFO, "usn='%.*s'", l, p);
        !          1054:        newserv->usn = malloc(l + 1);
        !          1055:        if(!newserv->usn) {
        !          1056:            syslog(LOG_ERR, "cannot allocate memory");
        !          1057:            goto error;
        !          1058:        }
        !          1059:        memcpy(newserv->usn, p, l);
        !          1060:        newserv->usn[l] = '\0';
        !          1061:        p += l;
        !          1062:        DECODELENGTH_CHECKLIMIT(l, p, buf + n);
        !          1063:        if(l > (unsigned)(buf+n-p)) {
        !          1064:            syslog(LOG_WARNING, "bad request (length encoding)");
        !          1065:            goto error;
        !          1066:        }
        !          1067:        if(containsForbiddenChars(p, l)) {
        !          1068:            syslog(LOG_ERR, "bad request (server contains forbidden chars)");
        !          1069:            goto error;
        !          1070:        }
        !          1071:        syslog(LOG_INFO, "server='%.*s'", l, p);
        !          1072:        newserv->server = malloc(l + 1);
        !          1073:        if(!newserv->server) {
        !          1074:            syslog(LOG_ERR, "cannot allocate memory");
        !          1075:            goto error;
        !          1076:        }
        !          1077:        memcpy(newserv->server, p, l);
        !          1078:        newserv->server[l] = '\0';
        !          1079:        p += l;
        !          1080:        DECODELENGTH_CHECKLIMIT(l, p, buf + n);
        !          1081:        if(l > (unsigned)(buf+n-p)) {
        !          1082:            syslog(LOG_WARNING, "bad request (length encoding)");
        !          1083:            goto error;
        !          1084:        }
        !          1085:        if(containsForbiddenChars(p, l)) {
        !          1086:            syslog(LOG_ERR, "bad request (location contains forbidden chars)");
        !          1087:            goto error;
        !          1088:        }
        !          1089:        syslog(LOG_INFO, "location='%.*s'", l, p);
        !          1090:        newserv->location = malloc(l + 1);
        !          1091:        if(!newserv->location) {
        !          1092:            syslog(LOG_ERR, "cannot allocate memory");
        !          1093:            goto error;
        !          1094:        }
        !          1095:        memcpy(newserv->location, p, l);
        !          1096:        newserv->location[l] = '\0';
        !          1097:        p += l;
        !          1098:        /* look in service list for duplicate */
        !          1099:        for(serv = servicelisthead.lh_first;
        !          1100:            serv;
        !          1101:            serv = serv->entries.le_next) {
        !          1102:            if(0 == strcmp(newserv->usn, serv->usn)
        !          1103:              && 0 == strcmp(newserv->st, serv->st)) {
        !          1104:                syslog(LOG_INFO, "Service already in the list. Updating...");
        !          1105:                free(newserv->st);
        !          1106:                free(newserv->usn);
        !          1107:                free(serv->server);
        !          1108:                serv->server = newserv->server;
        !          1109:                free(serv->location);
        !          1110:                serv->location = newserv->location;
        !          1111:                free(newserv);
        !          1112:                newserv = NULL;
        !          1113:                return (p - buf);
        !          1114:            }
        !          1115:        }
        !          1116:        /* Inserting new service */
        !          1117:        LIST_INSERT_HEAD(&servicelisthead, newserv, entries);
        !          1118:        sendNotifications(NOTIF_NEW, NULL, newserv);
        !          1119:        newserv = NULL;
        !          1120:        break;
        !          1121:    case MINISSDPD_NOTIF:   /* switch socket to notify */
        !          1122:        rbuf[0] = '\0';
        !          1123:        if(write_or_buffer(req, rbuf, 1) < 0) {
        !          1124:            syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
        !          1125:            goto error;
        !          1126:        }
        !          1127:        req->is_notify = 1;
        !          1128:        p += l;
        !          1129:        break;
        !          1130:    default:
        !          1131:        syslog(LOG_WARNING, "Unknown request type %d", type);
        !          1132:        rbuf[0] = '\0';
        !          1133:        if(write_or_buffer(req, rbuf, 1) < 0) {
        !          1134:            syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
        !          1135:            goto error;
        !          1136:        }
        !          1137:    }
        !          1138:    return (p - buf);
        !          1139: error:
        !          1140:    if(newserv) {
        !          1141:        free(newserv->st);
        !          1142:        free(newserv->usn);
        !          1143:        free(newserv->server);
        !          1144:        free(newserv->location);
        !          1145:        free(newserv);
        !          1146:        newserv = NULL;
        !          1147:    }
        !          1148:    return -1;
        !          1149: }
        !          1150: 
        !          1151: static volatile sig_atomic_t quitting = 0;
        !          1152: /* SIGTERM signal handler */
        !          1153: static void
        !          1154: sigterm(int sig)
        !          1155: {
        !          1156:    (void)sig;
        !          1157:    /*int save_errno = errno;*/
        !          1158:    /*signal(sig, SIG_IGN);*/
        !          1159: #if 0
        !          1160:    /* calling syslog() is forbidden in a signal handler according to
        !          1161:     * signal(3) */
        !          1162:    syslog(LOG_NOTICE, "received signal %d, good-bye", sig);
        !          1163: #endif
        !          1164:    quitting = 1;
        !          1165:    /*errno = save_errno;*/
        !          1166: }
        !          1167: 
        !          1168: #define PORT 1900
        !          1169: #define XSTR(s) STR(s)
        !          1170: #define STR(s) #s
        !          1171: #define UPNP_MCAST_ADDR "239.255.255.250"
        !          1172: /* for IPv6 */
        !          1173: #define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
        !          1174: #define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
        !          1175: 
        !          1176: /* send the M-SEARCH request for devices
        !          1177:  * either all devices (third argument is NULL or "*") or a specific one */
        !          1178: static void ssdpDiscover(int s, int ipv6, const char * search)
        !          1179: {
        !          1180:    static const char MSearchMsgFmt[] =
        !          1181:    "M-SEARCH * HTTP/1.1\r\n"
        !          1182:    "HOST: %s:" XSTR(PORT) "\r\n"
        !          1183:    "ST: %s\r\n"
        !          1184:    "MAN: \"ssdp:discover\"\r\n"
        !          1185:    "MX: %u\r\n"
        !          1186:    "\r\n";
        !          1187:    char bufr[512];
        !          1188:    int n;
        !          1189:    int mx = 3;
        !          1190:    int linklocal = 1;
        !          1191:    struct sockaddr_storage sockudp_w;
        !          1192: 
        !          1193:    {
        !          1194:        n = snprintf(bufr, sizeof(bufr),
        !          1195:                     MSearchMsgFmt,
        !          1196:                     ipv6 ?
        !          1197:                     (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" :  "[" UPNP_MCAST_SL_ADDR "]")
        !          1198:                     : UPNP_MCAST_ADDR,
        !          1199:                     (search ? search : "ssdp:all"), mx);
        !          1200:        memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
        !          1201:        if(ipv6) {
        !          1202:            struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
        !          1203:            p->sin6_family = AF_INET6;
        !          1204:            p->sin6_port = htons(PORT);
        !          1205:            inet_pton(AF_INET6,
        !          1206:                      linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
        !          1207:                      &(p->sin6_addr));
        !          1208:        } else {
        !          1209:            struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
        !          1210:            p->sin_family = AF_INET;
        !          1211:            p->sin_port = htons(PORT);
        !          1212:            p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
        !          1213:        }
        !          1214: 
        !          1215:        n = sendto_or_schedule(s, bufr, n, 0, (const struct sockaddr *)&sockudp_w,
        !          1216:                               ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
        !          1217:        if (n < 0) {
        !          1218:            syslog(LOG_ERR, "%s: sendto(s=%d, ipv6=%d): %m", __func__, s, ipv6);
        !          1219:        }
        !          1220:    }
        !          1221: }
        !          1222: 
        !          1223: /* main(): program entry point */
        !          1224: int main(int argc, char * * argv)
        !          1225: {
        !          1226:    int ret = 0;
        !          1227: #ifndef NO_BACKGROUND_NO_PIDFILE
        !          1228:    int pid;
        !          1229: #endif
        !          1230:    struct sigaction sa;
        !          1231:    char buf[1500];
        !          1232:    ssize_t n;
        !          1233:    int s_ssdp = -1;    /* udp socket receiving ssdp packets */
        !          1234: #ifdef ENABLE_IPV6
        !          1235:    int s_ssdp6 = -1;   /* udp socket receiving ssdp packets IPv6*/
        !          1236: #else  /* ENABLE_IPV6 */
        !          1237: #define s_ssdp6 (-1)
        !          1238: #endif /* ENABLE_IPV6 */
        !          1239:    int s_unix = -1;    /* unix socket communicating with clients */
        !          1240:    int s_ifacewatch = -1;  /* socket to receive Route / network interface config changes */
        !          1241:    struct reqelem * req;
        !          1242:    struct reqelem * reqnext;
        !          1243:    fd_set readfds;
        !          1244:    fd_set writefds;
        !          1245:    struct timeval now;
        !          1246:    int max_fd;
        !          1247:    struct lan_addr_s * lan_addr;
        !          1248:    int i;
        !          1249:    const char * sockpath = "/var/run/minissdpd.sock";
        !          1250: #ifndef NO_BACKGROUND_NO_PIDFILE
        !          1251:    const char * pidfilename = "/var/run/minissdpd.pid";
        !          1252: #endif
        !          1253:    int debug_flag = 0;
        !          1254: #ifdef ENABLE_IPV6
        !          1255:    int ipv6 = 0;
        !          1256: #endif /* ENABLE_IPV6 */
        !          1257:    int deltadev = 0;
        !          1258:    struct sockaddr_in sendername;
        !          1259:    socklen_t sendername_len;
        !          1260: #ifdef ENABLE_IPV6
        !          1261:    struct sockaddr_in6 sendername6;
        !          1262:    socklen_t sendername6_len;
        !          1263: #endif /* ENABLE_IPV6 */
        !          1264:    unsigned char ttl = 2;  /* UDA says it should default to 2 */
        !          1265:    const char * searched_device = NULL;    /* if not NULL, search/filter a specific device type */
        !          1266:    int opt;
        !          1267: 
        !          1268:    LIST_INIT(&reqlisthead);
        !          1269:    LIST_INIT(&servicelisthead);
        !          1270:    LIST_INIT(&lan_addrs);
        !          1271:    /* process command line */
        !          1272: #define OPTSTRING "d6i:s:p:t:f:"
        !          1273:    while ((opt = getopt(argc, argv, "di:s:t:f:"
        !          1274: #ifdef ENABLE_IPV6
        !          1275:                                     "6"
        !          1276: #endif
        !          1277: #ifndef NO_BACKGROUND_NO_PIDFILE
        !          1278:                                     "p:"
        !          1279: #endif
        !          1280: 
        !          1281:                         )) != -1)
        !          1282:    {
        !          1283:        switch(opt)
        !          1284:        {
        !          1285:        case 'd':
        !          1286:            debug_flag = 1;
        !          1287:            break;
        !          1288: #ifdef ENABLE_IPV6
        !          1289:        case '6':
        !          1290:            ipv6 = 1;
        !          1291:            break;
        !          1292: #endif /* ENABLE_IPV6 */
        !          1293:        case 'i':
        !          1294:            lan_addr = malloc(sizeof(struct lan_addr_s));
        !          1295:            if(lan_addr == NULL) {
        !          1296:                fprintf(stderr, "malloc(%d) FAILED\n", (int)sizeof(struct lan_addr_s));
        !          1297:                break;
        !          1298:            }
        !          1299:            if(parselanaddr(lan_addr, optarg) != 0) {
        !          1300:                fprintf(stderr, "can't parse \"%s\" as a valid "
        !          1301: #ifndef ENABLE_IPV6
        !          1302:                        "address or "
        !          1303: #endif
        !          1304:                        "interface name\n", optarg);
        !          1305:                free(lan_addr);
        !          1306:            } else {
        !          1307:                LIST_INSERT_HEAD(&lan_addrs, lan_addr, list);
        !          1308:            }
        !          1309:            break;
        !          1310:        case 's':
        !          1311:            sockpath = optarg;
        !          1312:            break;
        !          1313: #ifndef NO_BACKGROUND_NO_PIDFILE
        !          1314:        case 'p':
        !          1315:            pidfilename = optarg;
        !          1316:            break;
        !          1317: #endif
        !          1318:        case 't':
        !          1319:            ttl = (unsigned char)atoi(optarg);
        !          1320:            break;
        !          1321:        case 'f':
        !          1322:            searched_device = optarg;
        !          1323:            break;
        !          1324:        }
        !          1325:    }
        !          1326:    if(lan_addrs.lh_first == NULL)
        !          1327:    {
        !          1328:        fprintf(stderr,
        !          1329:                "Usage: %s [-d] "
        !          1330: #ifdef ENABLE_IPV6
        !          1331:                "[-6] "
        !          1332: #endif /* ENABLE_IPV6 */
        !          1333:                "[-s socket] "
        !          1334: #ifndef NO_BACKGROUND_NO_PIDFILE
        !          1335:                "[-p pidfile] "
        !          1336: #endif
        !          1337:                "[-t TTL] "
        !          1338:                "[-f device] "
        !          1339:                "-i <interface> [-i <interface2>] ...\n",
        !          1340:                argv[0]);
        !          1341:        fprintf(stderr,
        !          1342:                "\n  <interface> is "
        !          1343: #ifndef ENABLE_IPV6
        !          1344:                "either an IPv4 address with mask such as\n"
        !          1345:                "  192.168.1.42/255.255.255.0, or "
        !          1346: #endif
        !          1347:                "an interface name such as eth0.\n");
        !          1348:        fprintf(stderr,
        !          1349:                "\n  By default, socket will be open as %s\n"
        !          1350: #ifndef NO_BACKGROUND_NO_PIDFILE
        !          1351:                "  and pid written to file %s\n",
        !          1352:                sockpath, pidfilename
        !          1353: #else
        !          1354:                ,sockpath
        !          1355: #endif
        !          1356:                );
        !          1357:        return 1;
        !          1358:    }
        !          1359: 
        !          1360:    /* open log */
        !          1361:    openlog("minissdpd",
        !          1362:            LOG_CONS|LOG_PID|(debug_flag?LOG_PERROR:0),
        !          1363:            LOG_MINISSDPD);
        !          1364:    if(!debug_flag) /* speed things up and ignore LOG_INFO and LOG_DEBUG */
        !          1365:        setlogmask(LOG_UPTO(LOG_NOTICE));
        !          1366: 
        !          1367: #ifndef NO_BACKGROUND_NO_PIDFILE
        !          1368:    if(checkforrunning(pidfilename) < 0)
        !          1369:    {
        !          1370:        syslog(LOG_ERR, "MiniSSDPd is already running. EXITING");
        !          1371:        return 1;
        !          1372:    }
        !          1373: #endif
        !          1374: 
        !          1375:    upnp_bootid = (unsigned int)time(NULL);
        !          1376: 
        !          1377:    /* set signal handlers */
        !          1378:    memset(&sa, 0, sizeof(struct sigaction));
        !          1379:    sa.sa_handler = sigterm;
        !          1380:    if(sigaction(SIGTERM, &sa, NULL))
        !          1381:    {
        !          1382:        syslog(LOG_ERR, "Failed to set SIGTERM handler. EXITING");
        !          1383:        ret = 1;
        !          1384:        goto quit;
        !          1385:    }
        !          1386:    if(sigaction(SIGINT, &sa, NULL))
        !          1387:    {
        !          1388:        syslog(LOG_ERR, "Failed to set SIGINT handler. EXITING");
        !          1389:        ret = 1;
        !          1390:        goto quit;
        !          1391:    }
        !          1392:    /* open route/interface config changes socket */
        !          1393:    s_ifacewatch = OpenAndConfInterfaceWatchSocket();
        !          1394:    /* open UDP socket(s) for receiving SSDP packets */
        !          1395:    s_ssdp = OpenAndConfSSDPReceiveSocket(0, ttl);
        !          1396:    if(s_ssdp < 0)
        !          1397:    {
        !          1398:        syslog(LOG_ERR, "Cannot open socket for receiving SSDP messages, exiting");
        !          1399:        ret = 1;
        !          1400:        goto quit;
        !          1401:    }
        !          1402: #ifdef ENABLE_IPV6
        !          1403:    if(ipv6) {
        !          1404:        s_ssdp6 = OpenAndConfSSDPReceiveSocket(1, ttl);
        !          1405:        if(s_ssdp6 < 0)
        !          1406:        {
        !          1407:            syslog(LOG_ERR, "Cannot open socket for receiving SSDP messages (IPv6), exiting");
        !          1408:            ret = 1;
        !          1409:            goto quit;
        !          1410:        }
        !          1411:    }
        !          1412: #endif /* ENABLE_IPV6 */
        !          1413:    /* Open Unix socket to communicate with other programs on
        !          1414:     * the same machine */
        !          1415:    s_unix = OpenUnixSocket(sockpath);
        !          1416:    if(s_unix < 0)
        !          1417:    {
        !          1418:        syslog(LOG_ERR, "Cannot open unix socket for communicating with clients. Exiting");
        !          1419:        ret = 1;
        !          1420:        goto quit;
        !          1421:    }
        !          1422: 
        !          1423:    /* drop privileges */
        !          1424: #if 0
        !          1425:    /* if we drop privileges, how to unlink(/var/run/minissdpd.sock) ? */
        !          1426:    if(getuid() == 0) {
        !          1427:        struct passwd * user;
        !          1428:        struct group * group;
        !          1429:        user = getpwnam("nobody");
        !          1430:        if(!user) {
        !          1431:            syslog(LOG_ERR, "getpwnam(\"%s\") : %m", "nobody");
        !          1432:            ret = 1;
        !          1433:            goto quit;
        !          1434:        }
        !          1435:        group = getgrnam("nogroup");
        !          1436:        if(!group) {
        !          1437:            syslog(LOG_ERR, "getgrnam(\"%s\") : %m", "nogroup");
        !          1438:            ret = 1;
        !          1439:            goto quit;
        !          1440:        }
        !          1441:        if(setgid(group->gr_gid) < 0) {
        !          1442:            syslog(LOG_ERR, "setgit(%d) : %m", group->gr_gid);
        !          1443:            ret = 1;
        !          1444:            goto quit;
        !          1445:        }
        !          1446:        if(setuid(user->pw_uid) < 0) {
        !          1447:            syslog(LOG_ERR, "setuid(%d) : %m", user->pw_uid);
        !          1448:            ret = 1;
        !          1449:            goto quit;
        !          1450:        }
        !          1451:    }
        !          1452: #endif
        !          1453: 
        !          1454: #ifndef NO_BACKGROUND_NO_PIDFILE
        !          1455:    /* daemonize or in any case get pid ! */
        !          1456:    if(debug_flag)
        !          1457:        pid = getpid();
        !          1458:    else {
        !          1459: #ifdef USE_DAEMON
        !          1460:        if(daemon(0, 0) < 0)
        !          1461:            perror("daemon()");
        !          1462:        pid = getpid();
        !          1463: #else  /* USE_DAEMON */
        !          1464:        pid = daemonize();
        !          1465: #endif /* USE_DAEMON */
        !          1466:    }
        !          1467: 
        !          1468:    writepidfile(pidfilename, pid);
        !          1469: #endif
        !          1470: 
        !          1471:    /* send M-SEARCH ssdp:all Requests */
        !          1472:    if(s_ssdp >= 0) {
        !          1473:        for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
        !          1474: #ifndef HAVE_IP_MREQN
        !          1475:            struct in_addr mc_if;
        !          1476: 
        !          1477:            mc_if.s_addr = lan_addr->addr.s_addr;   /*inet_addr(addr);*/
        !          1478: #else
        !          1479:            struct ip_mreqn mc_if;
        !          1480: 
        !          1481:            mc_if.imr_address.s_addr = lan_addr->addr.s_addr;   /*inet_addr(addr);*/
        !          1482: #ifdef ENABLE_IPV6
        !          1483:            mc_if.imr_ifindex = lan_addr->index;
        !          1484: #else  /* ENABLE_IPV6 */
        !          1485:            mc_if.imr_ifindex = if_nametoindex(lan_addr->ifname);
        !          1486: #endif /* ENABLE_IPV6 */
        !          1487: #endif /* HAVE_IP_MREQN */
        !          1488:            if(setsockopt(s_ssdp, IPPROTO_IP, IP_MULTICAST_IF, &mc_if, sizeof(mc_if)) < 0) {
        !          1489:                syslog(LOG_WARNING, "setsockopt(IP_MULTICAST_IF): %m");
        !          1490:            }
        !          1491:            ssdpDiscover(s_ssdp, 0, searched_device);
        !          1492:            /* XXX if ssdpDiscover() doesn't send the SSDP packet at once,
        !          1493:             * we should wait here */
        !          1494:        }
        !          1495:    }
        !          1496:    if(s_ssdp6 >= 0)
        !          1497:        ssdpDiscover(s_ssdp6, 1, searched_device);
        !          1498: 
        !          1499:    /* Main loop */
        !          1500:    while(!quitting) {
        !          1501:        /* fill readfds fd_set */
        !          1502:        FD_ZERO(&readfds);
        !          1503:        FD_ZERO(&writefds);
        !          1504: 
        !          1505:        FD_SET(s_unix, &readfds);
        !          1506:        max_fd = s_unix;
        !          1507:        if(s_ssdp >= 0) {
        !          1508:            FD_SET(s_ssdp, &readfds);
        !          1509:            SET_MAX(max_fd, s_ssdp);
        !          1510:        }
        !          1511: #ifdef ENABLE_IPV6
        !          1512:        if(s_ssdp6 >= 0) {
        !          1513:            FD_SET(s_ssdp6, &readfds);
        !          1514:            SET_MAX(max_fd, s_ssdp6);
        !          1515:        }
        !          1516: #endif /* ENABLE_IPV6 */
        !          1517:        if(s_ifacewatch >= 0) {
        !          1518:            FD_SET(s_ifacewatch, &readfds);
        !          1519:            SET_MAX(max_fd, s_ifacewatch);
        !          1520:        }
        !          1521:        for(req = reqlisthead.lh_first; req; req = req->entries.le_next) {
        !          1522:            if(req->socket >= 0) {
        !          1523:                FD_SET(req->socket, &readfds);
        !          1524:                SET_MAX(max_fd, req->socket);
        !          1525:            }
        !          1526:            if(req->output_buffer_len > 0) {
        !          1527:                FD_SET(req->socket, &writefds);
        !          1528:                SET_MAX(max_fd, req->socket);
        !          1529:            }
        !          1530:        }
        !          1531:        gettimeofday(&now, NULL);
        !          1532:        i = get_sendto_fds(&writefds, &max_fd, &now);
        !          1533:        /* select call */
        !          1534:        if(select(max_fd + 1, &readfds, &writefds, 0, 0) < 0) {
        !          1535:            if(errno != EINTR) {
        !          1536:                syslog(LOG_ERR, "select: %m");
        !          1537:                break;  /* quit */
        !          1538:            }
        !          1539:            continue;   /* try again */
        !          1540:        }
        !          1541:        if(try_sendto(&writefds) < 0) {
        !          1542:            syslog(LOG_ERR, "try_sendto: %m");
        !          1543:            break;
        !          1544:        }
        !          1545: #ifdef ENABLE_IPV6
        !          1546:        if((s_ssdp6 >= 0) && FD_ISSET(s_ssdp6, &readfds))
        !          1547:        {
        !          1548:            sendername6_len = sizeof(struct sockaddr_in6);
        !          1549:            n = recvfrom(s_ssdp6, buf, sizeof(buf), 0,
        !          1550:                         (struct sockaddr *)&sendername6, &sendername6_len);
        !          1551:            if(n<0)
        !          1552:            {
        !          1553:                 /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time)
        !          1554:                  * other errors : log to LOG_ERR */
        !          1555:                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
        !          1556:                    syslog(LOG_ERR, "recvfrom: %m");
        !          1557:            }
        !          1558:            else
        !          1559:            {
        !          1560:                /* Parse and process the packet received */
        !          1561:                /*printf("%.*s", n, buf);*/
        !          1562:                i = ParseSSDPPacket(s_ssdp6, buf, n,
        !          1563:                                    (struct sockaddr *)&sendername6, searched_device);
        !          1564:                syslog(LOG_DEBUG, "** i=%d deltadev=%d **", i, deltadev);
        !          1565:                if(i==0 || (i*deltadev < 0))
        !          1566:                {
        !          1567:                    if(deltadev > 0)
        !          1568:                        syslog(LOG_NOTICE, "%d new devices added", deltadev);
        !          1569:                    else if(deltadev < 0)
        !          1570:                        syslog(LOG_NOTICE, "%d devices removed (good-bye!)", -deltadev);
        !          1571:                    deltadev = i;
        !          1572:                }
        !          1573:                else if((i*deltadev) >= 0)
        !          1574:                {
        !          1575:                    deltadev += i;
        !          1576:                }
        !          1577:            }
        !          1578:        }
        !          1579: #endif /* ENABLE_IPV6 */
        !          1580:        if((s_ssdp >= 0) && FD_ISSET(s_ssdp, &readfds))
        !          1581:        {
        !          1582:            sendername_len = sizeof(struct sockaddr_in);
        !          1583:            n = recvfrom(s_ssdp, buf, sizeof(buf), 0,
        !          1584:                         (struct sockaddr *)&sendername, &sendername_len);
        !          1585:            if(n<0)
        !          1586:            {
        !          1587:                 /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time)
        !          1588:                  * other errors : log to LOG_ERR */
        !          1589:                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
        !          1590:                    syslog(LOG_ERR, "recvfrom: %m");
        !          1591:            }
        !          1592:            else
        !          1593:            {
        !          1594:                /* Parse and process the packet received */
        !          1595:                /*printf("%.*s", n, buf);*/
        !          1596:                i = ParseSSDPPacket(s_ssdp, buf, n,
        !          1597:                                    (struct sockaddr *)&sendername, searched_device);
        !          1598:                syslog(LOG_DEBUG, "** i=%d deltadev=%d **", i, deltadev);
        !          1599:                if(i==0 || (i*deltadev < 0))
        !          1600:                {
        !          1601:                    if(deltadev > 0)
        !          1602:                        syslog(LOG_NOTICE, "%d new devices added", deltadev);
        !          1603:                    else if(deltadev < 0)
        !          1604:                        syslog(LOG_NOTICE, "%d devices removed (good-bye!)", -deltadev);
        !          1605:                    deltadev = i;
        !          1606:                }
        !          1607:                else if((i*deltadev) >= 0)
        !          1608:                {
        !          1609:                    deltadev += i;
        !          1610:                }
        !          1611:            }
        !          1612:        }
        !          1613:        /* processing unix socket requests */
        !          1614:        for(req = reqlisthead.lh_first; req;) {
        !          1615:            reqnext = req->entries.le_next;
        !          1616:            if((req->socket >= 0) && FD_ISSET(req->socket, &readfds)) {
        !          1617:                processRequest(req);
        !          1618:            }
        !          1619:            if((req->socket >= 0) && FD_ISSET(req->socket, &writefds)) {
        !          1620:                write_buffer(req);
        !          1621:            }
        !          1622:            if(req->socket < 0) {
        !          1623:                LIST_REMOVE(req, entries);
        !          1624:                free(req->output_buffer);
        !          1625:                free(req);
        !          1626:            }
        !          1627:            req = reqnext;
        !          1628:        }
        !          1629:        /* processing new requests */
        !          1630:        if(FD_ISSET(s_unix, &readfds))
        !          1631:        {
        !          1632:            struct reqelem * tmp;
        !          1633:            int s = accept(s_unix, NULL, NULL);
        !          1634:            if(s < 0) {
        !          1635:                syslog(LOG_ERR, "accept(s_unix): %m");
        !          1636:            } else {
        !          1637:                syslog(LOG_INFO, "(s=%d) new request connection", s);
        !          1638:                if(!set_non_blocking(s))
        !          1639:                    syslog(LOG_WARNING, "Failed to set new socket non blocking : %m");
        !          1640:                tmp = malloc(sizeof(struct reqelem));
        !          1641:                if(!tmp) {
        !          1642:                    syslog(LOG_ERR, "cannot allocate memory for request");
        !          1643:                    close(s);
        !          1644:                } else {
        !          1645:                    memset(tmp, 0, sizeof(struct reqelem));
        !          1646:                    tmp->socket = s;
        !          1647:                    LIST_INSERT_HEAD(&reqlisthead, tmp, entries);
        !          1648:                }
        !          1649:            }
        !          1650:        }
        !          1651:        /* processing route/network interface config changes */
        !          1652:        if((s_ifacewatch >= 0) && FD_ISSET(s_ifacewatch, &readfds)) {
        !          1653:            ProcessInterfaceWatch(s_ifacewatch, s_ssdp, s_ssdp6);
        !          1654:        }
        !          1655:    }
        !          1656:    syslog(LOG_DEBUG, "quitting...");
        !          1657:    finalize_sendto();
        !          1658: 
        !          1659:    /* closing and cleaning everything */
        !          1660: quit:
        !          1661:    if(s_ssdp >= 0) {
        !          1662:        close(s_ssdp);
        !          1663:        s_ssdp = -1;
        !          1664:    }
        !          1665: #ifdef ENABLE_IPV6
        !          1666:    if(s_ssdp6 >= 0) {
        !          1667:        close(s_ssdp6);
        !          1668:        s_ssdp6 = -1;
        !          1669:    }
        !          1670: #endif /* ENABLE_IPV6 */
        !          1671:    if(s_unix >= 0) {
        !          1672:        close(s_unix);
        !          1673:        s_unix = -1;
        !          1674:        if(unlink(sockpath) < 0)
        !          1675:            syslog(LOG_ERR, "unlink(%s): %m", sockpath);
        !          1676:    }
        !          1677:    if(s_ifacewatch >= 0) {
        !          1678:        close(s_ifacewatch);
        !          1679:        s_ifacewatch = -1;
        !          1680:    }
        !          1681:    /* empty LAN interface/address list */
        !          1682:    while(lan_addrs.lh_first != NULL) {
        !          1683:        lan_addr = lan_addrs.lh_first;
        !          1684:        LIST_REMOVE(lan_addrs.lh_first, list);
        !          1685:        free(lan_addr);
        !          1686:    }
        !          1687:    /* empty device list */
        !          1688:    while(devlist != NULL) {
        !          1689:        struct device * next = devlist->next;
        !          1690:        free(devlist);
        !          1691:        devlist = next;
        !          1692:    }
        !          1693:    /* empty service list */
        !          1694:    while(servicelisthead.lh_first != NULL) {
        !          1695:        struct service * serv = servicelisthead.lh_first;
        !          1696:        LIST_REMOVE(servicelisthead.lh_first, entries);
        !          1697:        free(serv->st);
        !          1698:        free(serv->usn);
        !          1699:        free(serv->server);
        !          1700:        free(serv->location);
        !          1701:        free(serv);
        !          1702:    }
        !          1703: #ifndef NO_BACKGROUND_NO_PIDFILE
        !          1704:    if(unlink(pidfilename) < 0)
        !          1705:        syslog(LOG_ERR, "unlink(%s): %m", pidfilename);
        !          1706: #endif
        !          1707:    closelog();
        !          1708:    return ret;
        !          1709: }
        !          1710: 

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