Cannot connect to server in nonblocking mode ("Please retry current operation.")
After reenabling nonblocking sockets by applying the fix (workaround?) described in #2315 (closed) the client is unable to connect to the server at all. HTTP request is sent, but the client closes the connection before the reply arrives.
$ ./nonblocking
Error connecting: Please retry current operation.
strace shows the following:
$ strace -e connect,fcntl,fcntl64,select ./nonblocking
fcntl(4, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
connect(4, {sa_family=AF_INET, sin_port=htons(8000), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
select(5, [4], [4], [4], {tv_sec=0, tv_usec=1000}) = 1 (out [4], left {tv_sec=0, tv_usec=999})
select(5, NULL, [4], NULL, {tv_sec=0, tv_usec=0}) = 1 (out [4], left {tv_sec=0, tv_usec=0})
select(5, [4], NULL, [4], {tv_sec=0, tv_usec=1000}) = 0 (Timeout)
Error connecting: Please retry current operation.
+++ exited with 0 +++
The third select
call times out. Backtrace at this select
call:
#0 __GI___select (nfds=5, readfds=readfds@entry=0x7fffffffc6c0, writefds=writefds@entry=0x0,
exceptfds=exceptfds@entry=0x7fffffffc7c0, timeout=timeout@entry=0x7fffffffc6b0) at ../sysdeps/unix/sysv/linux/select.c:39
#1 0x00007ffff7f78f3e in shout_connection_iter__wait_for_io (con=con@entry=0x55555555aa10, for_write=for_write@entry=0,
timeout=timeout@entry=0, shout=0x55555555a490, for_read=1) at connection.c:144
#2 0x00007ffff7f7961c in shout_connection_iter__message (shout=0x55555555a490, con=0x55555555aa10) at connection.c:374
#3 shout_connection_iter (shout=<optimized out>, con=<optimized out>) at connection.c:478
#4 shout_connection_iter (con=con@entry=0x55555555aa10, shout=shout@entry=0x55555555a490) at connection.c:442
#5 0x00007ffff7f77571 in try_connect (self=self@entry=0x55555555a490) at shout.c:1333
#6 0x00007ffff7f77752 in shout_open (self=0x55555555a490) at shout.c:189
#7 0x000055555555529b in main () at nonblocking.c:66
As a result of this timeout, shout_connection_iter__wait_for_io
returns SHOUT_RS_TIMEOUT
to shout_connection_iter__message
, which then gets propagated back to shout_connection_iter
. Now due to the following condition in __iter
macro:
case SHOUT_RS_TIMEOUT: \
case SHOUT_RS_NOTNOW: \
if (con->nonblocking == SHOUT_BLOCKING_NONE) \
return SHOUTERR_RETRY; \
retry = 1; \
SHOUTERR_RETRY
is returned from shout_connection_iter
and propagated back via try_connect
and shout_open
to the caller, which is usually not prepared to handle this value (it expects SHOUTERR_SUCCESS
, SHOUTERR_CONNECTED
or SHOUTERR_BUSY
).
A one-line fix to the above:
if (con->nonblocking == SHOUT_BLOCKING_NONE) \
return SHOUTERR_BUSY; \
fixes the problem.