Search code examples
cserveripv6winsock2recvfrom

IPv6 Server in c - recvfrom failed


i have written a small c-program for an IPv6 server with winsock2.h When I run the program in Visual Studio, I get the following message all the time: recvfrom failed

I just can't find the error in the recvfrom function. Maybe someone can see why my program does not work at this point, thanks! :-)

Best regards, Ken

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma comment(lib, "Ws2_32.lib")

int main(int argc, char* argv[]) {

    SOCKET server_socket;
    struct sockaddr_in6 server_addr, client_addr;
    socklen_t client_len;
    char buf[1024];
    char clientIP[256];

    WSADATA data;
    WORD version = MAKEWORD(2, 2);
    if (WSAStartup(version, &data) == SOCKET_ERROR) {

        printf("WSASStartup failed\n");
        WSACleanup();
        exit(EXIT_FAILURE);
    }

    server_socket = socket(AF_INET6, SOCK_DGRAM, 0);
    if (server_socket == -1) {

        printf("creating socket failed\n");
        WSACleanup();
        exit(EXIT_FAILURE);
    }
    else {

        printf("creating socket successful\n");
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin6_addr = in6addr_any;
    server_addr.sin6_family = AF_INET6;
    server_addr.sin6_port = htons(5001);

    if (bind(server_socket, (const struct sockaddr*) & server_addr,
        sizeof(server_addr)) == -1) {

        printf("bind socket failed\n");
        WSACleanup();
        exit(EXIT_FAILURE);
    }
    else {

        printf("bind socket successful\n");
    }

    while (1) {

        memset(&client_addr, 0, sizeof(client_addr));
        memset(buf, 0, sizeof(buf));

        if (recvfrom(server_socket, (char*)buf, 1024, 0,
            (struct sockaddr*) & client_addr,
            sizeof(client_addr)) == -1) {

            printf("recvfrom failed\n");
            WSACleanup();
            exit(EXIT_FAILURE);
        }
        else {

            printf("recvfrom successful");
        }

        printf("%s\n", buf);
        printf("IP: %s\n", inet_ntop(AF_INET6, &client_addr.sin6_addr,
            clientIP, 256));
    }

    closesocket(server_socket);

    WSACleanup();

    return 0;
}

Solution

  • You are misusing recvfrom(). The fromlen parameter expects to receive an int* pointer that points to an int, which on input specifies the byte size of the sockaddr buffer being passed in the from parameter, and on output receives the byte size of the sockaddr written to the from buffer.

    There are also some other minor bugs in your code:

    • WSAStartup() does not return SOCKET_ERROR on failure, it returns an actual error code.

    • you are ignoring the return value of recvfrom(), which tells you how many bytes were actually written to your buf. You are assuming buf is always null-terminated when passing it to printf("%s"), but that is not guaranteed. You are zeroing out buf to initialize it with null terminators, which is fine if recvfrom() receives a datagram containing less than 1024 bytes. But if it receives a datagram with exactly 1024 bytes than all of your null terminators will be overwritten and there will be no terminator left for printf() to find (if recvfrom() receives a datagram with more than 1024 bytes, it will fail with a WSAEMSGSIZE error, which is not a fatal error but you are treating it as if it were). Rather than rely on any null terminators at all, you can pass the return value of recvfrom() to printf() for the buffer size. No need to waste overhead zeroing out what recvfrom() will overwrite.

    Try this instead:

    #define WIN32_LEAN_AND_MEAN
    
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #pragma comment(lib, "Ws2_32.lib")
    
    int main(int argc, char* argv[]) {
    
        SOCKET server_socket;
        struct sockaddr_in6 server_addr, client_addr;
        int client_len, num_recvd;
        char buf[1024];
        char clientIP[256];
    
        WSADATA data;
        WORD version = MAKEWORD(2, 2);
    
        int errCode = WSAStartup(version, &data);
        if (errCode != 0) {
            printf("WSAStartup failed, error %d\n", errCode);
            WSACleanup();
            return EXIT_FAILURE;
        }
    
        server_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
        if (server_socket == INVALID_SOCKET) {
            errCode = WSAGetLastError();
            printf("creating socket failed, error %d\n", errCode);
            WSACleanup();
            return EXIT_FAILURE;
        }
    
        printf("creating socket successful\n");
    
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin6_addr = in6addr_any;
        server_addr.sin6_family = AF_INET6;
        server_addr.sin6_port = htons(5001);
    
        if (bind(server_socket, (struct sockaddr*) &server_addr, sizeof(server_addr)) == SOCKET_ERROR) {
            errCode = WSAGetLastError();
            printf("bind socket failed, error %d\n", errCode);
            closesocket(server_socket);
            WSACleanup();
            return EXIT_FAILURE;
        }
    
        printf("bind socket successful\n");
    
        while (1) {
    
            client_len = sizeof(client_addr);
    
            num_recvd = recvfrom(server_socket, buf, sizeof(buf), 0, (struct sockaddr*) &client_addr, &client_len);
            if (num_recvd == SOCKET_ERROR) {
                errCode = WSAGetLastError();
                if (errCode != WSAEMSGSIZE) {
                    printf("recvfrom failed, error %d\n", errCode);
                    closesocket(server_socket);
                    WSACleanup();
                    return EXIT_FAILURE;
                }
                printf("recvfrom truncated a datagram larger than %u bytes!\n", sizeof(buf));
                num_recvd = sizeof(buf);
            }
            else {
                printf("recvfrom successful\n");
            }
    
            printf("%.*s\n", num_recvd, buf);
            printf("IP: %s\n", inet_ntop(AF_INET6, &client_addr.sin6_addr, clientIP, 256));
        }
    
        closesocket(server_socket);
        WSACleanup();
    
        return 0;
    }