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