c++udpwinsock2

WinSock2 UDP - Using socket() and recvfrom() on 2 distinct functions


I am new using WinSock2 and I am trying to create an UDP server. It works perfectly when I test it by using the whole procedure on the main function :

When I want to separate my code on several function, the code doesn't works anymore and I don't know why.

#include <iostream>
#include <winsock2.h> 
#include <Ws2tcpip.h>

void TEST(SOCKET sock) {
    sockaddr_in from; int fromlen;
    char buf[1024];
    int result = recvfrom(sock, buf, 1024, 0, (sockaddr *)&from, &fromlen);
    if (result < 0) {
        std::cerr << "Error : " << WSAGetLastError() << std::endl;
        return;
    }
        
    printf("Received a datagram: %s", buf);
}


void server() {
    int result = 0;
    SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock == INVALID_SOCKET) {
        std::cerr << "Error socket()" << std::endl;
        return;
    }

    sockaddr_in addrListen = {};
    addrListen.sin_family = AF_INET;
    addrListen.sin_addr.s_addr = htonl(INADDR_ANY);
    addrListen.sin_port = htons(1234);
    
    result = bind(sock, (sockaddr*)&addrListen, sizeof(addrListen));
    if (result < 0) {
       std::cout << "Error bind() : " << result << " : " << WSAGetLastError() << std::endl;
       return;
    }

    std::cout << "Listening..." << std::endl;
    TEST(sock);
    
    closesocket(sock);
    WSACleanup();
}

int main(int argc, char const *argv[]) {
    WSADATA wsaData;
    int err = WSAStartup(MAKEWORD(2, 2), &wsaData); // Winsock v2.2
    if (err != NO_ERROR) {
        wprintf(L"WSAStartup failed with error: %d\n", err);
        return 1;
    }

    server();
    
    std::cout << "Done." << std::endl;
    return 0;
}

I know the code is horrible but it is for testing purpose. I tried by using a pointer, a reference, sock as global var... Nothing works. recvfrom() always returns -1 when socket() and recvfrom() are not in the same function. On some tests WSAGetLastError() returns 5 (ACCESS_DENIED) but it returns 0 most of the time.

I haven't found any topic about this problem. Does anyone have a tip for me ?


Solution

  • This line:

    sockaddr_in from; int fromlen;
    

    Is missing an initialization for fromLen. It needs to be:

    int fromlen=sizeof(from);
    

    recvfrom needs to know how big the from address is, so this needs to be set. It can also technically change in size on return, but that's not usually the case unless you're using sockaddr_storage as the address type and mixed IPv4/IPv6 code.

    So, when combined with my original comment, we can fix up your code like this:

    void TEST(SOCKET sock) {
        sockaddr_in from; int fromlen=sizeof(from);
        
        char buf[1024+1];   // +1 to ensure space for null char
    
        int result = recvfrom(sock, buf, 1024, 0, (sockaddr *)&from, &fromlen);
        if (result < 0) {
            std::cerr << "Error : " << WSAGetLastError() << std::endl;
            return;
        }
    
        buf[result] = '\0';
            
        printf("Received a datagram: %s", buf);
    }