Annotation of embedaddon/miniupnpc/src/miniupnpc.c, revision 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>