1

When using the timer in the following code, either the "Error calling select" error appears, otherwise new data is expected:

    timeval tv;
    tv.tv_sec = 1;
    tv.tv_usec = 0;
    if( select(s + 1, &readmask, NULL, NULL, &tv ) <= 0 )
    {
         perror("Error calling select");
         return 0;
    }

What can be done on the client without breaking the session in order to avoid this error when you re-access this code?

Christophe
  • 68,716
  • 7
  • 72
  • 138
shaman888
  • 283
  • 1
  • 10
  • 1
    `perror` should display some information about the actual error (using the associated `errno` value). Please edit your question to show the complete error message. – G.M. Jan 19 '20 at 12:12

1 Answers1

2

You should not be using <= 0 as the condition since 0 means timeout and < 0 means error.

Alternative:

if(int rv = select(s + 1, &readmask, NULL, NULL, &tv ); rv > 0) {
    // success
} else if(rv == 0) {
    // timeout
} else {
    // error
}

What can be done on the client without breaking the session in order to avoid this error when you re-access this code?

If you get timeouts too quickly after you've changed the code to the above you should take a closer look at the timeout parameter. You should reinitialize it before each call to select:

"On Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do this. (POSIX.1 permits either behavior.) This causes problems both when Linux code which reads timeout is ported to other operating systems, and when code is ported to Linux that reuses a struct timeval for multiple select()s in a loop without reinitializing it. Consider timeout to be undefined after select() returns."

...

"On Linux, select() also modifies timeout if the call is interrupted by a signal handler (i.e., the EINTR error return). This is not permitted by POSIX.1."

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • As a result, it is not clear what you need to do to stop listening to the read and start recording. And then start reading again. I'm starting to guess that this can only be done multithreaded. Is this so? – shaman888 Jan 21 '20 at 03:55
  • @shaman888 That's a totally different question, but no, you don't need multithreading to do that. You can use non blocking sockets and/or the `timeout` parameter to do this. It's a different topic and probably deserves a separate question to be asked. – Ted Lyngmo Jan 21 '20 at 07:28
  • @shaman888 Do you still get "_Error calling select_" after making the change I suggested or is that problem solved? – Ted Lyngmo Jan 21 '20 at 09:12
  • There is no point in waiting any longer, since you need to interrupt the reading. – shaman888 Jan 21 '20 at 09:15
  • @shaman888 I don't understand what you mean. Do you still get "_Error calling select_" or is that solved? It should be possible to answer with _yes_ or _no_. – Ted Lyngmo Jan 21 '20 at 09:19
  • isn't it similar? if( select(s + 1, &readmask, NULL, NULL ) <= 0 ) – shaman888 Jan 21 '20 at 10:30
  • I don't consider a timeout and an error to be similar. An error often needs some special handling where the possible `errno`:s are investigated. `EINTR` is probably ok and you can restart the `select()`, `EBADF`, `EINVAL`, `EINVAL` and `ENOMEM` may all need different handling. A timeout on the other hand is usually not an exception to the normal flow. You just have to decide what to do if you get a timeout. Do you reinitialize `tv` before every `select()`? – Ted Lyngmo Jan 21 '20 at 11:32