0

Right now, I am trying to specify options with setsockopt() using the following code:

// bind socket
// Use setsockopt() function to make sure the port is not in use
int yes = 1;
setsockopt(TCPSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
setsockopt(TCPSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
status = bind(TCPSocket, host_info_list->ai_addr, host_info_list->ai_addrlen);
if (status == -1)  std::cout << "bind error" << std::endl ;

// listen for connections
status =  listen(TCPSocket, 5);
if (status == -1)  std::cout << "listen error" << std::endl ;

int new_sd;
struct sockaddr_storage their_addr;
socklen_t addr_size = sizeof(their_addr);
new_sd = accept(TCPSocket, (struct sockaddr *)&their_addr, &addr_size);
if (new_sd == -1) std::cout << "listen error" << std::endl ;

Note tv is an already-specified timeval.

When I make only the first setsockopt() call, everything works fine. However, with the addition of the second (which does not return any errors), I encounter the second "listen error" specified in the code. I'm not sure why setting the timeout value affect this, can someone explain?

I do not take credit for the code specified; it is modified from the code presented in the tutorial here: http://codebase.eu/tutorial/linux-socket-programming-c/

Bobazonski
  • 1,515
  • 5
  • 26
  • 43
  • How do you know it doesn't return any errors (the second call) ? you don't do any return value check or `errno` access? By the way, what do you think `SO_RCVTIMEO` does? What do you expect to set in the second call? perhaps your idea of that parameter is not the right one. – Luis Colorado Nov 24 '15 at 11:10

2 Answers2

2

If you see a TCP state diagram like this one you see there's a state called TIME_WAIT when actively closing a socket. This state can take some time before it ends, up to four minutes according to RFC793.

While the socket is in the TIME_WAIT you can not bind to an interface using the same address-port pair as the socket that is in the wait state. Setting the SO_REUSEADDR flag om a socket enables other sockets to bind to the address when the current socket (with the flag set) is in the TIME_WAIT state.

The SO_REUSEADDR option is most useful for server (passive, listening) sockets.


As for your problem, after each call to setsockopt check what it returns, and if it's -1 then you check errno to see what went wrong. You can use perror or strerror to print or get a printable string for the error, like

if (setsockopt(TCPSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0)
{
    std::cerr << "Error setting the SO_REUSEADDR: " << strerror(errno) << '\n';
    // Do something appropriate
}
Community
  • 1
  • 1
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thanks for the explanation, I think I understand why that option is necessary (I am using that port with each subsequent run of my program!). I tried your suggestion and do not encounter any errors, but get an error later in the program (note there are no errors when not specifying the timeout options). I will edit my question to reflect this. – Bobazonski Nov 23 '15 at 07:08
0

Joachim's solution did a great job of answering my intial question and explaining setsockopt(). To answer my own question after realizing the issue was further down in the code, the timeout affects the server being able to listen to a port. Say the timeout is only 10ms, the server must be started, then the client, and a connection must be established in that time. This wasn't happening in my case, thus the resulting error.

Bobazonski
  • 1,515
  • 5
  • 26
  • 43