sergico
sergico

Reputation: 2621

setsockopt() not returning error when setting a big socket recv buffer

I'm testing the funcion setsockopt() with the below code and I'm getting a behavior I don't understand: Below is the code snippet I'm running (compiled on Ubuntu 12.04 64bit, Qt 4.8.x):

#include <QCoreApplication>

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <QDebug>

#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>

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

    int sock = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    int res;
    int bufferSizeByte = QString(argv[1]).toInt();

    qDebug() << "Setting socket buffer size to" << bufferSizeByte << "bytes";
    res = setsockopt( sock, SOL_SOCKET, SO_RCVBUF, (void*)&bufferSizeByte, sizeof(bufferSizeByte) );
    if ( -1 == res )
    {
        qDebug() << "ERROR setting socket buffer size to" << bufferSizeByte << "bytes";
    }

    /*
     *  !! WARNING !!
     *  If we try setting the buff size over the kernel max: we do not get an error
     */

    int readValue = 0;
    unsigned int readLen = sizeof(readValue);
    res = getsockopt( sock, SOL_SOCKET, SO_RCVBUF, (void*)&readValue, &readLen );
    if ( -1 == res )
    {
        qDebug() << "ERROR reading socket buffer size";
    }
    else
    {
        qDebug() << "Read socket buffer size:" << readValue << "bytes";
        Q_ASSERT ( readValue == bufferSizeByte*2 );
    }


    return a.exec();
}

Basically I'm setting the recv buffer size for a socket, and reading it back to verify that the operation really succeded. Setting the buffer size to a value withing the one configured in the Linux kernel (/proc/sys/net/core/rmem_max) triggers the Q_ASSERT() as expecetd but I do not get the setsockopt error message.

For instance:

sergio@netbeast: sudo ./setsockopt 300000 
Setting socket buffer size to 300000 bytes  
Read socket buffer size: 262142 bytes  
ASSERT: "readValue == bufferSizeByte*2" in file ../setsockopt/main.cpp, line 43

What I don't get is why the setsockopt() does not return an error

Any clue?

Upvotes: 2

Views: 3170

Answers (1)

jxh
jxh

Reputation: 70492

The implementaiton of sock_setsockopt() (which is what the system call setsockopt() ends up calling in the kernel) has a comment as to why setting a too large value does not incur an error. The comment indicates the reason is for compatibility with the original BSD implementation (and thus, for software written for BSD systems to be more easily ported to Linux):

            /* Don't error on this BSD doesn't and if you think
             * about it this is right. Otherwise apps have to
             * play 'guess the biggest size' games. RCVBUF/SNDBUF
             * are treated in BSD as hints
             */

Please note that if the maximum size is not exceeded when doing so (and if the minimum value has been satisfied) what is actually stored is double the value that was passed in to SO_RCVBUF. From the man page:

SO_RCVBUF Sets or gets the maximum socket receive buffer in bytes. The kernel doubles this value (to allow space for bookkeeping overhead) when it is set using setsockopt(2), and this doubled value is returned by getsockopt(2). The default value is set by the /proc/sys/net/core/rmem_default file, and the maximum allowed value is set by the /proc/sys/net/core/rmem_max file. The minimum (doubled) value for this option is 256.

Upvotes: 5

Related Questions