How to easily solve the 10040 message too long error on Wsock2

19,376

Solution 1

WSAEMSGSIZE usually means that the buffer you provided to recvfrom() was smaller than the incoming datagram. Check or post your recvfrom() code to make sure you are using a sufficiently large and correctly declared buffer. Because IPv4 packets can (theoretically) be up to 64 kilobytes in size, it is safest to always use a buffer that large.

Solution 2

Reading from the MSDN documentation for error WSAEMSGSIZE (10040):

Message too long.

A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram was smaller than the datagram itself.

This probably means that your receive buffer is too small, and you need to enlarge it. This is done with the setsockopt function and the SO_RCVBUF option.

Solution 3

10040 is telling you to use a larger buffer when you call recvfrom(). It does NOT mean for you to increase the size of the socket's internal receive buffer.

Since you already know how many floats you are expecting to receive, simply declare a buffer large enough to receive them all, eg:

float buffer[1404];
int ret = recvfrom(..., (char*)&buffer[0], sizeof(buffer), ...);

Winsock most certainly does NOT have a 1480 byte limit on messages.

Share:
19,376
Gabriel Sanmartin
Author by

Gabriel Sanmartin

Updated on June 04, 2022

Comments

  • Gabriel Sanmartin
    Gabriel Sanmartin almost 2 years

    I'm sending from a .Net application 1404 float values which make up for 5616 bytes through an udp socket. I get no exceptions off this operation.

    However, the program receiving those data, is a C++ application, and when receiving such amount of data I get a 10040 message too long error.

    Apparently 1480bytes is the longest size possible for messages in Wsock2.

    What would be the easiest, cleanest way to fix this?

    Thanks!

    EDIT: Posting some code:

    This is my socket J_Receive class:

    #include "J_Receive.h"
    
    
    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #if defined (WIN32) && !defined(__CYGWIN__)
    #include <winsock.h>
    #else
    #include <unistd.h>
    #include <sys/uio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <sys/time.h>
    #endif
    #include <string.h>
    
    #include <iostream>
    
    using namespace sockets;
    
    J_Recibir::J_Recibir( void )
    {
        _port = 0;
        _initialized = false;
        _buffer = 0L;
    }
    
    J_Recibir::~J_Recibir( void )
    {
    #if defined (WIN32) && !defined(__CYGWIN__)
        closesocket( _so);
    #else
        close( _so );
    #endif
    }
    
    bool J_Recibir::init( void )
    {
    #if defined(WIN32) && !defined(__CYGWIN__)
        WORD version = MAKEWORD(1,1);
        WSADATA wsaData;
        // First, we start up Winsock
        WSAStartup(version, &wsaData);
    #endif
    
        if( _port == 0 )
        {
        fprintf( stderr, "Receiver::init() - port not defined\n" );
        return false;
        }
    
        if( (_so = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 )
        {
            perror( "Socket" );
        return false;
        }
    
    
    
        /*int buffsize  = 50000;
        setsockopt( _so, SOL_SOCKET, SO_RCVBUF, (const char*)&buffsize, sizeof(buffsize));*/
    
    #if defined (WIN32) && !defined(__CYGWIN__)
    //    const BOOL on = TRUE;
    //    setsockopt( _so, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, sizeof(int));
    #else
        int on = 1;
        setsockopt( _so, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    #endif
    
    
    
    
    //    struct sockaddr_in saddr;
        saddr.sin_family = AF_INET;
        saddr.sin_port   = htons( _port );
    #if defined (WIN32) && !defined(__CYGWIN__)
        saddr.sin_addr.s_addr =  htonl(INADDR_ANY);
    #else
        saddr.sin_addr.s_addr =  0;
    #endif
    
        if( bind( _so, (struct sockaddr *)&saddr, sizeof( saddr )) < 0 )
        {
            perror( "bind" );
            return false;
        }
    
        u_long iMode = 1;       // 1 para No bloqueante, 0 para bloqueante
        ioctlsocket(_so, FIONBIO, &iMode);
    
        _initialized = true;
        return _initialized;
    }
    
    
    void J_Recibir::setPort( const short port )
    {
        _port = port;
    }
    
    void J_Recibir::setBuffer( void *buffer, const unsigned int size )
    {
        _buffer = buffer;
        _buffer_size = size;
    }
    
    int J_Recibir::sync( void )
    {
        if(!_initialized) init();
    
        if( _buffer == 0L )
        {
            fprintf( stderr, "Receiver::sync() - No buffer\n" );
            return -1;
        }
    
    #if defined(__linux) || defined(__FreeBSD__) || defined( __APPLE__ )
        socklen_t 
    #else
        int
    #endif
            size = sizeof( struct sockaddr_in );
    
        fd_set fdset;
        FD_ZERO( &fdset );
        FD_SET( _so, &fdset );
    
        struct timeval tv;
        tv.tv_sec = 0;
        tv.tv_usec = 0;
    
    #if defined (WIN32) && !defined(__CYGWIN__)
    //    saddr.sin_port   = htons( _port );
        recvfrom( _so, (char *)_buffer, _buffer_size, 0, (sockaddr*)&saddr, &size );
    
    
    //    recvfrom(sock_Receive, szMessage, 256, 0, (sockaddr*)&addr_Cli, &clilen)
        int err = WSAGetLastError ();
        if (err!=0){
            fprintf( stderr, "Receiver::sync() - error %d\n",err );
            perror("Error: ");
        }
    
        while( select( _so+1, &fdset, 0L, 0L, &tv ) )
        {
            if( FD_ISSET( _so, &fdset ) )
            {
                recvfrom( _so, (char *)_buffer, _buffer_size, 0, (sockaddr*)&saddr, &size );
            }
        }
    #else
        recvfrom( _so, (caddr_t)_buffer, _buffer_size, 0, 0, &size );
        while( select( _so+1, &fdset, 0L, 0L, &tv ) )
        {
            if( FD_ISSET( _so, &fdset ) )
            {
                recvfrom( _so, (caddr_t)_buffer, _buffer_size, 0, 0, &size );
            }
        }
    #endif
    
        if (err!=0) return -1;
        else        return 0;
    }
    

    And this is how I call the receive function:

         sockets::J_Receiver receiverGUI = new sockets::J_Recibir();
         receiverGUI->setPort(4020);
         nDatosGUI = 1404;
         float* datosGUI = new datosGUI[nDatosGUI ];
         receiverGUI->setBuffer((void *)datosGUI, sizeof(float)*nDatosGUI);
    
  • Gabriel Sanmartin
    Gabriel Sanmartin about 12 years
    So this code should work: int buffsize = 50000; setsockopt( _so, SOL_SOCKET, SO_RCVBUF, &buffsize, sizeof(buffsize)); Yet I can't compile because setsockopt requires a const char* and using a cast does nothing :(
  • Gabriel Sanmartin
    Gabriel Sanmartin about 12 years
    According to this post: stackoverflow.com/questions/2566915/setsockopt-sys-socket-h Using an int should work, which leaves me puzzled :$
  • Some programmer dude
    Some programmer dude about 12 years
    @kelmer That should work, you should just cast the parameter: (const char *) &buffsize
  • Gabriel Sanmartin
    Gabriel Sanmartin about 12 years
    I just did, I now get the same 10040 error plus a 10035 resource temporarily unavailable, alternatively...
  • Gabriel Sanmartin
    Gabriel Sanmartin about 12 years
    Which, now that I tried again, is the same that happened before lol
  • Some programmer dude
    Some programmer dude about 12 years
    @kelmer Error 10035 is WSAEWOULDBLOCK, which means you try to read from a non-blocking socket and it has no data to read. About the buffer size, after you set the size, use getsockopt to get the actual size it have, because the system may not honor your request.
  • Gabriel Sanmartin
    Gabriel Sanmartin about 12 years
    It does seem that the receive buffer is set to 50000, yet I keep receiving the 10040 error. I'll see if the problem is in the sender, then.
  • Gabriel Sanmartin
    Gabriel Sanmartin about 12 years
    I send from a 1404 float buffer and receive to a 1404 float buffer as well. Shouldn't that be the same size?
  • Seth Noble
    Seth Noble about 12 years
    No, your buffer needs to be big enough to handle any datagram which might arrive. Firewalls aside, you could receive any sized datagram from anywhere at any time, not just from your sending program. So at the very least you need to prevent those from choking your receive queue. But it is more likely that you are sending more data than you mean to. It would help to see the code.
  • Gabriel Sanmartin
    Gabriel Sanmartin about 12 years
    You were all right, I was sizing my buffer wrong, now it's properly sized to 5616 bytes, but now the program just hangs forever, does this have to do with blocking sockets?
  • Gabriel Sanmartin
    Gabriel Sanmartin about 12 years
    I posted some code. My program seems to be executing the receive function fine the first two times, then I get a 10038 error and it hangs. The program works fine with a smaller buffer.
  • Seth Noble
    Seth Noble about 12 years
    Check the semantics of select(): its return is not a boolean, you need to check it for error, zero, or a count. Also, the first argument should not involve your socket descriptor, it is a count which should be 1 in this case. Finally, calling select with a 0 timeout means it will return immediately regardless of whether there is data is ready. You probably want either NULL to wait indefinitely, or a value like 100ms if you want to watch for some sort of quit signal. In any case, you need to pay attention to the select() return value and handle all three cases.
  • Gabriel Sanmartin
    Gabriel Sanmartin about 12 years
    Will try that (can't do it now), thanks. To be honest, I don't strictly get what that while loop does (I got the class from the Internet :P)... If it helps, what I did found out is that when the socket fails and the program hangs (which is in the second or third call of the thread) the values of the object seem to be reset, as "initialized" goes back to false and "port" is set to zero, even if the object is never reset or destroyed. That's probalby the origin of the 10038 error, but why?
  • Seth Noble
    Seth Noble about 12 years
    The loop is how you read more than one message. select() is intended to block on one or more descriptors until one or more have them becomes available. When it returns, you figure out from its return value and the descriptor sets which descriptors need attention and do whatever you need to do. Typically, you would loop on a control variable, such as while (!Done) which lets you break out when some quit condition occurs or if a fatal error ocurrs. Remember that select() modifies the descriptors sets, so you must reset them every time (or keep a spare copy).
  • Gabriel Sanmartin
    Gabriel Sanmartin about 12 years
    Ok, by checking select and stopping with an error, the program does not crash. However, I found out the problem was not on the socket, I do receive my data in the first frame (this is a rendering loop application), but strangely on the subsequent frames I lose the reference to all of my objects, so I'll go dig up the cause that way. Thanks guys!