Annotation of embedaddon/miniupnpc/src/miniupnpc.c, revision 1.1.1.1

1.1       misho       1: /* $Id: miniupnpc.c,v 1.159 2021/03/02 23:36:32 nanard Exp $ */
                      2: /* vim: tabstop=4 shiftwidth=4 noexpandtab
                      3:  * Project : miniupnp
                      4:  * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
                      5:  * Author : Thomas BERNARD
                      6:  * copyright (c) 2005-2021 Thomas Bernard
                      7:  * This software is subjet to the conditions detailed in the
                      8:  * provided LICENSE file. */
                      9: #include <stdlib.h>
                     10: #include <stdio.h>
                     11: #include <string.h>
                     12: #ifdef _WIN32
                     13: /* Win32 Specific includes and defines */
                     14: #include <winsock2.h>
                     15: #include <ws2tcpip.h>
                     16: #include <io.h>
                     17: #include <iphlpapi.h>
                     18: #include "win32_snprintf.h"
                     19: #define strdup _strdup
                     20: #ifndef strncasecmp
                     21: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
                     22: #define strncasecmp _memicmp
                     23: #else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
                     24: #define strncasecmp memicmp
                     25: #endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
                     26: #endif /* #ifndef strncasecmp */
                     27: #define MAXHOSTNAMELEN 64
                     28: #else /* #ifdef _WIN32 */
                     29: /* Standard POSIX includes */
                     30: #include <unistd.h>
                     31: #if defined(__amigaos__) && !defined(__amigaos4__)
                     32: /* Amiga OS 3 specific stuff */
                     33: #define socklen_t int
                     34: #else
                     35: #include <sys/select.h>
                     36: #endif
                     37: #include <sys/socket.h>
                     38: #include <sys/types.h>
                     39: #include <sys/param.h>
                     40: #include <netinet/in.h>
                     41: #include <arpa/inet.h>
                     42: #include <netdb.h>
                     43: #include <net/if.h>
                     44: #if !defined(__amigaos__) && !defined(__amigaos4__)
                     45: #include <poll.h>
                     46: #endif
                     47: #include <strings.h>
                     48: #include <errno.h>
                     49: #define closesocket close
                     50: #endif /* #else _WIN32 */
                     51: #ifdef __GNU__
                     52: #define MAXHOSTNAMELEN 64
                     53: #endif
                     54: 
                     55: 
                     56: #include "miniupnpc.h"
                     57: #include "minissdpc.h"
                     58: #include "miniwget.h"
                     59: #include "miniwget_private.h"
                     60: #include "minisoap.h"
                     61: #include "minixml.h"
                     62: #include "upnpcommands.h"
                     63: #include "connecthostport.h"
                     64: #include "addr_is_reserved.h"
                     65: 
                     66: /* compare the beginning of a string with a constant string */
                     67: #define COMPARE(str, cstr) (0==strncmp(str, cstr, sizeof(cstr) - 1))
                     68: 
                     69: #ifndef MAXHOSTNAMELEN
                     70: #define MAXHOSTNAMELEN 64
                     71: #endif
                     72: 
                     73: #define SOAPPREFIX "s"
                     74: #define SERVICEPREFIX "u"
                     75: #define SERVICEPREFIX2 'u'
                     76: 
                     77: /* root description parsing */
                     78: MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
                     79: {
                     80:    struct xmlparser parser;
                     81:    /* xmlparser object */
                     82:    parser.xmlstart = buffer;
                     83:    parser.xmlsize = bufsize;
                     84:    parser.data = data;
                     85:    parser.starteltfunc = IGDstartelt;
                     86:    parser.endeltfunc = IGDendelt;
                     87:    parser.datafunc = IGDdata;
                     88:    parser.attfunc = 0;
                     89:    parsexml(&parser);
                     90: #ifdef DEBUG
                     91:    printIGD(data);
                     92: #endif
                     93: }
                     94: 
                     95: /* simpleUPnPcommand2 :
                     96:  * not so simple !
                     97:  * return values :
                     98:  *   pointer - OK
                     99:  *   NULL - error */
                    100: static char *
                    101: simpleUPnPcommand2(SOCKET s, const char * url, const char * service,
                    102:                    const char * action, struct UPNParg * args,
                    103:                    int * bufsize, const char * httpversion)
                    104: {
                    105:    char hostname[MAXHOSTNAMELEN+1];
                    106:    unsigned short port = 0;
                    107:    char * path;
                    108:    char soapact[128];
                    109:    char soapbody[2048];
                    110:    int soapbodylen;
                    111:    char * buf;
                    112:    int n;
                    113:    int status_code;
                    114: 
                    115:    *bufsize = 0;
                    116:    snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
                    117:    if(args==NULL)
                    118:    {
                    119:        soapbodylen = snprintf(soapbody, sizeof(soapbody),
                    120:                          "<?xml version=\"1.0\"?>\r\n"
                    121:                          "<" SOAPPREFIX ":Envelope "
                    122:                          "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
                    123:                          SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                    124:                          "<" SOAPPREFIX ":Body>"
                    125:                          "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
                    126:                          "</" SERVICEPREFIX ":%s>"
                    127:                          "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
                    128:                          "\r\n", action, service, action);
                    129:        if ((unsigned int)soapbodylen >= sizeof(soapbody))
                    130:            return NULL;
                    131:    }
                    132:    else
                    133:    {
                    134:        char * p;
                    135:        const char * pe, * pv;
                    136:        const char * const pend = soapbody + sizeof(soapbody);
                    137:        soapbodylen = snprintf(soapbody, sizeof(soapbody),
                    138:                        "<?xml version=\"1.0\"?>\r\n"
                    139:                        "<" SOAPPREFIX ":Envelope "
                    140:                        "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
                    141:                        SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                    142:                        "<" SOAPPREFIX ":Body>"
                    143:                        "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">",
                    144:                        action, service);
                    145:        if ((unsigned int)soapbodylen >= sizeof(soapbody))
                    146:            return NULL;
                    147:        p = soapbody + soapbodylen;
                    148:        while(args->elt)
                    149:        {
                    150:            if(p >= pend) /* check for space to write next byte */
                    151:                return NULL;
                    152:            *(p++) = '<';
                    153: 
                    154:            pe = args->elt;
                    155:            while(p < pend && *pe)
                    156:                *(p++) = *(pe++);
                    157: 
                    158:            if(p >= pend) /* check for space to write next byte */
                    159:                return NULL;
                    160:            *(p++) = '>';
                    161: 
                    162:            if((pv = args->val))
                    163:            {
                    164:                while(p < pend && *pv)
                    165:                    *(p++) = *(pv++);
                    166:            }
                    167: 
                    168:            if((p+2) > pend) /* check for space to write next 2 bytes */
                    169:                return NULL;
                    170:            *(p++) = '<';
                    171:            *(p++) = '/';
                    172: 
                    173:            pe = args->elt;
                    174:            while(p < pend && *pe)
                    175:                *(p++) = *(pe++);
                    176: 
                    177:            if(p >= pend) /* check for space to write next byte */
                    178:                return NULL;
                    179:            *(p++) = '>';
                    180: 
                    181:            args++;
                    182:        }
                    183:        if((p+4) > pend) /* check for space to write next 4 bytes */
                    184:            return NULL;
                    185:        *(p++) = '<';
                    186:        *(p++) = '/';
                    187:        *(p++) = SERVICEPREFIX2;
                    188:        *(p++) = ':';
                    189: 
                    190:        pe = action;
                    191:        while(p < pend && *pe)
                    192:            *(p++) = *(pe++);
                    193: 
                    194:        strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
                    195:                pend - p);
                    196:        if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */
                    197:            return NULL;
                    198:    }
                    199:    if(!parseURL(url, hostname, &port, &path, NULL)) return NULL;
                    200:    if(ISINVALID(s)) {
                    201:        s = connecthostport(hostname, port, 0);
                    202:        if(ISINVALID(s)) {
                    203:            /* failed to connect */
                    204:            return NULL;
                    205:        }
                    206:    }
                    207: 
                    208:    n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion);
                    209:    if(n<=0) {
                    210: #ifdef DEBUG
                    211:        printf("Error sending SOAP request\n");
                    212: #endif
                    213:        closesocket(s);
                    214:        return NULL;
                    215:    }
                    216: 
                    217:    buf = getHTTPResponse(s, bufsize, &status_code);
                    218: #ifdef DEBUG
                    219:    if(*bufsize > 0 && buf)
                    220:    {
                    221:        printf("HTTP %d SOAP Response :\n%.*s\n", status_code, *bufsize, buf);
                    222:    }
                    223:    else
                    224:    {
                    225:        printf("HTTP %d, empty SOAP response. size=%d\n", status_code, *bufsize);
                    226:    }
                    227: #endif
                    228:    closesocket(s);
                    229:    return buf;
                    230: }
                    231: 
                    232: /* simpleUPnPcommand :
                    233:  * not so simple !
                    234:  * return values :
                    235:  *   pointer - OK
                    236:  *   NULL    - error */
                    237: char *
                    238: simpleUPnPcommand(int s, const char * url, const char * service,
                    239:                   const char * action, struct UPNParg * args,
                    240:                   int * bufsize)
                    241: {
                    242:    char * buf;
                    243: 
                    244: #if 1
                    245:    buf = simpleUPnPcommand2((SOCKET)s, url, service, action, args, bufsize, "1.1");
                    246: #else
                    247:    buf = simpleUPnPcommand2((SOCKET)s, url, service, action, args, bufsize, "1.0");
                    248:    if (!buf || *bufsize == 0)
                    249:    {
                    250: #if DEBUG
                    251:        printf("Error or no result from SOAP request; retrying with HTTP/1.1\n");
                    252: #endif
                    253:        buf = simpleUPnPcommand2((SOCKET)s, url, service, action, args, bufsize, "1.1");
                    254:    }
                    255: #endif
                    256:    return buf;
                    257: }
                    258: 
                    259: /* upnpDiscoverDevices() :
                    260:  * return a chained list of all devices found or NULL if
                    261:  * no devices was found.
                    262:  * It is up to the caller to free the chained list
                    263:  * delay is in millisecond (poll).
                    264:  * UDA v1.1 says :
                    265:  *   The TTL for the IP packet SHOULD default to 2 and
                    266:  *   SHOULD be configurable. */
                    267: MINIUPNP_LIBSPEC struct UPNPDev *
                    268: upnpDiscoverDevices(const char * const deviceTypes[],
                    269:                     int delay, const char * multicastif,
                    270:                     const char * minissdpdsock, int localport,
                    271:                     int ipv6, unsigned char ttl,
                    272:                     int * error,
                    273:                     int searchalltypes)
                    274: {
                    275:    struct UPNPDev * tmp;
                    276:    struct UPNPDev * devlist = 0;
                    277: #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
                    278:    int deviceIndex;
                    279: #endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
                    280: 
                    281:    if(error)
                    282:        *error = UPNPDISCOVER_UNKNOWN_ERROR;
                    283: #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
                    284:    /* first try to get infos from minissdpd ! */
                    285:    if(!minissdpdsock)
                    286:        minissdpdsock = "/var/run/minissdpd.sock";
                    287:    if(minissdpdsock[0] != '\0') {
                    288:        for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
                    289:            struct UPNPDev * minissdpd_devlist;
                    290:            int only_rootdevice = 1;
                    291:            minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
                    292:                                                        minissdpdsock, 0);
                    293:            if(minissdpd_devlist) {
                    294: #ifdef DEBUG
                    295:                printf("returned by MiniSSDPD: %s\t%s\n",
                    296:                       minissdpd_devlist->st, minissdpd_devlist->descURL);
                    297: #endif /* DEBUG */
                    298:                if(!strstr(minissdpd_devlist->st, "rootdevice"))
                    299:                    only_rootdevice = 0;
                    300:                for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) {
                    301: #ifdef DEBUG
                    302:                    printf("returned by MiniSSDPD: %s\t%s\n",
                    303:                           tmp->pNext->st, tmp->pNext->descURL);
                    304: #endif /* DEBUG */
                    305:                    if(!strstr(tmp->st, "rootdevice"))
                    306:                        only_rootdevice = 0;
                    307:                }
                    308:                tmp->pNext = devlist;
                    309:                devlist = minissdpd_devlist;
                    310:                if(!searchalltypes && !only_rootdevice)
                    311:                    break;
                    312:            }
                    313:        }
                    314:    }
                    315:    for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) {
                    316:        /* We return what we have found if it was not only a rootdevice */
                    317:        if(!strstr(tmp->st, "rootdevice")) {
                    318:            if(error)
                    319:                *error = UPNPDISCOVER_SUCCESS;
                    320:            return devlist;
                    321:        }
                    322:    }
                    323: #else  /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
                    324:    (void)minissdpdsock; /* unused */
                    325: #endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
                    326: 
                    327:    /* direct discovery if minissdpd responses are not sufficient */
                    328:    {
                    329:        struct UPNPDev * discovered_devlist;
                    330:        discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport,
                    331:                                                 ipv6, ttl, error, searchalltypes);
                    332:        if(devlist == NULL)
                    333:            devlist = discovered_devlist;
                    334:        else {
                    335:            for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext);
                    336:            tmp->pNext = discovered_devlist;
                    337:        }
                    338:    }
                    339:    return devlist;
                    340: }
                    341: 
                    342: /* upnpDiscover() Discover IGD device */
                    343: MINIUPNP_LIBSPEC struct UPNPDev *
                    344: upnpDiscover(int delay, const char * multicastif,
                    345:              const char * minissdpdsock, int localport,
                    346:              int ipv6, unsigned char ttl,
                    347:              int * error)
                    348: {
                    349:    static const char * const deviceList[] = {
                    350: #if 0
                    351:        "urn:schemas-upnp-org:device:InternetGatewayDevice:2",
                    352:        "urn:schemas-upnp-org:service:WANIPConnection:2",
                    353: #endif
                    354:        "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
                    355:        "urn:schemas-upnp-org:service:WANIPConnection:1",
                    356:        "urn:schemas-upnp-org:service:WANPPPConnection:1",
                    357:        "upnp:rootdevice",
                    358:        /*"ssdp:all",*/
                    359:        0
                    360:    };
                    361:    return upnpDiscoverDevices(deviceList,
                    362:                               delay, multicastif, minissdpdsock, localport,
                    363:                               ipv6, ttl, error, 0);
                    364: }
                    365: 
                    366: /* upnpDiscoverAll() Discover all UPnP devices */
                    367: MINIUPNP_LIBSPEC struct UPNPDev *
                    368: upnpDiscoverAll(int delay, const char * multicastif,
                    369:                 const char * minissdpdsock, int localport,
                    370:                 int ipv6, unsigned char ttl,
                    371:                 int * error)
                    372: {
                    373:    static const char * const deviceList[] = {
                    374:        /*"upnp:rootdevice",*/
                    375:        "ssdp:all",
                    376:        0
                    377:    };
                    378:    return upnpDiscoverDevices(deviceList,
                    379:                               delay, multicastif, minissdpdsock, localport,
                    380:                               ipv6, ttl, error, 0);
                    381: }
                    382: 
                    383: /* upnpDiscoverDevice() Discover a specific device */
                    384: MINIUPNP_LIBSPEC struct UPNPDev *
                    385: upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
                    386:                 const char * minissdpdsock, int localport,
                    387:                 int ipv6, unsigned char ttl,
                    388:                 int * error)
                    389: {
                    390:    const char * const deviceList[] = {
                    391:        device,
                    392:        0
                    393:    };
                    394:    return upnpDiscoverDevices(deviceList,
                    395:                               delay, multicastif, minissdpdsock, localport,
                    396:                               ipv6, ttl, error, 0);
                    397: }
                    398: 
                    399: static char *
                    400: build_absolute_url(const char * baseurl, const char * descURL,
                    401:                    const char * url, unsigned int scope_id)
                    402: {
                    403:    size_t l, n;
                    404:    char * s;
                    405:    const char * base;
                    406:    char * p;
                    407: #if defined(IF_NAMESIZE) && !defined(_WIN32)
                    408:    char ifname[IF_NAMESIZE];
                    409: #else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
                    410:    char scope_str[8];
                    411: #endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
                    412: 
                    413:    if(  (url[0] == 'h')
                    414:       &&(url[1] == 't')
                    415:       &&(url[2] == 't')
                    416:       &&(url[3] == 'p')
                    417:       &&(url[4] == ':')
                    418:       &&(url[5] == '/')
                    419:       &&(url[6] == '/'))
                    420:        return strdup(url);
                    421:    base = (baseurl[0] == '\0') ? descURL : baseurl;
                    422:    n = strlen(base);
                    423:    if(n > 7) {
                    424:        p = strchr(base + 7, '/');
                    425:        if(p)
                    426:            n = p - base;
                    427:    }
                    428:    l = n + strlen(url) + 1;
                    429:    if(url[0] != '/')
                    430:        l++;
                    431:    if(scope_id != 0) {
                    432: #if defined(IF_NAMESIZE) && !defined(_WIN32)
                    433:        if(if_indextoname(scope_id, ifname)) {
                    434:            l += 3 + strlen(ifname);    /* 3 == strlen(%25) */
                    435:        }
                    436: #else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
                    437:        /* under windows, scope is numerical */
                    438:        l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
                    439: #endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
                    440:    }
                    441:    s = malloc(l);
                    442:    if(s == NULL) return NULL;
                    443:    memcpy(s, base, n);
                    444:    if(scope_id != 0) {
                    445:        s[n] = '\0';
                    446:        if(n > 13 && 0 == memcmp(s, "http://[fe80:", 13)) {
                    447:            /* this is a linklocal IPv6 address */
                    448:            p = strchr(s, ']');
                    449:            if(p) {
                    450:                /* insert %25<scope> into URL */
                    451: #if defined(IF_NAMESIZE) && !defined(_WIN32)
                    452:                memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
                    453:                memcpy(p, "%25", 3);
                    454:                memcpy(p + 3, ifname, strlen(ifname));
                    455:                n += 3 + strlen(ifname);
                    456: #else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
                    457:                memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
                    458:                memcpy(p, "%25", 3);
                    459:                memcpy(p + 3, scope_str, strlen(scope_str));
                    460:                n += 3 + strlen(scope_str);
                    461: #endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
                    462:            }
                    463:        }
                    464:    }
                    465:    if(url[0] != '/')
                    466:        s[n++] = '/';
                    467:    memcpy(s + n, url, l - n);
                    468:    return s;
                    469: }
                    470: 
                    471: /* Prepare the Urls for usage...
                    472:  */
                    473: MINIUPNP_LIBSPEC void
                    474: GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
                    475:             const char * descURL, unsigned int scope_id)
                    476: {
                    477:    /* strdup descURL */
                    478:    urls->rootdescURL = strdup(descURL);
                    479: 
                    480:    /* get description of WANIPConnection */
                    481:    urls->ipcondescURL = build_absolute_url(data->urlbase, descURL,
                    482:                                            data->first.scpdurl, scope_id);
                    483:    urls->controlURL = build_absolute_url(data->urlbase, descURL,
                    484:                                          data->first.controlurl, scope_id);
                    485:    urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL,
                    486:                                              data->CIF.controlurl, scope_id);
                    487:    urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL,
                    488:                                              data->IPv6FC.controlurl, scope_id);
                    489: 
                    490: #ifdef DEBUG
                    491:    printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL);
                    492:    printf("urls->controlURL='%s'\n", urls->controlURL);
                    493:    printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF);
                    494:    printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC);
                    495: #endif
                    496: }
                    497: 
                    498: MINIUPNP_LIBSPEC void
                    499: FreeUPNPUrls(struct UPNPUrls * urls)
                    500: {
                    501:    if(!urls)
                    502:        return;
                    503:    free(urls->controlURL);
                    504:    urls->controlURL = 0;
                    505:    free(urls->ipcondescURL);
                    506:    urls->ipcondescURL = 0;
                    507:    free(urls->controlURL_CIF);
                    508:    urls->controlURL_CIF = 0;
                    509:    free(urls->controlURL_6FC);
                    510:    urls->controlURL_6FC = 0;
                    511:    free(urls->rootdescURL);
                    512:    urls->rootdescURL = 0;
                    513: }
                    514: 
                    515: int
                    516: UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
                    517: {
                    518:    char status[64];
                    519:    unsigned int uptime;
                    520:    status[0] = '\0';
                    521:    UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
                    522:                       status, &uptime, NULL);
                    523:    if(0 == strcmp("Connected", status))
                    524:        return 1;
                    525:    else if(0 == strcmp("Up", status))  /* Also accept "Up" */
                    526:        return 1;
                    527:    else
                    528:        return 0;
                    529: }
                    530: 
                    531: 
                    532: /* UPNP_GetValidIGD() :
                    533:  * return values :
                    534:  *    -1 = Internal error
                    535:  *     0 = NO IGD found
                    536:  *     1 = A valid connected IGD has been found
                    537:  *     2 = A valid IGD has been found but it reported as
                    538:  *         not connected
                    539:  *     3 = an UPnP device has been found but was not recognized as an IGD
                    540:  *
                    541:  * In any positive non zero return case, the urls and data structures
                    542:  * passed as parameters are set. Don't forget to call FreeUPNPUrls(urls) to
                    543:  * free allocated memory.
                    544:  */
                    545: MINIUPNP_LIBSPEC int
                    546: UPNP_GetValidIGD(struct UPNPDev * devlist,
                    547:                  struct UPNPUrls * urls,
                    548:                 struct IGDdatas * data,
                    549:                 char * lanaddr, int lanaddrlen)
                    550: {
                    551:    struct xml_desc {
                    552:        char lanaddr[40];
                    553:        char * xml;
                    554:        int size;
                    555:        int is_igd;
                    556:    } * desc = NULL;
                    557:    struct UPNPDev * dev;
                    558:    int ndev = 0;
                    559:    int i;
                    560:    int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
                    561:    char extIpAddr[16];
                    562:    int status_code = -1;
                    563: 
                    564:    if(!devlist)
                    565:    {
                    566: #ifdef DEBUG
                    567:        printf("Empty devlist\n");
                    568: #endif
                    569:        return 0;
                    570:    }
                    571:    /* counting total number of devices in the list */
                    572:    for(dev = devlist; dev; dev = dev->pNext)
                    573:        ndev++;
                    574:    /* ndev is always > 0 */
                    575:    desc = calloc(ndev, sizeof(struct xml_desc));
                    576:    if(!desc)
                    577:        return -1; /* memory allocation error */
                    578:    /* Step 1 : downloading descriptions and testing type */
                    579:    for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
                    580:    {
                    581:        /* we should choose an internet gateway device.
                    582:         * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
                    583:        desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size),
                    584:                                       desc[i].lanaddr, sizeof(desc[i].lanaddr),
                    585:                                       dev->scope_id, &status_code);
                    586: #ifdef DEBUG
                    587:        if(!desc[i].xml)
                    588:        {
                    589:            printf("error getting XML description %s\n", dev->descURL);
                    590:        }
                    591: #endif
                    592:        if(desc[i].xml)
                    593:        {
                    594:            memset(data, 0, sizeof(struct IGDdatas));
                    595:            memset(urls, 0, sizeof(struct UPNPUrls));
                    596:            parserootdesc(desc[i].xml, desc[i].size, data);
                    597:            if(COMPARE(data->CIF.servicetype,
                    598:                       "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))
                    599:            {
                    600:                desc[i].is_igd = 1;
                    601:            }
                    602:        }
                    603:    }
                    604:    /* iterate the list to find a device depending on state */
                    605:    for(state = 1; state <= 3; state++)
                    606:    {
                    607:        for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
                    608:        {
                    609:            if(desc[i].xml)
                    610:            {
                    611:                memset(data, 0, sizeof(struct IGDdatas));
                    612:                memset(urls, 0, sizeof(struct UPNPUrls));
                    613:                parserootdesc(desc[i].xml, desc[i].size, data);
                    614:                if(desc[i].is_igd || state >= 3 )
                    615:                {
                    616:                  int is_connected;
                    617: 
                    618:                  GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
                    619: 
                    620:                  /* in state 2 and 3 we don't test if device is connected ! */
                    621:                  if(state >= 2)
                    622:                    goto free_and_return;
                    623:                  is_connected = UPNPIGD_IsConnected(urls, data);
                    624: #ifdef DEBUG
                    625:                  printf("UPNPIGD_IsConnected(%s) = %d\n",
                    626:                     urls->controlURL, is_connected);
                    627: #endif
                    628:                  /* checks that status is connected AND there is a external IP address assigned */
                    629:                  if(is_connected &&
                    630:                     (UPNP_GetExternalIPAddress(urls->controlURL,  data->first.servicetype, extIpAddr) == 0)) {
                    631:                    if(!addr_is_reserved(extIpAddr))
                    632:                      goto free_and_return;
                    633:                  }
                    634:                  FreeUPNPUrls(urls);
                    635:                  if(data->second.servicetype[0] != '\0') {
                    636: #ifdef DEBUG
                    637:                    printf("We tried %s, now we try %s !\n",
                    638:                           data->first.servicetype, data->second.servicetype);
                    639: #endif
                    640:                    /* swaping WANPPPConnection and WANIPConnection ! */
                    641:                    memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service));
                    642:                    memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service));
                    643:                    memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service));
                    644:                    GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
                    645:                    is_connected = UPNPIGD_IsConnected(urls, data);
                    646: #ifdef DEBUG
                    647:                    printf("UPNPIGD_IsConnected(%s) = %d\n",
                    648:                       urls->controlURL, is_connected);
                    649: #endif
                    650:                    if(is_connected &&
                    651:                       (UPNP_GetExternalIPAddress(urls->controlURL,  data->first.servicetype, extIpAddr) == 0)) {
                    652:                      if(!addr_is_reserved(extIpAddr))
                    653:                        goto free_and_return;
                    654:                    }
                    655:                    FreeUPNPUrls(urls);
                    656:                  }
                    657:                }
                    658:                memset(data, 0, sizeof(struct IGDdatas));
                    659:            }
                    660:        }
                    661:    }
                    662:    state = 0;
                    663: free_and_return:
                    664:    if (lanaddr != NULL && state >= 1 && state <= 3 && i < ndev)
                    665:        strncpy(lanaddr, desc[i].lanaddr, lanaddrlen);
                    666:    for(i = 0; i < ndev; i++)
                    667:        free(desc[i].xml);
                    668:    free(desc);
                    669:    return state;
                    670: }
                    671: 
                    672: /* UPNP_GetIGDFromUrl()
                    673:  * Used when skipping the discovery process.
                    674:  * return value :
                    675:  *   0 - Not ok
                    676:  *   1 - OK */
                    677: int
                    678: UPNP_GetIGDFromUrl(const char * rootdescurl,
                    679:                    struct UPNPUrls * urls,
                    680:                    struct IGDdatas * data,
                    681:                    char * lanaddr, int lanaddrlen)
                    682: {
                    683:    char * descXML;
                    684:    int descXMLsize = 0;
                    685: 
                    686:    descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
                    687:                               lanaddr, lanaddrlen, 0, NULL);
                    688:    if(descXML) {
                    689:        memset(data, 0, sizeof(struct IGDdatas));
                    690:        memset(urls, 0, sizeof(struct UPNPUrls));
                    691:        parserootdesc(descXML, descXMLsize, data);
                    692:        free(descXML);
                    693:        GetUPNPUrls(urls, data, rootdescurl, 0);
                    694:        return 1;
                    695:    } else {
                    696:        return 0;
                    697:    }
                    698: }

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