esrf changes: slsReceiver: better checking of socket buffer pars. and warn on failures

* not done. The 'setsockopt(SO_RECVBUF)' system call cannot set the socket buffer
  size lager than the specified in net.core.rmem_max. The requested value
  was 2 GB (commit 3b0e2e6), which is far too large for this application,
  so it was restored to the acceptable 100 MB value.

* The syscall does not fail if the requested buffer size is larger than
  net.core.rmem_max. Use 'setsockopt(SO_RECVBUFFORCE)' to actually force a
  value larger than the system limit, which can be done if run in a
  privileged context (capability CAP_NET_ADMIN set).

* The real value is read with 'getsockopt(SO_RECVBUF)'. If it
  corresponds to twice the requested value (see 'man 7 socket'), it is
  printed in green, otherwise it is signalled in red.

* The 'setsockopt(SO_RECVBUFFORCE)' syscall removes the need to write to
  /proc/sys/net/core/rmem_max, so this was was suppressed in the
  'UDPStandardImplementation' constructor.

* The test on EIGER detectors before setting the system
  buffers was removed. Was there for 9m/2m eiger, but one can take care of
  memory requirements using a customizable max socket buffer size(only with
  permissions). to be implmented later.

* The file /proc/sys/net/core/netdev_max_backlog is first read by the
  receiver to check is the current value is OK. If it is not, the receiver
  directly writes the good value into the file (instead of delegating to
  the system shell), printing a red error message if there is an access
  error (non-privileged user).
This commit is contained in:
maliakal_d 2018-04-26 15:22:44 +02:00
parent 16428f3828
commit 173d8f740e
3 changed files with 67 additions and 40 deletions

View File

@ -4392,7 +4392,7 @@ slsDetectorDefs::runStatus slsDetector::getRunStatus(){
int fnum=F_GET_RUN_STATUS; int fnum=F_GET_RUN_STATUS;
int ret=FAIL; int ret=FAIL;
char mess[MAX_STR_LENGTH]=""; char mess[MAX_STR_LENGTH]="";
strcpy(mess,"aaaaa"); strcpy(mess,"could not get run status");
runStatus retval=ERROR; runStatus retval=ERROR;
#ifdef VERBOSE #ifdef VERBOSE
std::cout<< "Getting status "<< std::endl; std::cout<< "Getting status "<< std::endl;

View File

@ -62,8 +62,7 @@ class sockaddr_in;
using namespace std; using namespace std;
#define DEFAULT_PACKET_SIZE 1286 #define DEFAULT_PACKET_SIZE 1286
/*#define SOCKET_BUFFER_SIZE (100*1024*1024) //100MB*/ #define SOCKET_BUFFER_SIZE (2000*1024*1024) //2GB, previously 100MB
#define SOCKET_BUFFER_SIZE (2000*1024*1024) //100MB
#define DEFAULT_BACKLOG 5 #define DEFAULT_BACKLOG 5
@ -81,7 +80,8 @@ enum communicationProtocol{
genericSocket(const char* const host_ip_or_name, unsigned short int const port_number, communicationProtocol p, int ps = DEFAULT_PACKET_SIZE) : genericSocket(const char* const host_ip_or_name, unsigned short int const port_number,
communicationProtocol p, int ps = DEFAULT_PACKET_SIZE) :
portno(port_number), portno(port_number),
protocol(p), protocol(p),
is_a_server(0), is_a_server(0),
@ -121,7 +121,7 @@ enum communicationProtocol{
return SOCK_DGRAM; return SOCK_DGRAM;
default: default:
cerr << "unknown protocol " << p << endl; cprintf(RED, "unknown protocol %d\n", p);
return -1; return -1;
} }
} }
@ -140,7 +140,9 @@ enum communicationProtocol{
*/ */
genericSocket(unsigned short int const port_number, communicationProtocol p, int ps = DEFAULT_PACKET_SIZE, const char *eth=NULL, int hsize=0): genericSocket(unsigned short int const port_number, communicationProtocol p,
int ps = DEFAULT_PACKET_SIZE, const char *eth=NULL, int hsize=0,
int buf_size=SOCKET_BUFFER_SIZE):
portno(port_number), portno(port_number),
protocol(p), protocol(p),
is_a_server(1), is_a_server(1),
@ -188,7 +190,7 @@ enum communicationProtocol{
socketDescriptor = socket(AF_INET, getProtocol(),0); //tcp socketDescriptor = socket(AF_INET, getProtocol(),0); //tcp
if (socketDescriptor < 0) { if (socketDescriptor < 0) {
cerr << "Can not create socket "<<endl; cprintf(RED, "Can not create socket\n");
return; return;
} }
@ -208,25 +210,49 @@ enum communicationProtocol{
// reuse port // reuse port
int val=1; int val=1;
if (setsockopt(socketDescriptor,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(int)) == -1) { if (setsockopt(socketDescriptor,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(int)) == -1) {
cerr << "setsockopt" << endl; cprintf(RED, "setsockopt REUSEADDR failed\n");
socketDescriptor=-1; socketDescriptor=-1;
return; return;
} }
//increase buffer size if its udp //increase buffer size if its udp
val = SOCKET_BUFFER_SIZE; if (p == UDP) {
if((p == UDP) && (setsockopt(socketDescriptor, SOL_SOCKET, SO_RCVBUF, &val, sizeof(int)) == -1)) val = buf_size;
{ int real_val = -1;
cerr << "WARNING:Could not set socket receive buffer size" << endl; socklen_t optlen = sizeof(int);
//socketDescriptor=-1; // set buffer size (could not set)
//return; if (setsockopt(socketDescriptor, SOL_SOCKET, SO_RCVBUF, &val, optlen) == -1) {
FILE_LOG(logWARNING) << "Could not set socket receive buffer size: "
<< val << " : no root privileges?";
}
// confirm size (could not get)
else if (getsockopt(socketDescriptor, SOL_SOCKET, SO_RCVBUF, &real_val, &optlen) == -1) {
FILE_LOG(logWARNING) << "Could not get socket receive buffer size";
}
// set buffer size worked if real val is twice the requested value
else if (real_val == val * 2) {
cprintf(GREEN, "UDP Socket buffer size modified to %d\n", real_val);
}
// buffer size too large
else {
// force a value larger than system limit (if run in a privileged context (capability CAP_NET_ADMIN set))
int ret = setsockopt(socketDescriptor, SOL_SOCKET, SO_RCVBUFFORCE, &val, optlen);
getsockopt(socketDescriptor, SOL_SOCKET, SO_RCVBUF, &real_val, &optlen);
if (ret == -1) {
FILE_LOG(logWARNING) << "Could not force socket receive buffer size to "
<< val << ", real size is " << real_val <<
" : no root privileges?";
} else {
cprintf(GREEN, "UDP socket buffer size modified to %d\n", real_val);
}
}
} }
if(bind(socketDescriptor,(struct sockaddr *) &serverAddress,sizeof(serverAddress))<0){ if(bind(socketDescriptor,(struct sockaddr *) &serverAddress,sizeof(serverAddress))<0){
cerr << "Can not bind socket "<< endl; cprintf(RED, "Can not bind socket\n");
socketDescriptor=-1; socketDescriptor=-1;
return; return;
} }
@ -313,7 +339,7 @@ enum communicationProtocol{
if(is_a_server && protocol==TCP){ //server tcp; the server will wait for the clients connection if(is_a_server && protocol==TCP){ //server tcp; the server will wait for the clients connection
if (socketDescriptor>0) { if (socketDescriptor>0) {
if ((file_des = accept(socketDescriptor,(struct sockaddr *) &clientAddress, &clientAddress_length)) < 0) { if ((file_des = accept(socketDescriptor,(struct sockaddr *) &clientAddress, &clientAddress_length)) < 0) {
cerr << "Error: with server accept, connection refused"<<endl; cprintf(RED, "Error: with server accept, connection refused\n");
switch(errno) { switch(errno) {
case EWOULDBLOCK: case EWOULDBLOCK:
printf("ewouldblock eagain\n"); printf("ewouldblock eagain\n");
@ -381,11 +407,11 @@ enum communicationProtocol{
socketDescriptor = socket(AF_INET, getProtocol(),0); socketDescriptor = socket(AF_INET, getProtocol(),0);
// SetTimeOut(10); // SetTimeOut(10);
if (socketDescriptor < 0){ if (socketDescriptor < 0){
cerr << "Can not create socket "<<endl; cprintf(RED, "Can not create socket\n");
file_des = socketDescriptor; file_des = socketDescriptor;
} else { } else {
if(connect(socketDescriptor,(struct sockaddr *) &serverAddress,sizeof(serverAddress))<0){ if(connect(socketDescriptor,(struct sockaddr *) &serverAddress,sizeof(serverAddress))<0){
cerr << "Can not connect to socket "<<endl; cprintf(RED, "Can not connect to socket\n");
file_des = -1; file_des = -1;
} else{ } else{
file_des = socketDescriptor; file_des = socketDescriptor;
@ -455,13 +481,13 @@ enum communicationProtocol{
tout.tv_usec = 0; tout.tv_usec = 0;
if(::setsockopt(socketDescriptor, SOL_SOCKET, SO_RCVTIMEO, &tout, sizeof(struct timeval)) <0) if(::setsockopt(socketDescriptor, SOL_SOCKET, SO_RCVTIMEO, &tout, sizeof(struct timeval)) <0)
{ {
cerr << "Error in setsockopt SO_RCVTIMEO "<< 0 << endl; cprintf(RED, "Error in setsockopt SO_RCVTIMEO %d\n", 0);
} }
tout.tv_sec = ts; tout.tv_sec = ts;
tout.tv_usec = 0; tout.tv_usec = 0;
if(::setsockopt(socketDescriptor, SOL_SOCKET, SO_SNDTIMEO, &tout, sizeof(struct timeval)) < 0) if(::setsockopt(socketDescriptor, SOL_SOCKET, SO_SNDTIMEO, &tout, sizeof(struct timeval)) < 0)
{ {
cerr << "Error in setsockopt SO_SNDTIMEO " << ts << endl; cprintf(RED, "Error in setsockopt SO_SNDTIMEO %d\n", ts);
} }
return 0; return 0;
@ -593,7 +619,7 @@ enum communicationProtocol{
return 0; return 0;
} }
} }
cerr << "Error: Could not convert hostname to internet address" << endl; cprintf(RED, "Error: Could not convert hostname to internet address\n");
return 1; return 1;
}; };
@ -611,7 +637,7 @@ enum communicationProtocol{
freeaddrinfo(res); freeaddrinfo(res);
return 0; return 0;
} }
cerr << "Error: Could not convert internet address to ip string" << endl; cprintf(RED, "Error: Could not convert internet address to ip string\n");
return 1; return 1;
} }

View File

@ -646,28 +646,29 @@ int UDPStandardImplementation::restreamStop() {
void UDPStandardImplementation::SetLocalNetworkParameters() { void UDPStandardImplementation::SetLocalNetworkParameters() {
//to increase socket receiver buffer size and max length of input queue by changing kernel settings
if (myDetectorType == EIGER)
return;
char command[255]; char command[255];
//to increase Socket Receiver Buffer size
sprintf(command,"echo $((%d)) > /proc/sys/net/core/rmem_max",RECEIVE_SOCKET_BUFFER_SIZE);
if (system(command)) {
FILE_LOG(logWARNING) << "No root privileges to change Socket Receiver Buffer size (net.core.rmem_max)";
return;
}
FILE_LOG(logINFO) << "Socket Receiver Buffer size (/proc/sys/net/core/rmem_max) modified to " << RECEIVE_SOCKET_BUFFER_SIZE ;
// to increase Max length of input packet queue // to increase Max length of input packet queue
sprintf(command,"echo %d > /proc/sys/net/core/netdev_max_backlog",MAX_SOCKET_INPUT_PACKET_QUEUE); int max_back_log;
if (system(command)) { const char *proc_file_name = "/proc/sys/net/core/netdev_max_backlog";
FILE_LOG(logWARNING) << "No root privileges to change Max length of input packet queue (net.core.rmem_max)"; {
return; ifstream proc_file(proc_file_name);
proc_file >> max_back_log;
}
if (max_back_log < MAX_SOCKET_INPUT_PACKET_QUEUE) {
ofstream proc_file(proc_file_name);
if (proc_file.good()) {
proc_file << MAX_SOCKET_INPUT_PACKET_QUEUE << endl;
cprintf(GREEN, "Max length of input packet queue "
"(/proc/sys/net/core/netdev_max_backlog) modified to %d\n",
MAX_SOCKET_INPUT_PACKET_QUEUE);
} else {
const char *msg = "Could not change max length of"
"input packet queue (net.core.netdev_max_backlog): no root privileges?";
cprintf(RED, "WARNING: %s\n", msg);
}
} }
FILE_LOG(logINFO) << "Max length of input packet queue (/proc/sys/net/core/netdev_max_backlog) modified to " << MAX_SOCKET_INPUT_PACKET_QUEUE ;
} }