Reputation: 2621
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
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 usingsetsockopt(2)
, and this doubled value is returned bygetsockopt(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