Annotation of embedaddon/miniupnpc/miniupnpc.c, revision 1.1

1.1     ! misho       1: /* $Id: miniupnpc.c,v 1.95 2011/05/15 21:42:26 nanard Exp $ */
        !             2: /* Project : miniupnp
        !             3:  * Author : Thomas BERNARD
        !             4:  * copyright (c) 2005-2011 Thomas Bernard
        !             5:  * This software is subjet to the conditions detailed in the
        !             6:  * provided LICENSE file. */
        !             7: #define __EXTENSIONS__ 1
        !             8: #if !defined(MACOSX) && !defined(__sun)
        !             9: #if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__)
        !            10: #ifndef __cplusplus
        !            11: #define _XOPEN_SOURCE 600
        !            12: #endif
        !            13: #endif
        !            14: #ifndef __BSD_VISIBLE
        !            15: #define __BSD_VISIBLE 1
        !            16: #endif
        !            17: #endif
        !            18: 
        !            19: #include <stdlib.h>
        !            20: #include <stdio.h>
        !            21: #include <string.h>
        !            22: #ifdef WIN32
        !            23: /* Win32 Specific includes and defines */
        !            24: #include <winsock2.h>
        !            25: #include <ws2tcpip.h>
        !            26: #include <io.h>
        !            27: #include <iphlpapi.h>
        !            28: #define snprintf _snprintf
        !            29: #ifndef strncasecmp
        !            30: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
        !            31: #define strncasecmp _memicmp
        !            32: #else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
        !            33: #define strncasecmp memicmp
        !            34: #endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
        !            35: #endif /* #ifndef strncasecmp */
        !            36: #define MAXHOSTNAMELEN 64
        !            37: #else /* #ifdef WIN32 */
        !            38: /* Standard POSIX includes */
        !            39: #include <unistd.h>
        !            40: #if defined(__amigaos__) && !defined(__amigaos4__)
        !            41: /* Amiga OS 3 specific stuff */
        !            42: #define socklen_t int
        !            43: #else
        !            44: #include <sys/select.h>
        !            45: #endif
        !            46: #include <sys/socket.h>
        !            47: #include <sys/types.h>
        !            48: #include <sys/param.h>
        !            49: #include <netinet/in.h>
        !            50: #include <arpa/inet.h>
        !            51: #include <netdb.h>
        !            52: #include <net/if.h>
        !            53: #if !defined(__amigaos__) && !defined(__amigaos4__)
        !            54: #include <poll.h>
        !            55: #endif
        !            56: #include <strings.h>
        !            57: #include <errno.h>
        !            58: #define closesocket close
        !            59: #endif /* #else WIN32 */
        !            60: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
        !            61: #include <sys/time.h>
        !            62: #endif
        !            63: #if defined(__amigaos__) || defined(__amigaos4__)
        !            64: /* Amiga OS specific stuff */
        !            65: #define TIMEVAL struct timeval
        !            66: #endif
        !            67: 
        !            68: #include "miniupnpc.h"
        !            69: #include "minissdpc.h"
        !            70: #include "miniwget.h"
        !            71: #include "minisoap.h"
        !            72: #include "minixml.h"
        !            73: #include "upnpcommands.h"
        !            74: #include "connecthostport.h"
        !            75: #include "receivedata.h"
        !            76: 
        !            77: #ifdef WIN32
        !            78: #define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, WSAGetLastError());
        !            79: #else
        !            80: #define PRINT_SOCKET_ERROR(x) perror(x)
        !            81: #endif
        !            82: 
        !            83: #define SOAPPREFIX "s"
        !            84: #define SERVICEPREFIX "u"
        !            85: #define SERVICEPREFIX2 'u'
        !            86: 
        !            87: /* root description parsing */
        !            88: LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
        !            89: {
        !            90:        struct xmlparser parser;
        !            91:        /* xmlparser object */
        !            92:        parser.xmlstart = buffer;
        !            93:        parser.xmlsize = bufsize;
        !            94:        parser.data = data;
        !            95:        parser.starteltfunc = IGDstartelt;
        !            96:        parser.endeltfunc = IGDendelt;
        !            97:        parser.datafunc = IGDdata;
        !            98:        parser.attfunc = 0;
        !            99:        parsexml(&parser);
        !           100: #ifdef DEBUG
        !           101:        printIGD(data);
        !           102: #endif
        !           103: }
        !           104: 
        !           105: /* simpleUPnPcommand2 :
        !           106:  * not so simple !
        !           107:  * return values :
        !           108:  *   pointer - OK
        !           109:  *   NULL - error */
        !           110: char * simpleUPnPcommand2(int s, const char * url, const char * service,
        !           111:                       const char * action, struct UPNParg * args,
        !           112:                       int * bufsize, const char * httpversion)
        !           113: {
        !           114:        char hostname[MAXHOSTNAMELEN+1];
        !           115:        unsigned short port = 0;
        !           116:        char * path;
        !           117:        char soapact[128];
        !           118:        char soapbody[2048];
        !           119:        char * buf;
        !           120:     int n;
        !           121: 
        !           122:        *bufsize = 0;
        !           123:        snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
        !           124:        if(args==NULL)
        !           125:        {
        !           126:                /*soapbodylen = */snprintf(soapbody, sizeof(soapbody),
        !           127:                                                "<?xml version=\"1.0\"?>\r\n"
        !           128:                              "<" SOAPPREFIX ":Envelope "
        !           129:                                                  "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
        !           130:                                                  SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
        !           131:                                                  "<" SOAPPREFIX ":Body>"
        !           132:                                                  "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
        !           133:                                                  "</" SERVICEPREFIX ":%s>"
        !           134:                                                  "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
        !           135:                                                  "\r\n", action, service, action);
        !           136:        }
        !           137:        else
        !           138:        {
        !           139:                char * p;
        !           140:                const char * pe, * pv;
        !           141:                int soapbodylen;
        !           142:                soapbodylen = snprintf(soapbody, sizeof(soapbody),
        !           143:                                                "<?xml version=\"1.0\"?>\r\n"
        !           144:                            "<" SOAPPREFIX ":Envelope "
        !           145:                                                "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
        !           146:                                                SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
        !           147:                                                "<" SOAPPREFIX ":Body>"
        !           148:                                                "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">",
        !           149:                                                action, service);
        !           150:                p = soapbody + soapbodylen;
        !           151:                while(args->elt)
        !           152:                {
        !           153:                        /* check that we are never overflowing the string... */
        !           154:                        if(soapbody + sizeof(soapbody) <= p + 100)
        !           155:                        {
        !           156:                                /* we keep a margin of at least 100 bytes */
        !           157:                                return NULL;
        !           158:                        }
        !           159:                        *(p++) = '<';
        !           160:                        pe = args->elt;
        !           161:                        while(*pe)
        !           162:                                *(p++) = *(pe++);
        !           163:                        *(p++) = '>';
        !           164:                        if((pv = args->val))
        !           165:                        {
        !           166:                                while(*pv)
        !           167:                                        *(p++) = *(pv++);
        !           168:                        }
        !           169:                        *(p++) = '<';
        !           170:                        *(p++) = '/';
        !           171:                        pe = args->elt;
        !           172:                        while(*pe)
        !           173:                                *(p++) = *(pe++);
        !           174:                        *(p++) = '>';
        !           175:                        args++;
        !           176:                }
        !           177:                *(p++) = '<';
        !           178:                *(p++) = '/';
        !           179:                *(p++) = SERVICEPREFIX2;
        !           180:                *(p++) = ':';
        !           181:                pe = action;
        !           182:                while(*pe)
        !           183:                        *(p++) = *(pe++);
        !           184:                strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
        !           185:                        soapbody + sizeof(soapbody) - p);
        !           186:        }
        !           187:        if(!parseURL(url, hostname, &port, &path)) return NULL;
        !           188:        if(s<0)
        !           189:        {
        !           190:                s = connecthostport(hostname, port);
        !           191:                if(s < 0)
        !           192:                {
        !           193:                        return NULL;
        !           194:                }
        !           195:        }
        !           196: 
        !           197:        n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion);
        !           198:        if(n<=0) {
        !           199: #ifdef DEBUG
        !           200:                printf("Error sending SOAP request\n");
        !           201: #endif
        !           202:                closesocket(s);
        !           203:                return NULL;
        !           204:        }
        !           205: 
        !           206:        buf = getHTTPResponse(s, bufsize);
        !           207: #ifdef DEBUG
        !           208:        if(*bufsize > 0 && buf)
        !           209:        {
        !           210:                printf("SOAP Response :\n%.*s\n", *bufsize, buf);
        !           211:        }
        !           212: #endif
        !           213:        closesocket(s);
        !           214:        return buf;
        !           215: }
        !           216: 
        !           217: /* simpleUPnPcommand :
        !           218:  * not so simple !
        !           219:  * return values :
        !           220:  *   pointer - OK
        !           221:  *   NULL    - error */
        !           222: char * simpleUPnPcommand(int s, const char * url, const char * service,
        !           223:                       const char * action, struct UPNParg * args,
        !           224:                       int * bufsize)
        !           225: {
        !           226:        char * buf;
        !           227: 
        !           228:        buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1");
        !           229: /*
        !           230:        buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0");
        !           231:        if (!buf || *bufsize == 0)
        !           232:        {
        !           233: #if DEBUG
        !           234:            printf("Error or no result from SOAP request; retrying with HTTP/1.1\n");
        !           235: #endif
        !           236:                buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1");
        !           237:        }
        !           238: */
        !           239:        return buf;
        !           240: }
        !           241: 
        !           242: /* parseMSEARCHReply()
        !           243:  * the last 4 arguments are filled during the parsing :
        !           244:  *    - location/locationsize : "location:" field of the SSDP reply packet
        !           245:  *    - st/stsize : "st:" field of the SSDP reply packet.
        !           246:  * The strings are NOT null terminated */
        !           247: static void
        !           248: parseMSEARCHReply(const char * reply, int size,
        !           249:                   const char * * location, int * locationsize,
        !           250:                              const char * * st, int * stsize)
        !           251: {
        !           252:        int a, b, i;
        !           253:        i = 0;
        !           254:        a = i;  /* start of the line */
        !           255:        b = 0;  /* end of the "header" (position of the colon) */
        !           256:        while(i<size)
        !           257:        {
        !           258:                switch(reply[i])
        !           259:                {
        !           260:                case ':':
        !           261:                                if(b==0)
        !           262:                                {
        !           263:                                        b = i; /* end of the "header" */
        !           264:                                        /*for(j=a; j<b; j++)
        !           265:                                        {
        !           266:                                                putchar(reply[j]);
        !           267:                                        }
        !           268:                                        */
        !           269:                                }
        !           270:                                break;
        !           271:                case '\x0a':
        !           272:                case '\x0d':
        !           273:                                if(b!=0)
        !           274:                                {
        !           275:                                        /*for(j=b+1; j<i; j++)
        !           276:                                        {
        !           277:                                                putchar(reply[j]);
        !           278:                                        }
        !           279:                                        putchar('\n');*/
        !           280:                                        /* skip the colon and white spaces */
        !           281:                                        do { b++; } while(reply[b]==' ');
        !           282:                                        if(0==strncasecmp(reply+a, "location", 8))
        !           283:                                        {
        !           284:                                                *location = reply+b;
        !           285:                                                *locationsize = i-b;
        !           286:                                        }
        !           287:                                        else if(0==strncasecmp(reply+a, "st", 2))
        !           288:                                        {
        !           289:                                                *st = reply+b;
        !           290:                                                *stsize = i-b;
        !           291:                                        }
        !           292:                                        b = 0;
        !           293:                                }
        !           294:                                a = i+1;
        !           295:                                break;
        !           296:                default:
        !           297:                                break;
        !           298:                }
        !           299:                i++;
        !           300:        }
        !           301: }
        !           302: 
        !           303: /* port upnp discover : SSDP protocol */
        !           304: #define PORT 1900
        !           305: #define XSTR(s) STR(s)
        !           306: #define STR(s) #s
        !           307: #define UPNP_MCAST_ADDR "239.255.255.250"
        !           308: /* for IPv6 */
        !           309: #define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
        !           310: #define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
        !           311: 
        !           312: /* upnpDiscover() :
        !           313:  * return a chained list of all devices found or NULL if
        !           314:  * no devices was found.
        !           315:  * It is up to the caller to free the chained list
        !           316:  * delay is in millisecond (poll) */
        !           317: LIBSPEC struct UPNPDev *
        !           318: upnpDiscover(int delay, const char * multicastif,
        !           319:              const char * minissdpdsock, int sameport,
        !           320:              int ipv6,
        !           321:              int * error)
        !           322: {
        !           323:        struct UPNPDev * tmp;
        !           324:        struct UPNPDev * devlist = 0;
        !           325:        int opt = 1;
        !           326:        static const char MSearchMsgFmt[] = 
        !           327:        "M-SEARCH * HTTP/1.1\r\n"
        !           328:        "HOST: %s:" XSTR(PORT) "\r\n"
        !           329:        "ST: %s\r\n"
        !           330:        "MAN: \"ssdp:discover\"\r\n"
        !           331:        "MX: %u\r\n"
        !           332:        "\r\n";
        !           333:        static const char * const deviceList[] = {
        !           334: #if 0
        !           335:                "urn:schemas-upnp-org:device:InternetGatewayDevice:2",
        !           336:                "urn:schemas-upnp-org:service:WANIPConnection:2",
        !           337: #endif
        !           338:                "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
        !           339:                "urn:schemas-upnp-org:service:WANIPConnection:1",
        !           340:                "urn:schemas-upnp-org:service:WANPPPConnection:1",
        !           341:                "upnp:rootdevice",
        !           342:                0
        !           343:        };
        !           344:        int deviceIndex = 0;
        !           345:        char bufr[1536];        /* reception and emission buffer */
        !           346:        int sudp;
        !           347:        int n;
        !           348:        struct sockaddr_storage sockudp_r;
        !           349:        unsigned int mx;
        !           350: #ifdef NO_GETADDRINFO
        !           351:        struct sockaddr_storage sockudp_w;
        !           352: #else
        !           353:        int rv;
        !           354:        struct addrinfo hints, *servinfo, *p;
        !           355: #endif
        !           356: #ifdef WIN32
        !           357:        MIB_IPFORWARDROW ip_forward;
        !           358: #endif
        !           359:        int linklocal = 1;
        !           360: 
        !           361:        if(error)
        !           362:                *error = UPNPDISCOVER_UNKNOWN_ERROR;
        !           363: #if !defined(WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
        !           364:        /* first try to get infos from minissdpd ! */
        !           365:        if(!minissdpdsock)
        !           366:                minissdpdsock = "/var/run/minissdpd.sock";
        !           367:        while(!devlist && deviceList[deviceIndex]) {
        !           368:                devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex],
        !           369:                                                  minissdpdsock);
        !           370:                /* We return what we have found if it was not only a rootdevice */
        !           371:                if(devlist && !strstr(deviceList[deviceIndex], "rootdevice")) {
        !           372:                        if(error)
        !           373:                                *error = UPNPDISCOVER_SUCCESS;
        !           374:                        return devlist;
        !           375:                }
        !           376:                deviceIndex++;
        !           377:        }
        !           378:        deviceIndex = 0;
        !           379: #endif
        !           380:        /* fallback to direct discovery */
        !           381: #ifdef WIN32
        !           382:        sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
        !           383: #else
        !           384:        sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
        !           385: #endif
        !           386:        if(sudp < 0)
        !           387:        {
        !           388:                if(error)
        !           389:                        *error = UPNPDISCOVER_SOCKET_ERROR;
        !           390:                PRINT_SOCKET_ERROR("socket");
        !           391:                return NULL;
        !           392:        }
        !           393:        /* reception */
        !           394:        memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
        !           395:        if(ipv6) {
        !           396:                struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
        !           397:                p->sin6_family = AF_INET6;
        !           398:                if(sameport)
        !           399:                        p->sin6_port = htons(PORT);
        !           400:                p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
        !           401:        } else {
        !           402:                struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
        !           403:                p->sin_family = AF_INET;
        !           404:                if(sameport)
        !           405:                        p->sin_port = htons(PORT);
        !           406:                p->sin_addr.s_addr = INADDR_ANY;
        !           407:        }
        !           408: #ifdef WIN32
        !           409: /* This code could help us to use the right Network interface for 
        !           410:  * SSDP multicast traffic */
        !           411: /* Get IP associated with the index given in the ip_forward struct
        !           412:  * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
        !           413:        if(!ipv6
        !           414:           && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
        !           415:                DWORD dwRetVal = 0;
        !           416:                PMIB_IPADDRTABLE pIPAddrTable;
        !           417:                DWORD dwSize = 0;
        !           418: #ifdef DEBUG
        !           419:                IN_ADDR IPAddr;
        !           420: #endif
        !           421:                int i;
        !           422: #ifdef DEBUG
        !           423:                printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
        !           424: #endif
        !           425:                pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
        !           426:                if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
        !           427:                        free(pIPAddrTable);
        !           428:                        pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
        !           429:                }
        !           430:                if(pIPAddrTable) {
        !           431:                        dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
        !           432: #ifdef DEBUG
        !           433:                        printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
        !           434: #endif
        !           435:                        for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
        !           436: #ifdef DEBUG
        !           437:                                printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
        !           438:                                IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
        !           439:                                printf("\tIP Address[%d]:     \t%s\n", i, inet_ntoa(IPAddr) );
        !           440:                                IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
        !           441:                                printf("\tSubnet Mask[%d]:    \t%s\n", i, inet_ntoa(IPAddr) );
        !           442:                                IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
        !           443:                                printf("\tBroadCast[%d]:      \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
        !           444:                                printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
        !           445:                                printf("\tType and State[%d]:", i);
        !           446:                                printf("\n");
        !           447: #endif
        !           448:                                if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
        !           449:                                        /* Set the address of this interface to be used */
        !           450:                                        struct in_addr mc_if;
        !           451:                                        memset(&mc_if, 0, sizeof(mc_if));
        !           452:                                        mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
        !           453:                                        if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
        !           454:                                                PRINT_SOCKET_ERROR("setsockopt");
        !           455:                                        }
        !           456:                                        ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
        !           457: #ifndef DEBUG
        !           458:                                        break;
        !           459: #endif
        !           460:                                }
        !           461:                        }
        !           462:                        free(pIPAddrTable);
        !           463:                        pIPAddrTable = NULL;
        !           464:                }
        !           465:        }
        !           466: #endif
        !           467: 
        !           468: #ifdef WIN32
        !           469:        if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
        !           470: #else
        !           471:        if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
        !           472: #endif
        !           473:        {
        !           474:                if(error)
        !           475:                        *error = UPNPDISCOVER_SOCKET_ERROR;
        !           476:                PRINT_SOCKET_ERROR("setsockopt");
        !           477:                return NULL;
        !           478:        }
        !           479: 
        !           480:        if(multicastif)
        !           481:        {
        !           482:                if(ipv6) {
        !           483: #if !defined(WIN32)
        !           484:                        /* according to MSDN, if_nametoindex() is supported since
        !           485:                         * MS Windows Vista and MS Windows Server 2008.
        !           486:                         * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
        !           487:                        unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
        !           488:                        if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0)
        !           489:                        {
        !           490:                                PRINT_SOCKET_ERROR("setsockopt");
        !           491:                        }
        !           492: #else
        !           493: #ifdef DEBUG
        !           494:                        printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
        !           495: #endif
        !           496: #endif
        !           497:                } else {
        !           498:                        struct in_addr mc_if;
        !           499:                        mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
        !           500:                        ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
        !           501:                        if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
        !           502:                        {
        !           503:                                PRINT_SOCKET_ERROR("setsockopt");
        !           504:                        }
        !           505:                }
        !           506:        }
        !           507: 
        !           508:        /* Avant d'envoyer le paquet on bind pour recevoir la reponse */
        !           509:     if (bind(sudp, (const struct sockaddr *)&sockudp_r,
        !           510:                 ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
        !           511:        {
        !           512:                if(error)
        !           513:                        *error = UPNPDISCOVER_SOCKET_ERROR;
        !           514:         PRINT_SOCKET_ERROR("bind");
        !           515:                closesocket(sudp);
        !           516:                return NULL;
        !           517:     }
        !           518: 
        !           519:        if(error)
        !           520:                *error = UPNPDISCOVER_SUCCESS;
        !           521:        /* Calculating maximum response time in seconds */
        !           522:        mx = ((unsigned int)delay) / 1000u;
        !           523:        /* receiving SSDP response packet */
        !           524:        for(n = 0; deviceList[deviceIndex]; deviceIndex++)
        !           525:        {
        !           526:        if(n == 0)
        !           527:        {
        !           528:                /* sending the SSDP M-SEARCH packet */
        !           529:                n = snprintf(bufr, sizeof(bufr),
        !           530:                             MSearchMsgFmt,
        !           531:                             ipv6 ?
        !           532:                             (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" :  "[" UPNP_MCAST_SL_ADDR "]")
        !           533:                             : UPNP_MCAST_ADDR,
        !           534:                             deviceList[deviceIndex], mx);
        !           535: #ifdef DEBUG
        !           536:                printf("Sending %s", bufr);
        !           537: #endif
        !           538: #ifdef NO_GETADDRINFO
        !           539:                /* the following code is not using getaddrinfo */
        !           540:                /* emission */
        !           541:                memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
        !           542:                if(ipv6) {
        !           543:                        struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
        !           544:                        p->sin6_family = AF_INET6;
        !           545:                        p->sin6_port = htons(PORT);
        !           546:                        inet_pton(AF_INET6,
        !           547:                                  linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
        !           548:                                  &(p->sin6_addr));
        !           549:                } else {
        !           550:                        struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
        !           551:                        p->sin_family = AF_INET;
        !           552:                        p->sin_port = htons(PORT);
        !           553:                        p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
        !           554:                }
        !           555:                n = sendto(sudp, bufr, n, 0,
        !           556:                           &sockudp_w,
        !           557:                           ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
        !           558:                if (n < 0) {
        !           559:                        if(error)
        !           560:                                *error = UPNPDISCOVER_SOCKET_ERROR;
        !           561:                        PRINT_SOCKET_ERROR("sendto");
        !           562:                        break;
        !           563:                }
        !           564: #else /* #ifdef NO_GETADDRINFO */
        !           565:                memset(&hints, 0, sizeof(hints));
        !           566:                hints.ai_family = AF_UNSPEC; // AF_INET6 or AF_INET
        !           567:                hints.ai_socktype = SOCK_DGRAM;
        !           568:                /*hints.ai_flags = */
        !           569:                if ((rv = getaddrinfo(ipv6
        !           570:                                      ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
        !           571:                                      : UPNP_MCAST_ADDR,
        !           572:                                      XSTR(PORT), &hints, &servinfo)) != 0) {
        !           573:                        if(error)
        !           574:                                *error = UPNPDISCOVER_SOCKET_ERROR;
        !           575: #ifdef WIN32
        !           576:                    fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
        !           577: #else
        !           578:                    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        !           579: #endif
        !           580:                        break;
        !           581:                }
        !           582:                for(p = servinfo; p; p = p->ai_next) {
        !           583:                        n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
        !           584:                        if (n < 0) {
        !           585:                                PRINT_SOCKET_ERROR("sendto");
        !           586:                                continue;
        !           587:                        }
        !           588:                }
        !           589:                freeaddrinfo(servinfo);
        !           590:                if(n < 0) {
        !           591:                        if(error)
        !           592:                                *error = UPNPDISCOVER_SOCKET_ERROR;
        !           593:                        break;
        !           594:                }
        !           595: #endif /* #ifdef NO_GETADDRINFO */
        !           596:        }
        !           597:        /* Waiting for SSDP REPLY packet to M-SEARCH */
        !           598:        n = receivedata(sudp, bufr, sizeof(bufr), delay);
        !           599:        if (n < 0) {
        !           600:                /* error */
        !           601:                if(error)
        !           602:                        *error = UPNPDISCOVER_SOCKET_ERROR;
        !           603:                break;
        !           604:        } else if (n == 0) {
        !           605:                /* no data or Time Out */
        !           606:                if (devlist) {
        !           607:                        /* no more device type to look for... */
        !           608:                        if(error)
        !           609:                                *error = UPNPDISCOVER_SUCCESS;
        !           610:                        break;
        !           611:                }
        !           612:                if(ipv6) {
        !           613:                        if(linklocal) {
        !           614:                                linklocal = 0;
        !           615:                                --deviceIndex;
        !           616:                        } else {
        !           617:                                linklocal = 1;
        !           618:                        }
        !           619:                }
        !           620:        } else {
        !           621:                const char * descURL=NULL;
        !           622:                int urlsize=0;
        !           623:                const char * st=NULL;
        !           624:                int stsize=0;
        !           625:         /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
        !           626:                parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
        !           627:                if(st&&descURL)
        !           628:                {
        !           629: #ifdef DEBUG
        !           630:                        printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
        !           631:                               stsize, st, urlsize, descURL);
        !           632: #endif
        !           633:                        for(tmp=devlist; tmp; tmp = tmp->pNext) {
        !           634:                                if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
        !           635:                                   tmp->descURL[urlsize] == '\0' &&
        !           636:                                   memcmp(tmp->st, st, stsize) == 0 &&
        !           637:                                   tmp->st[stsize] == '\0')
        !           638:                                        break;
        !           639:                        }
        !           640:                        /* at the exit of the loop above, tmp is null if
        !           641:                         * no duplicate device was found */
        !           642:                        if(tmp)
        !           643:                                continue;
        !           644:                        tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
        !           645:                        if(!tmp) {
        !           646:                                /* memory allocation error */
        !           647:                                if(error)
        !           648:                                        *error = UPNPDISCOVER_MEMORY_ERROR;
        !           649:                                break;
        !           650:                        }
        !           651:                        tmp->pNext = devlist;
        !           652:                        tmp->descURL = tmp->buffer;
        !           653:                        tmp->st = tmp->buffer + 1 + urlsize;
        !           654:                        memcpy(tmp->buffer, descURL, urlsize);
        !           655:                        tmp->buffer[urlsize] = '\0';
        !           656:                        memcpy(tmp->buffer + urlsize + 1, st, stsize);
        !           657:                        tmp->buffer[urlsize+1+stsize] = '\0';
        !           658:                        devlist = tmp;
        !           659:                }
        !           660:        }
        !           661:        }
        !           662:        closesocket(sudp);
        !           663:        return devlist;
        !           664: }
        !           665: 
        !           666: /* freeUPNPDevlist() should be used to
        !           667:  * free the chained list returned by upnpDiscover() */
        !           668: LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist)
        !           669: {
        !           670:        struct UPNPDev * next;
        !           671:        while(devlist)
        !           672:        {
        !           673:                next = devlist->pNext;
        !           674:                free(devlist);
        !           675:                devlist = next;
        !           676:        }
        !           677: }
        !           678: 
        !           679: static void
        !           680: url_cpy_or_cat(char * dst, const char * src, int n)
        !           681: {
        !           682:        if(  (src[0] == 'h')
        !           683:           &&(src[1] == 't')
        !           684:           &&(src[2] == 't')
        !           685:           &&(src[3] == 'p')
        !           686:           &&(src[4] == ':')
        !           687:           &&(src[5] == '/')
        !           688:           &&(src[6] == '/'))
        !           689:        {
        !           690:                strncpy(dst, src, n);
        !           691:        }
        !           692:        else
        !           693:        {
        !           694:                int l = strlen(dst);
        !           695:                if(src[0] != '/')
        !           696:                        dst[l++] = '/';
        !           697:                if(l<=n)
        !           698:                        strncpy(dst + l, src, n - l);
        !           699:        }
        !           700: }
        !           701: 
        !           702: /* Prepare the Urls for usage...
        !           703:  */
        !           704: LIBSPEC void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
        !           705:                  const char * descURL)
        !           706: {
        !           707:        char * p;
        !           708:        int n1, n2, n3, n4;
        !           709:        n1 = strlen(data->urlbase);
        !           710:        if(n1==0)
        !           711:                n1 = strlen(descURL);
        !           712:        n1 += 2;        /* 1 byte more for Null terminator, 1 byte for '/' if needed */
        !           713:        n2 = n1; n3 = n1; n4 = n1;
        !           714:        n1 += strlen(data->first.scpdurl);
        !           715:        n2 += strlen(data->first.controlurl);
        !           716:        n3 += strlen(data->CIF.controlurl);
        !           717:        n4 += strlen(data->IPv6FC.controlurl);
        !           718: 
        !           719:        urls->ipcondescURL = (char *)malloc(n1);
        !           720:        urls->controlURL = (char *)malloc(n2);
        !           721:        urls->controlURL_CIF = (char *)malloc(n3);
        !           722:        urls->controlURL_6FC = (char *)malloc(n4);
        !           723:        /* maintenant on chope la desc du WANIPConnection */
        !           724:        if(data->urlbase[0] != '\0')
        !           725:                strncpy(urls->ipcondescURL, data->urlbase, n1);
        !           726:        else
        !           727:                strncpy(urls->ipcondescURL, descURL, n1);
        !           728:        p = strchr(urls->ipcondescURL+7, '/');
        !           729:        if(p) p[0] = '\0';
        !           730:        strncpy(urls->controlURL, urls->ipcondescURL, n2);
        !           731:        strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3);
        !           732:        strncpy(urls->controlURL_6FC, urls->ipcondescURL, n4);
        !           733:        
        !           734:        url_cpy_or_cat(urls->ipcondescURL, data->first.scpdurl, n1);
        !           735: 
        !           736:        url_cpy_or_cat(urls->controlURL, data->first.controlurl, n2);
        !           737: 
        !           738:        url_cpy_or_cat(urls->controlURL_CIF, data->CIF.controlurl, n3);
        !           739: 
        !           740:        url_cpy_or_cat(urls->controlURL_6FC, data->IPv6FC.controlurl, n4);
        !           741: 
        !           742: #ifdef DEBUG
        !           743:        printf("urls->ipcondescURL='%s' %u n1=%d\n", urls->ipcondescURL,
        !           744:               (unsigned)strlen(urls->ipcondescURL), n1);
        !           745:        printf("urls->controlURL='%s' %u n2=%d\n", urls->controlURL,
        !           746:               (unsigned)strlen(urls->controlURL), n2);
        !           747:        printf("urls->controlURL_CIF='%s' %u n3=%d\n", urls->controlURL_CIF,
        !           748:               (unsigned)strlen(urls->controlURL_CIF), n3);
        !           749:        printf("urls->controlURL_6FC='%s' %u n4=%d\n", urls->controlURL_6FC,
        !           750:               (unsigned)strlen(urls->controlURL_6FC), n4);
        !           751: #endif
        !           752: }
        !           753: 
        !           754: LIBSPEC void
        !           755: FreeUPNPUrls(struct UPNPUrls * urls)
        !           756: {
        !           757:        if(!urls)
        !           758:                return;
        !           759:        free(urls->controlURL);
        !           760:        urls->controlURL = 0;
        !           761:        free(urls->ipcondescURL);
        !           762:        urls->ipcondescURL = 0;
        !           763:        free(urls->controlURL_CIF);
        !           764:        urls->controlURL_CIF = 0;
        !           765:        free(urls->controlURL_6FC);
        !           766:        urls->controlURL_6FC = 0;
        !           767: }
        !           768: 
        !           769: int
        !           770: UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
        !           771: {
        !           772:        char status[64];
        !           773:        unsigned int uptime;
        !           774:        status[0] = '\0';
        !           775:        UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
        !           776:                           status, &uptime, NULL);
        !           777:        if(0 == strcmp("Connected", status))
        !           778:        {
        !           779:                return 1;
        !           780:        }
        !           781:        else
        !           782:                return 0;
        !           783: }
        !           784: 
        !           785: 
        !           786: /* UPNP_GetValidIGD() :
        !           787:  * return values :
        !           788:  *     0 = NO IGD found
        !           789:  *     1 = A valid connected IGD has been found
        !           790:  *     2 = A valid IGD has been found but it reported as
        !           791:  *         not connected
        !           792:  *     3 = an UPnP device has been found but was not recognized as an IGD
        !           793:  *
        !           794:  * In any non zero return case, the urls and data structures
        !           795:  * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
        !           796:  * free allocated memory.
        !           797:  */
        !           798: LIBSPEC int
        !           799: UPNP_GetValidIGD(struct UPNPDev * devlist,
        !           800:                  struct UPNPUrls * urls,
        !           801:                                 struct IGDdatas * data,
        !           802:                                 char * lanaddr, int lanaddrlen)
        !           803: {
        !           804:        char * descXML;
        !           805:        int descXMLsize = 0;
        !           806:        struct UPNPDev * dev;
        !           807:        int ndev = 0;
        !           808:        int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
        !           809:        if(!devlist)
        !           810:        {
        !           811: #ifdef DEBUG
        !           812:                printf("Empty devlist\n");
        !           813: #endif
        !           814:                return 0;
        !           815:        }
        !           816:        for(state = 1; state <= 3; state++)
        !           817:        {
        !           818:                for(dev = devlist; dev; dev = dev->pNext)
        !           819:                {
        !           820:                        /* we should choose an internet gateway device.
        !           821:                        * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
        !           822:                        descXML = miniwget_getaddr(dev->descURL, &descXMLsize,
        !           823:                                                        lanaddr, lanaddrlen);
        !           824:                        if(descXML)
        !           825:                        {
        !           826:                                ndev++;
        !           827:                                memset(data, 0, sizeof(struct IGDdatas));
        !           828:                                memset(urls, 0, sizeof(struct UPNPUrls));
        !           829:                                parserootdesc(descXML, descXMLsize, data);
        !           830:                                free(descXML);
        !           831:                                descXML = NULL;
        !           832:                                if(0==strcmp(data->CIF.servicetype,
        !           833:                                   "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")
        !           834:                                   || state >= 3 )
        !           835:                                {
        !           836:                                  GetUPNPUrls(urls, data, dev->descURL);
        !           837: 
        !           838: #ifdef DEBUG
        !           839:                                  printf("UPNPIGD_IsConnected(%s) = %d\n",
        !           840:                                     urls->controlURL,
        !           841:                                 UPNPIGD_IsConnected(urls, data));
        !           842: #endif
        !           843:                                  if((state >= 2) || UPNPIGD_IsConnected(urls, data))
        !           844:                                        return state;
        !           845:                                  FreeUPNPUrls(urls);
        !           846:                                  if(data->second.servicetype[0] != '\0') {
        !           847: #ifdef DEBUG
        !           848:                                    printf("We tried %s, now we try %s !\n",
        !           849:                                           data->first.servicetype, data->second.servicetype);
        !           850: #endif
        !           851:                                    /* swaping WANPPPConnection and WANIPConnection ! */
        !           852:                                    memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service));
        !           853:                                    memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service));
        !           854:                                    memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service));
        !           855:                                    GetUPNPUrls(urls, data, dev->descURL);
        !           856: #ifdef DEBUG
        !           857:                                    printf("UPNPIGD_IsConnected(%s) = %d\n",
        !           858:                                       urls->controlURL,
        !           859:                                   UPNPIGD_IsConnected(urls, data));
        !           860: #endif
        !           861:                                    if((state >= 2) || UPNPIGD_IsConnected(urls, data))
        !           862:                                          return state;
        !           863:                                    FreeUPNPUrls(urls);
        !           864:                                  }
        !           865:                                }
        !           866:                                memset(data, 0, sizeof(struct IGDdatas));
        !           867:                        }
        !           868: #ifdef DEBUG
        !           869:                        else
        !           870:                        {
        !           871:                                printf("error getting XML description %s\n", dev->descURL);
        !           872:                        }
        !           873: #endif
        !           874:                }
        !           875:        }
        !           876:        return 0;
        !           877: }
        !           878: 
        !           879: /* UPNP_GetIGDFromUrl()
        !           880:  * Used when skipping the discovery process.
        !           881:  * return value :
        !           882:  *   0 - Not ok
        !           883:  *   1 - OK */
        !           884: int
        !           885: UPNP_GetIGDFromUrl(const char * rootdescurl,
        !           886:                    struct UPNPUrls * urls,
        !           887:                    struct IGDdatas * data,
        !           888:                    char * lanaddr, int lanaddrlen)
        !           889: {
        !           890:        char * descXML;
        !           891:        int descXMLsize = 0;
        !           892:        descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
        !           893:                                       lanaddr, lanaddrlen);
        !           894:        if(descXML) {
        !           895:                memset(data, 0, sizeof(struct IGDdatas));
        !           896:                memset(urls, 0, sizeof(struct UPNPUrls));
        !           897:                parserootdesc(descXML, descXMLsize, data);
        !           898:                free(descXML);
        !           899:                descXML = NULL;
        !           900:                GetUPNPUrls(urls, data, rootdescurl);
        !           901:                return 1;
        !           902:        } else {
        !           903:                return 0;
        !           904:        }
        !           905: }
        !           906: 

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