Esempio n. 1
0
/* upnpDiscover() :
 * return a chained list of all devices found or NULL if
 * no devices was found.
 * It is up to the caller to free the chained list
 * delay is in millisecond (poll) */
struct UPNPDev * upnpDiscover(int delay, const char * multicastif,
                              const char * minissdpdsock, int sameport)
{
	struct UPNPDev * tmp;
	struct UPNPDev * devlist = 0;
	int opt = 1;
	static const char MSearchMsgFmt[] = 
	"M-SEARCH * HTTP/1.1\r\n"
	"HOST: " UPNP_MCAST_ADDR ":" XSTR(PORT) "\r\n"
	"ST: %s\r\n"
	"MAN: \"ssdp:discover\"\r\n"
	"MX: 3\r\n"
	"\r\n";
	static const char * const deviceList[] = {
		"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
		"urn:schemas-upnp-org:service:WANIPConnection:1",
		"urn:schemas-upnp-org:service:WANPPPConnection:1",
		"upnp:rootdevice",
		0
	};
	int deviceIndex = 0;
	char bufr[1536];	/* reception and emission buffer */
	int sudp;
	int n;
	struct sockaddr_in sockudp_r, sockudp_w;

#ifndef WIN32
	/* first try to get infos from minissdpd ! */
	if(!minissdpdsock)
		minissdpdsock = "/var/run/minissdpd.sock";
	while(!devlist && deviceList[deviceIndex]) {
		devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex],
		                                  minissdpdsock);
		/* We return what we have found if it was not only a rootdevice */
		if(devlist && !strstr(deviceList[deviceIndex], "rootdevice"))
			return devlist;
		deviceIndex++;
	}
	deviceIndex = 0;
#endif
	/* fallback to direct discovery */
#ifdef WIN32
	sudp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
#else
	sudp = socket(PF_INET, SOCK_DGRAM, 0);
#endif
	if(sudp < 0)
	{
		PRINT_SOCKET_ERROR("socket");
		return NULL;
	}
    /* reception */
    memset(&sockudp_r, 0, sizeof(struct sockaddr_in));
    sockudp_r.sin_family = AF_INET;
	if(sameport)
    	sockudp_r.sin_port = htons(PORT);
    sockudp_r.sin_addr.s_addr = INADDR_ANY;
    /* emission */
    memset(&sockudp_w, 0, sizeof(struct sockaddr_in));
    sockudp_w.sin_family = AF_INET;
    sockudp_w.sin_port = htons(PORT);
    sockudp_w.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);

#ifdef WIN32
	if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
#else
	if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
#endif
	{
		PRINT_SOCKET_ERROR("setsockopt");
		return NULL;
	}

	if(multicastif)
	{
		struct in_addr mc_if;
		mc_if.s_addr = inet_addr(multicastif);
    	sockudp_r.sin_addr.s_addr = mc_if.s_addr;
		if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
		{
			PRINT_SOCKET_ERROR("setsockopt");
		}
	}

	/* Avant d'envoyer le paquet on bind pour recevoir la reponse */
    if (bind(sudp, (struct sockaddr *)&sockudp_r, sizeof(struct sockaddr_in)) != 0)
	{
        PRINT_SOCKET_ERROR("bind");
		closesocket(sudp);
		return NULL;
    }

	/* receiving SSDP response packet */
	for(n = 0;;)
	{
	if(n == 0)
	{
		/* sending the SSDP M-SEARCH packet */
		n = snprintf(bufr, sizeof(bufr),
		             MSearchMsgFmt, deviceList[deviceIndex++]);
		/*printf("Sending %s", bufr);*/
		n = sendto(sudp, bufr, n, 0,
		           (struct sockaddr *)&sockudp_w, sizeof(struct sockaddr_in));
		if (n < 0) {
			PRINT_SOCKET_ERROR("sendto");
			closesocket(sudp);
			return devlist;
		}
	}
	/* Waiting for SSDP REPLY packet to M-SEARCH */
	n = ReceiveData(sudp, bufr, sizeof(bufr), delay);
	if (n < 0) {
		/* error */
		closesocket(sudp);
		return devlist;
	} else if (n == 0) {
		/* no data or Time Out */
		if (devlist || (deviceList[deviceIndex] == 0)) {
			/* no more device type to look for... */
			closesocket(sudp);
			return devlist;
		}
	} else {
		const char * descURL=NULL;
		int urlsize=0;
		const char * st=NULL;
		int stsize=0;
        /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
		parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
		if(st&&descURL)
		{
			/*printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
			       stsize, st, urlsize, descURL); */
			tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
			tmp->pNext = devlist;
			tmp->descURL = tmp->buffer;
			tmp->st = tmp->buffer + 1 + urlsize;
			memcpy(tmp->buffer, descURL, urlsize);
			tmp->buffer[urlsize] = '\0';
			memcpy(tmp->buffer + urlsize + 1, st, stsize);
			tmp->buffer[urlsize+1+stsize] = '\0';
			devlist = tmp;
		}
	}
	}
}
Esempio n. 2
0
/* upnpDiscoverDevices() :
 * return a chained list of all devices found or NULL if
 * no devices was found.
 * It is up to the caller to free the chained list
 * delay is in millisecond (poll) */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevices(const char * const deviceTypes[],
                    int delay, const char * multicastif,
                    const char * minissdpdsock, int sameport,
                    int ipv6,
                    int * error)
{
    struct UPNPDev * tmp;
    struct UPNPDev * devlist = 0;
    unsigned int scope_id = 0;
    int opt = 1;
    static const char MSearchMsgFmt[] =
        "M-SEARCH * HTTP/1.1\r\n"
        "HOST: %s:" XSTR(PORT) "\r\n"
        "ST: %s\r\n"
        "MAN: \"ssdp:discover\"\r\n"
        "MX: %u\r\n"
        "\r\n";
    int deviceIndex;
    char bufr[1536];	/* reception and emission buffer */
    int sudp;
    int n;
    struct sockaddr_storage sockudp_r;
    unsigned int mx;
#ifdef NO_GETADDRINFO
    struct sockaddr_storage sockudp_w;
#else
    int rv;
    struct addrinfo hints, *servinfo, *p;
#endif
#ifdef _WIN32
    MIB_IPFORWARDROW ip_forward;
#endif
    int linklocal = 1;

    if(error)
        *error = UPNPDISCOVER_UNKNOWN_ERROR;
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
    /* first try to get infos from minissdpd ! */
    if(!minissdpdsock)
        minissdpdsock = "/var/run/minissdpd.sock";
    for(deviceIndex = 0; !devlist && deviceTypes[deviceIndex]; deviceIndex++) {
        devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
                                          minissdpdsock);
        /* We return what we have found if it was not only a rootdevice */
        if(devlist && !strstr(deviceTypes[deviceIndex], "rootdevice")) {
            if(error)
                *error = UPNPDISCOVER_SUCCESS;
            return devlist;
        }
    }
#endif
    /* fallback to direct discovery */
#ifdef _WIN32
    sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
#else
    sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
#endif
    if(sudp < 0)
    {
        if(error)
            *error = UPNPDISCOVER_SOCKET_ERROR;
        PRINT_SOCKET_ERROR("socket");
        return NULL;
    }

    /* reception */
    memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
    if(ipv6) {
        struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
        p->sin6_family = AF_INET6;
        if(sameport)
            p->sin6_port = htons(PORT);
        p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
    } else {
        struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
        p->sin_family = AF_INET;
        if(sameport)
            p->sin_port = htons(PORT);
        p->sin_addr.s_addr = INADDR_ANY;
    }
#ifdef _WIN32
    /* This code could help us to use the right Network interface for
     * SSDP multicast traffic */
    /* Get IP associated with the index given in the ip_forward struct
     * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
    if(!ipv6
            && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
        DWORD dwRetVal = 0;
        PMIB_IPADDRTABLE pIPAddrTable;
        DWORD dwSize = 0;
#ifdef DEBUG
        IN_ADDR IPAddr;
#endif
        int i;
#ifdef DEBUG
        printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
#endif
        pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
        if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
            free(pIPAddrTable);
            pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
        }
        if(pIPAddrTable) {
            dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
#ifdef DEBUG
            printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
#endif
            for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
#ifdef DEBUG
                printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
                IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
                printf("\tIP Address[%d]:     \t%s\n", i, inet_ntoa(IPAddr) );
                IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
                printf("\tSubnet Mask[%d]:    \t%s\n", i, inet_ntoa(IPAddr) );
                IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
                printf("\tBroadCast[%d]:      \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
                printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
                printf("\tType and State[%d]:", i);
                printf("\n");
#endif
                if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
                    /* Set the address of this interface to be used */
                    struct in_addr mc_if;
                    memset(&mc_if, 0, sizeof(mc_if));
                    mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
                    if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
                        PRINT_SOCKET_ERROR("setsockopt");
                    }
                    ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
#ifndef DEBUG
                    break;
#endif
                }
            }
            free(pIPAddrTable);
            pIPAddrTable = NULL;
        }
    }
#endif

#ifdef _WIN32
    if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
#else
    if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
#endif
    {
        if(error)
            *error = UPNPDISCOVER_SOCKET_ERROR;
        PRINT_SOCKET_ERROR("setsockopt");
        return NULL;
    }

    if(multicastif)
    {
        if(ipv6) {
#if !defined(_WIN32)
            /* according to MSDN, if_nametoindex() is supported since
             * MS Windows Vista and MS Windows Server 2008.
             * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
            unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
            if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0)
            {
                PRINT_SOCKET_ERROR("setsockopt");
            }
#else
#ifdef DEBUG
            printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
#endif
#endif
        } else {
            struct in_addr mc_if;
            mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
            if(mc_if.s_addr != INADDR_NONE)
            {
                ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
                if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
                {
                    PRINT_SOCKET_ERROR("setsockopt");
                }
            } else {
#ifdef HAS_IP_MREQN
                /* was not an ip address, try with an interface name */
                struct ip_mreqn reqn;	/* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
                memset(&reqn, 0, sizeof(struct ip_mreqn));
                reqn.imr_ifindex = if_nametoindex(multicastif);
                if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
                {
                    PRINT_SOCKET_ERROR("setsockopt");
                }
#else
#ifdef DEBUG
                printf("Setting of multicast interface not supported with interface name.\n");
#endif
#endif
            }
        }
    }

    /* Before sending the packed, we first "bind" in order to be able
     * to receive the response */
    if (bind(sudp, (const struct sockaddr *)&sockudp_r,
             ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
    {
        if(error)
            *error = UPNPDISCOVER_SOCKET_ERROR;
        PRINT_SOCKET_ERROR("bind");
        closesocket(sudp);
        return NULL;
    }

    if(error)
        *error = UPNPDISCOVER_SUCCESS;
    /* Calculating maximum response time in seconds */
    mx = ((unsigned int)delay) / 1000u;
    if(mx == 0) {
        mx = 1;
        delay = 1000;
    }
    /* receiving SSDP response packet */
    for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
        /* sending the SSDP M-SEARCH packet */
        n = snprintf(bufr, sizeof(bufr),
                     MSearchMsgFmt,
                     ipv6 ?
                     (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" :  "[" UPNP_MCAST_SL_ADDR "]")
                     : UPNP_MCAST_ADDR,
                     deviceTypes[deviceIndex], mx);
#ifdef DEBUG
        /*printf("Sending %s", bufr);*/
        printf("Sending M-SEARCH request to %s with ST: %s\n",
               ipv6 ?
               (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" :  "[" UPNP_MCAST_SL_ADDR "]")
               : UPNP_MCAST_ADDR,
               deviceTypes[deviceIndex]);
#endif
#ifdef NO_GETADDRINFO
        /* the following code is not using getaddrinfo */
        /* emission */
        memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
        if(ipv6) {
            struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
            p->sin6_family = AF_INET6;
            p->sin6_port = htons(PORT);
            inet_pton(AF_INET6,
                      linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
                      &(p->sin6_addr));
        } else {
            struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
            p->sin_family = AF_INET;
            p->sin_port = htons(PORT);
            p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
        }
        n = sendto(sudp, bufr, n, 0, &sockudp_w,
                   ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
        if (n < 0) {
            if(error)
                *error = UPNPDISCOVER_SOCKET_ERROR;
            PRINT_SOCKET_ERROR("sendto");
            break;
        }
#else /* #ifdef NO_GETADDRINFO */
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
        hints.ai_socktype = SOCK_DGRAM;
        /*hints.ai_flags = */
        if ((rv = getaddrinfo(ipv6
                              ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
                              : UPNP_MCAST_ADDR,
                              XSTR(PORT), &hints, &servinfo)) != 0) {
            if(error)
                *error = UPNPDISCOVER_SOCKET_ERROR;
#ifdef _WIN32
            fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
#else
            fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
#endif
            break;
        }
        for(p = servinfo; p; p = p->ai_next) {
            n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
            if (n < 0) {
#ifdef DEBUG
                char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
                if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
                                sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
                    fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
                }
#endif
                PRINT_SOCKET_ERROR("sendto");
                continue;
            }
        }
        freeaddrinfo(servinfo);
        if(n < 0) {
            if(error)
                *error = UPNPDISCOVER_SOCKET_ERROR;
            break;
        }
#endif /* #ifdef NO_GETADDRINFO */
        /* Waiting for SSDP REPLY packet to M-SEARCH */
        do {
            n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
            if (n < 0) {
                /* error */
                if(error)
                    *error = UPNPDISCOVER_SOCKET_ERROR;
                goto error;
            } else if (n == 0) {
                /* no data or Time Out */
                if (devlist) {
                    /* found some devices, stop now*/
                    if(error)
                        *error = UPNPDISCOVER_SUCCESS;
                    goto error;
                }
                if(ipv6) {
                    /* switch linklocal flag */
                    if(linklocal) {
                        linklocal = 0;
                        --deviceIndex;
                    } else {
                        linklocal = 1;
                    }
                }
            } else {
                const char * descURL=NULL;
                int urlsize=0;
                const char * st=NULL;
                int stsize=0;
                parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
                if(st&&descURL) {
#ifdef DEBUG
                    printf("M-SEARCH Reply:\n  ST: %.*s\n  Location: %.*s\n",
                           stsize, st, urlsize, descURL);
#endif
                    for(tmp=devlist; tmp; tmp = tmp->pNext) {
                        if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
                                tmp->descURL[urlsize] == '\0' &&
                                memcmp(tmp->st, st, stsize) == 0 &&
                                tmp->st[stsize] == '\0')
                            break;
                    }
                    /* at the exit of the loop above, tmp is null if
                     * no duplicate device was found */
                    if(tmp)
                        continue;
                    tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
                    if(!tmp) {
                        /* memory allocation error */
                        if(error)
                            *error = UPNPDISCOVER_MEMORY_ERROR;
                        goto error;
                    }
                    tmp->pNext = devlist;
                    tmp->descURL = tmp->buffer;
                    tmp->st = tmp->buffer + 1 + urlsize;
                    memcpy(tmp->buffer, descURL, urlsize);
                    tmp->buffer[urlsize] = '\0';
                    memcpy(tmp->buffer + urlsize + 1, st, stsize);
                    tmp->buffer[urlsize+1+stsize] = '\0';
                    tmp->scope_id = scope_id;
                    devlist = tmp;
                }
            }
        } while(n > 0);
    }
error:
    closesocket(sudp);
    return devlist;
}
Esempio n. 3
0
/* upnpDiscover() :
 * return a chained list of all devices found or NULL if
 * no devices was found.
 * It is up to the caller to free the chained list
 * delay is in millisecond (poll) */
struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
             const char * minissdpdsock, int sameport,
             int ipv6, //unused in psp port
             int * error)
{
	struct UPNPDev * tmp;
	struct UPNPDev * devlist = 0;
	int opt = 1;
	static const char MSearchMsgFmt[] = 
	"M-SEARCH * HTTP/1.1\r\n"
	"HOST: %s:" XSTR(PORT) "\r\n"
	"ST: %s\r\n"
	"MAN: \"ssdp:discover\"\r\n"
	"MX: %u\r\n"
	"\r\n";
	static const char * const deviceList[] = {
#if 0
		"urn:schemas-upnp-org:device:InternetGatewayDevice:2",
		"urn:schemas-upnp-org:service:WANIPConnection:2",
#endif
		"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
		"urn:schemas-upnp-org:service:WANIPConnection:1",
		"urn:schemas-upnp-org:service:WANPPPConnection:1",
		"upnp:rootdevice",
		0
	};
	int deviceIndex = 0;
	char bufr[1536];	/* reception and emission buffer */
	int sudp;
	int n;
	SceNetInetSockaddrIn sockudp_r;
	unsigned int mx;
	SceNetInetSockaddrIn sockudp_w;
	int linklocal = 1;

	if(error)
		*error = UPNPDISCOVER_UNKNOWN_ERROR;

	/* fallback to direct discovery */
	//sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
	sudp = sceNetInetSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if(sudp < 0)
	{
		if(error)
			*error = UPNPDISCOVER_SOCKET_ERROR;
		return NULL;
	}
	
	/* reception */
	memset(&sockudp_r, 0, sizeof(SceNetInetSockaddrIn));

	SceNetInetSockaddrIn * p = (SceNetInetSockaddrIn *)&sockudp_r;
	p->sin_family = AF_INET;
	if(sameport)
		p->sin_port = sceNetHtons(PORT);
	p->sin_addr = INADDR_ANY;


	// Enable Port Re-use
	sceNetInetSetsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
	sceNetInetSetsockopt(sudp, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
	
	/* Avant d'envoyer le paquet on bind pour recevoir la reponse */
    if (sceNetInetBind(sudp, (const struct SceNetInetSockaddr *)&sockudp_r,
	         sizeof(SceNetInetSockaddrIn)) != 0)
	{
		if(error)
			*error = UPNPDISCOVER_SOCKET_ERROR;
		sceNetInetClose(sudp);
		return NULL;
    }

	if(error)
		*error = UPNPDISCOVER_SUCCESS;
	/* Calculating maximum response time in seconds */
	mx = ((unsigned int)delay) / 1000u;
	/* receiving SSDP response packet */
	for(n = 0; deviceList[deviceIndex]; deviceIndex++)
	{
	if(n == 0)
	{
		/* sending the SSDP M-SEARCH packet */
		n = snprintf(bufr, sizeof(bufr),
		             MSearchMsgFmt,
		             UPNP_MCAST_ADDR,
		             deviceList[deviceIndex], mx);

		/* the following code is not using getaddrinfo */
		/* emission */
		memset(&sockudp_w, 0, sizeof(SceNetInetSockaddrIn));

		SceNetInetSockaddrIn * p = (SceNetInetSockaddrIn *)&sockudp_w;
		p->sin_family = AF_INET;
		p->sin_port = sceNetHtons(PORT);
		sceNetInetInetAton(UPNP_MCAST_ADDR, &p->sin_addr);
		
		n = sceNetInetSendto(sudp, bufr, n, 0,
		           (SceNetInetSockaddr *)&sockudp_w,
		           sizeof(SceNetInetSockaddrIn));
		if (n < 0) {
			if(error)
				*error = UPNPDISCOVER_SOCKET_ERROR;
			break;
		}
	}
	/* Waiting for SSDP REPLY packet to M-SEARCH */
	n = receivedata(sudp, bufr, sizeof(bufr), delay);
	if (n < 0) {
		/* error */
		if(error)
			*error = UPNPDISCOVER_SOCKET_ERROR;
		break;
	} else if (n == 0) {
		/* no data or Time Out */
		if (devlist) {
			/* no more device type to look for... */
			if(error)
				*error = UPNPDISCOVER_SUCCESS;
			break;
		}
		if(ipv6) {
			if(linklocal) {
				linklocal = 0;
				--deviceIndex;
			} else {
				linklocal = 1;
			}
		}
	} else {
		const char * descURL=NULL;
		int urlsize=0;
		const char * st=NULL;
		int stsize=0;
        /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
		parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
		if(st&&descURL)
		{
			for(tmp=devlist; tmp; tmp = tmp->pNext) {
				if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
				   tmp->descURL[urlsize] == '\0' &&
				   memcmp(tmp->st, st, stsize) == 0 &&
				   tmp->st[stsize] == '\0')
					break;
			}
			/* at the exit of the loop above, tmp is null if
			 * no duplicate device was found */
			if(tmp)
				continue;
			tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
			if(!tmp) {
				/* memory allocation error */
				if(error)
					*error = UPNPDISCOVER_MEMORY_ERROR;
				break;
			}
			tmp->pNext = devlist;
			tmp->descURL = tmp->buffer;
			tmp->st = tmp->buffer + 1 + urlsize;
			memcpy(tmp->buffer, descURL, urlsize);
			tmp->buffer[urlsize] = '\0';
			memcpy(tmp->buffer + urlsize + 1, st, stsize);
			tmp->buffer[urlsize+1+stsize] = '\0';
			devlist = tmp;
		}
	}
	}
	sceNetInetClose(sudp);
	return devlist;
}