1

I am right now debugging my socket application, witch involving running and shutting down it consistently. My problem is when I run and shut it down then run it again I receive 10048 error code, witch indicate address already in use. I tried to set socket descriptor to SO_REUSEADDR but still receiving 10048 error code if I run and close my application consistently.

int getExternalpAddress(char *upnpDeviceIp, char *localIp, char *externalIpAddress) {
    WSADATA wsaData;
    struct sockaddr_in upnpControl, 
                       upnpDevice;
    int i = 0,
        j = 0,
        result = -1,
        bodyLen = 0;
    char c, 
         *tmp = NULL,
         *pLen = NULL,
         *bodyResponse = NULL,
         pBodyLen[5], 
         responseHeader[512],
         getExternalIpRequest[622]; 
    int reuseAddress = 1;

    ZeroMemory(getExternalIpRequest, 622);
    StringCbPrintf(getExternalIpRequest, 622,
                                             "POST /UD/?3 HTTP/1.1\r\n"
                                             "Content-Type: text/xml; charset=\"utf-8\"\r\n" 
                                             "SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress\"\r\n"
                                             "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n"
                                             "Host: %s\r\n"
                                             "Content-Length: 303\r\n"
                                             "Connection: Close\r\n"
                                             "Cache-Control: no-cache\r\n"
                                             "Pragma: no-cache\r\n\r\n"
                                             "<?xml version=\"1.0\"?>"
                                             "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                                             "<SOAP-ENV:Body>"
                                             "<m:GetExternalIPAddress xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\"/>"
                                             "</SOAP-ENV:Body>"
                                             "</SOAP-ENV:Envelope>\r\n\r\n", upnpDeviceIp);
    result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if(result != 0)
        return WSAGetLastError();

    SOCKET sock = INVALID_SOCKET;
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock == SOCKET_ERROR)
        return WSAGetLastError();

    if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseAddress, sizeof(reuseAddress)))
        return WSAGetLastError();

    ZeroMemory(&upnpControl, sizeof(upnpControl));
    upnpControl.sin_family = AF_INET;
    if(localIp == NULL)
        upnpControl.sin_addr.s_addr = INADDR_ANY;
    else
        upnpControl.sin_addr.s_addr = inet_addr(localIp);

    upnpControl.sin_port = htons(8000);
    if(bind(sock, (struct sockaddr *)&upnpControl, sizeof(struct sockaddr)) == SOCKET_ERROR)
        return WSAGetLastError();

    ZeroMemory(&upnpDevice, sizeof(upnpDevice));
    upnpDevice.sin_family = AF_INET;
    upnpDevice.sin_port = htons(80);
    upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
    if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(struct sockaddr)) == SOCKET_ERROR)
        return WSAGetLastError();

    result = send(sock, getExternalIpRequest, lstrlen(getExternalIpRequest), 0);
    if(result != lstrlen(getExternalIpRequest))
        return WSAGetLastError();

    ZeroMemory(responseHeader, 512);
    while(recv(sock, &c, 1, 0) > 0) {
        responseHeader[i] = c;
        if(strstr(responseHeader, "\r\n\r\n")) {
            // Move the pointer to the first digit
            pLen = strstr(responseHeader, "Content-Length: ") + 16;
            ZeroMemory(pBodyLen, 5);
            // Get the body length
            while(*pLen != '\r') {
                pBodyLen[j] = *pLen;
                *pLen++;
                ++j;
            }

            bodyLen = atoi(pBodyLen);
            j = 0;
            bodyResponse = (char *)MALLOC(bodyLen);
            while(recv(sock, &c, 1, 0) > 0) {
                bodyResponse[j] = c;
                ++j;

                if(j == bodyLen) { // We got the HTTP body
                    closesocket(sock);
                }
            }
        }

        ++i;
    }

    i = 0;
    tmp = strstr(bodyResponse, "<NewExternalIPAddress>") + 22;
    ZeroMemory(externalIpAddress, 16);
    while(*tmp != '<') {
        externalIpAddress[i] = *tmp;
        *tmp++;
        ++i;
    }

    FREE(bodyResponse);
    WSACleanup();
    return 0;
}
Haris
  • 12,120
  • 6
  • 43
  • 70
SIFE
  • 5,567
  • 7
  • 32
  • 46
  • Not sure what your setsockopt is doing, but anyways you need to release the socket once you are done with before shutting down. – mawia Nov 15 '13 at 19:54
  • I think you doing setsockopt correctly, are you sure no other process is using it (on linux, netstat can be used here, but for windows I am not sure.) ? – UltraInstinct Nov 15 '13 at 19:56
  • @mawia I included how I shutdown the socket. – SIFE Nov 15 '13 at 20:02
  • @Thrustmaster In wireshark I can see the close handshake. – SIFE Nov 15 '13 at 20:05
  • The code shown is not binding the socket to a local IP/Port before closing it. `SO_REUSEADDR` is only meaningful if `bind()` is called. – Remy Lebeau Nov 16 '13 at 01:08
  • @RemyLebeau My code is a client socket, so bind is used, it is just happen that I embed only pseudo code for easy reading. – SIFE Nov 16 '13 at 02:03
  • @SIFE: if you want people on this site to help you with code, please post [SSCCE](http://sscce.org)s whenever possible. That includes showing your variable declarations and initializations. – Remy Lebeau Nov 16 '13 at 03:09
  • @SIFE: `sizeof(struct sockaddr))` is wrong. You need to use `sizeof(struct sockaddr_in))` instead, and make sure that `upnpControl` and `upnpDevice` are both declared as `sockaddr_in` and not `sockaddr` to begin with. – Remy Lebeau Nov 16 '13 at 03:11
  • @RemyLebeau I posted my complete code, it just I didn't see any issue except in reuse address part. – SIFE Nov 16 '13 at 11:22
  • You are using TCP so why are you bothering with `SO_REUSEADDR` at all? It is very rarely ever used with TCP, it is more commonly used with UDP instead. HTTP *does not* require you to bind a client to a specific local IP/Port when sending a request. If you want to bind manually, such as to pick a specific interface to use, then bind the IP only, but leave the port set to 0 so the OS will pick an available port for you. Otherwise, ignore `bind()` altogether and let `connect()` handle the binding for you. – Remy Lebeau Nov 16 '13 at 23:44
  • I didn't know that `bind()` is not always necessary. Would you re-post your comment as an answer so I can accept it for my question? – SIFE Nov 17 '13 at 06:12

0 Answers0