0
votes

I am using winsock socket api to send a udp packet with a very high port number, which I expect to be unused at the destination. My intention is to receive back one icmp packet with destination unreachable/port unreachable message. I have created two sockets, one on which I am sending UDP packet and other socket on which I am expecting the icmp packet. The send is successful. The destination returns the ICMP reply as well, this I can verify on wireshark. Now when I do a recv, to receive data, the recv function hangs. My objective is to read the data from recv function, which does not happen.

Any help for understaning/fixing this behavior will be highly appreciated. Thanks in advance.

I am attaching the code snippets here...

    void sendPacket(unsigned int socketFd, char *packet, char* remoteIP, char* pingType)
{
    int nsent = -1;
    int rc = -1;

    struct addrinfo hints, *res;

    memset(&hints, 0, sizeof(struct addrinfo));

    if (strcasecmp(pingType, "UDP")==0)
    {
        hints.ai_flags      = AI_CANONNAME;         /* always return canonical name */
        hints.ai_family     = AF_INET;              /* 0, AF_INET, AF_INET6, etc. */
        hints.ai_socktype   = SOCK_DGRAM;           /* 0, SOCK_STREAM, SOCK_DGRAM, etc. */
    }

    rc = getaddrinfo(remoteIP, NULL, &hints, &res);
    if ( rc != 0)
    {
        printf("... Function: %s\tError setting remote address. Exiting. ... \n", __FUNCTION__);    
        exit(-1);
    }

    if (strcasecmp(pingType, "UDP")==0)
    {
        ((struct sockaddr_in *)res->ai_addr)->sin_port = htons(34344);
        strcpy(packet, "TIMESTAMP");
    }

    do
    {
        if (strcasecmp(pingType, "UDP")==0)
        {
            nsent=sendto(socketFd, packet, strlen(packet), 0, (struct sockaddr *)res->ai_addr, (socklen_t)res->ai_addrlen);
            if (nsent < 0)
            {
                continue;
            }
        }
    }while(nsent < 0);

    return;
}


double receivePacket(int socketFd, struct timeval* tvSend, pingReply** lastReplyNode, char* pingType)
{
    ssize_t nRecv = -1;
    double rc = -1;
    char recvbuf[1024];

    do
    {
        nRecv = recv(socketFd, (char *)recvbuf, 1024, 0);
    }
    while(nRecv < 0);

    if (nRecv < 0)
    {
        return -1;
    }       

    rc = processPacket(recvbuf, nRecv, tvSend, lastReplyNode, pingType);

    if (rc == -1)
    {
        printf("... Function: %s\tReceiving error in Data/Protocol ...\n", __FUNCTION__);
        return -1;
    }

    return rc;
}

void createSocket(unsigned int *sendSocketFd, unsigned int *receiveSocketFd, char *pingType)
{
#ifdef _WIN32
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) 
    {
        /* Tell the user that we could not find a usable */
        /* Winsock DLL.                                  */
        printf("WSAStartup failed with error: %d\n", err);
        exit(-1);
    }
#endif

#ifdef _WIN32
    if (strcasecmp(pingType, "UDP")==0)
    {
        int rc = -1;
        struct sockaddr_in src_address;
        unsigned long int length;
        int optval = 1;
        DWORD Length;
        OSVERSIONINFO     g_OSVersionInfo;
        BOOLEAN           g_IsWindowsLonghorn = TRUE;
        BOOLEAN           g_UseFtosToSetTos = TRUE;
        int  ret, iVal=0;
        unsigned int sz = sizeof(iVal);

        g_OSVersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO);
        GetVersionEx( &g_OSVersionInfo );

        if( g_OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
        {
            if( g_OSVersionInfo.dwMajorVersion >= 6 )
            {
                g_IsWindowsLonghorn = TRUE;
                g_UseFtosToSetTos = TRUE;
            }
        }

        *receiveSocketFd = INVALID_SOCKET;
        *receiveSocketFd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
        if (*receiveSocketFd < 0)
        {
            printf("Function: %s\tReceiving Socket creation error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError());
            exit(-1);
        }

        src_address.sin_family=AF_INET;
        src_address.sin_addr.s_addr=inet_addr("x.x.x.x");
        src_address.sin_port=htons(0);

        rc = bind((SOCKET)*receiveSocketFd,(struct sockaddr *)&src_address,sizeof(src_address));
        if (rc < 0)
        {
            printf("Function: %s\tReceiving Socket bind error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError());
            exit(-1);
        }   

        iVal = 30000;   // in milliseconds
        ret = setsockopt(*receiveSocketFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&iVal, sz);
        if (ret == SOCKET_ERROR)
        {
            printf("%d\n", WSAGetLastError());
            return; // Temporary
        }

        rc = WSAIoctl((SOCKET)*receiveSocketFd, SIO_RCVALL, &optval, sizeof(optval), NULL, 0, &length, NULL, NULL);
        if (rc == SOCKET_ERROR)
        {
            printf("Function: %s\tReceiving Socket ioctl error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError());
            exit(-1);
        }
        printf("Function: %s\treceiveSocketFd %d ...\n", __FUNCTION__, *receiveSocketFd);
    }
    else
    {
        *receiveSocketFd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
        if (*receiveSocketFd < 0)
        {
            printf("Function: %s\tReceiving Socket creation error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError());
            exit(-1);
        }
        printf("Function: %s\treceiveSocketFd %d ...\n", __FUNCTION__, *receiveSocketFd);
    }
#endif

#ifndef _WIN32
    unsigned int size = 1024;       /* OK if setsockopt fails */
    setsockopt(*receiveSocketFd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
#else
    char size[5] = "1024";      /* OK if setsockopt fails */
    setsockopt(*receiveSocketFd, SOL_SOCKET, SO_RCVBUF, size, sizeof(size));
#endif

    if (strcasecmp(pingType, "UDP")==0)
    {
        *sendSocketFd = socket(AF_INET, SOCK_DGRAM, 0);
        if (*sendSocketFd < 0)
        {
            printf("Send Socket creation error.");
            exit(-1);
        }
        printf("Function: %s\tsendSocketFd %d ...\n", __FUNCTION__, *sendSocketFd);
    }

    return;
}
1
Are you sure that the recv function is blocking, and not your infinite loop on error? You should really check the error and handle it appropriately instead of just loop forever on error, as errors don't just go away magically.Some programmer dude
@JoachimPileborg There is no error, the recv function does not return. Only when the recv function returns, I can check for error.Abu
Have you debugged it? I.e. stepped through the code in a debugger to see that it really blocks? Or added e.g. printouts inside the loop before and after the call to recv to make sure? Because if there is an error you have an infinite loop.Some programmer dude
@JoachimPileborg Yes, I have debugged it. There are two things, one if I remove the SO_RCVTIMEO in createSocket function and remove the while loop around recv, the recv hangs... it does not return. As I mentioned in the question above, the data is available, I can see it in wireshark.Abu

1 Answers

0
votes

You don't get 'destination unreachable' unless the socket is connected, in the UDP sense, and then you don't get it via recv(), you get it as an errno value from a probably subsequent send().