Without adns_if_noautosys, adns would attempt read() on its TCP client
socket immediately after getting EINPROGRESS from connect(), and
assume that EAGAIN/EWOULDBLOCK means the socket is connected.
This is actually not correct on any platform that I'm aware of.
However, on Linux, write() on a socket which is being connected
returns EAGAIN, so everything seemed to work - adns would think that
the socket's window was full and wait for it to become writeable. On
many other platforms, write() on such a socket returns ENOTCONN.
The result is that adns's TCP support may fail to work properly on
such platforms, especially if the nameserver is not localhost. (A
connect to a suitable server on localhost often completes immediately,
which avoids exposing the bug.) adns might fail to be able to do TCP
at all.
We detect the completion (successful or otherwise) of connect() by
selecting the fd (as contemplated by SuS). This might expose us to
spurious fd writeability indications, if such things exist, but the
nonblocking connect API demands that they don't at least in this case.
We always do this select check, in adns_processwriteable. In theory
this is sometimes unnecessary, because adns_processwriteable's caller
has probably just got a writeability indication from poll or select.
But adns should not assume that its caller will never feed it spurious
events, and there seems little point optimising away one syscall per
tcp connection (given that adns reuses the connection where possible.)
This behaviour naturally causes a lot of the regression tests to fail.
So in this commit we also update all the regression tests. This has
been done in a programmatic way, by running
perl -i ./update-extra-select case-*.sys
update-extra-select is supplied in this commit. It is a (hopefully
easy to understand) script which adds a select just before every
applicable read. The pretended select always reports that the fd is
useable, which is what would justify adns's subsequent behaviour.
(Most of the tests run with adns_if_noautosys - since that's the
default and has to be toggled off - and in those cases the socket has
in any case just been reported as writeable.)
Note that regress/update-extra-select is not idempotent. Here, it has
been used exactly once. (It is going to be deleted again in the next
commit.)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
19 files changed:
* Portability fix for systems where socklen_t is bigger than int.
* Fix for malicious optimisation of memcpy in test suite, which
causes failure with gcc-4.1.9 -O3. See Debian bug #772718.
* Portability fix for systems where socklen_t is bigger than int.
* Fix for malicious optimisation of memcpy in test suite, which
causes failure with gcc-4.1.9 -O3. See Debian bug #772718.
+ * Fix TCP async connect handling. The bug is hidden on Linux and on most
+ systems where the nameserver is on localhost. If it is not hidden,
+ adns's TCP support is broken unless adns_if_noautosys is used.
select max=6 rfds=[4] wfds=[5] efds=[] to=13.987562
select=1 rfds=[] wfds=[5] efds=[]
+0.001172
select max=6 rfds=[4] wfds=[5] efds=[] to=13.987562
select=1 rfds=[] wfds=[5] efds=[]
+0.001172
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=OK
.
read fd=5 buflen=1
read=OK
.
write fd=5
003b311f 01000001 00000000 00000574 72756e63 04746573 74036977 6a0a7265
6c617469 76697479 08677265 656e656e 64036f72 6702756b 00000c00 01.
write fd=5
003b311f 01000001 00000000 00000574 72756e63 04746573 74036977 6a0a7265
6c617469 76697479 08677265 656e656e 64036f72 6702756b 00000c00 01.
select max=6 rfds=[4] wfds=[5] efds=[] to=13.992868
select=1 rfds=[] wfds=[5] efds=[]
+0.001011
select max=6 rfds=[4] wfds=[5] efds=[] to=13.992868
select=1 rfds=[] wfds=[5] efds=[]
+0.001011
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
003b311f 01000001 00000000 00000574 72756e63 04746573 74036977 6a0a7265
6c617469 76697479 08677265 656e656e 64036f72 6702756b 00000c00 01.
write fd=5
003b311f 01000001 00000000 00000574 72756e63 04746573 74036977 6a0a7265
6c617469 76697479 08677265 656e656e 64036f72 6702756b 00000c00 01.
select max=6 rfds=[4] wfds=[5] efds=[] to=13.991978
select=1 rfds=[] wfds=[5] efds=[]
+0.001038
select max=6 rfds=[4] wfds=[5] efds=[] to=13.991978
select=1 rfds=[] wfds=[5] efds=[]
+0.001038
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
003b311f 01000001 00000000 00000574 72756e63 04746573 74036977 6a0a7265
6c617469 76697479 08677265 656e656e 64036f72 6702756b 00000c00 01.
write fd=5
003b311f 01000001 00000000 00000574 72756e63 04746573 74036977 6a0a7265
6c617469 76697479 08677265 656e656e 64036f72 6702756b 00000c00 01.
select max=6 rfds=[4] wfds=[5] efds=[] to=13.996770
select=1 rfds=[] wfds=[5] efds=[]
+1.-14443
select max=6 rfds=[4] wfds=[5] efds=[] to=13.996770
select=1 rfds=[] wfds=[5] efds=[]
+1.-14443
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EHOSTUNREACH
read fd=5 buflen=1
read=EHOSTUNREACH
close fd=5
close=OK
+0.000146
close fd=5
close=OK
+0.000146
select max=6 rfds=[4] wfds=[5] efds=[] to=13.998787
select=1 rfds=[] wfds=[5] efds=[]
+0.000135
select max=6 rfds=[4] wfds=[5] efds=[] to=13.998787
select=1 rfds=[] wfds=[5] efds=[]
+0.000135
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
003b311f 01000001 00000000 00000574 72756e63 04746573 74036977 6a0a7265
6c617469 76697479 08677265 656e656e 64036f72 6702756b 00000c00 01.
write fd=5
003b311f 01000001 00000000 00000574 72756e63 04746573 74036977 6a0a7265
6c617469 76697479 08677265 656e656e 64036f72 6702756b 00000c00 01.
select max=6 rfds=[4] wfds=[5] efds=[] to=1.987296
select=1 rfds=[] wfds=[5] efds=[]
+0.000949
select max=6 rfds=[4] wfds=[5] efds=[] to=1.987296
select=1 rfds=[] wfds=[5] efds=[]
+0.000949
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
002b3123 01000001 00000000 00000332 35340130 02393903 32303307 696e2d61
64647204 61727061 00000c00 01.
write fd=5
002b3123 01000001 00000000 00000332 35340130 02393903 32303307 696e2d61
64647204 61727061 00000c00 01.
select max=6 rfds=[4] wfds=[5] efds=[] to=13.539402
select=1 rfds=[] wfds=[5] efds=[]
+0.008807
select max=6 rfds=[4] wfds=[5] efds=[] to=13.539402
select=1 rfds=[] wfds=[5] efds=[]
+0.008807
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
002b3123 01000001 00000000 00000332 35340130 02393903 32303307 696e2d61
64647204 61727061 00000c00 01.
write fd=5
002b3123 01000001 00000000 00000332 35340130 02393903 32303307 696e2d61
64647204 61727061 00000c00 01.
select max=6 rfds=[4] wfds=[5] efds=[] to=0.562305
select=1 rfds=[] wfds=[5] efds=[]
+0.001347
select max=6 rfds=[4] wfds=[5] efds=[] to=0.562305
select=1 rfds=[] wfds=[5] efds=[]
+0.001347
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
002b3123 01000001 00000000 00000332 35340130 02393903 32303307 696e2d61
64647204 61727061 00000c00 01.
write fd=5
002b3123 01000001 00000000 00000332 35340130 02393903 32303307 696e2d61
64647204 61727061 00000c00 01.
select max=6 rfds=[4] wfds=[5] efds=[] to=1.939813
select=1 rfds=[] wfds=[5] efds=[]
+0.001860
select max=6 rfds=[4] wfds=[5] efds=[] to=1.939813
select=1 rfds=[] wfds=[5] efds=[]
+0.001860
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
002b3123 01000001 00000000 00000332 35340130 02393903 32303307 696e2d61
64647204 61727061 00000c00 01.
write fd=5
002b3123 01000001 00000000 00000332 35340130 02393903 32303307 696e2d61
64647204 61727061 00000c00 01.
recvfrom fd=4 buflen=512
recvfrom=EAGAIN
+0.000116
recvfrom fd=4 buflen=512
recvfrom=EAGAIN
+0.000116
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
002b3123 01000001 00000000 00000134 03323034 02353003 31353807 696e2d61
64647204 61727061 00000c00 01.
write fd=5
002b3123 01000001 00000000 00000134 03323034 02353003 31353807 696e2d61
64647204 61727061 00000c00 01.
select max=6 rfds=[4] wfds=[5] efds=[] to=13.987312
select=1 rfds=[] wfds=[5] efds=[]
+0.000364
select max=6 rfds=[4] wfds=[5] efds=[] to=13.987312
select=1 rfds=[] wfds=[5] efds=[]
+0.000364
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
002b3123 01000001 00000000 00000134 03323034 02353003 31353807 696e2d61
64647204 61727061 00000c00 01.
write fd=5
002b3123 01000001 00000000 00000134 03323034 02353003 31353807 696e2d61
64647204 61727061 00000c00 01.
select max=6 rfds=[4] wfds=[5] efds=[] to=13.999272
select=1 rfds=[] wfds=[5] efds=[]
+0.000862
select max=6 rfds=[4] wfds=[5] efds=[] to=13.999272
select=1 rfds=[] wfds=[5] efds=[]
+0.000862
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=ECONNREFUSED
read fd=5 buflen=1
read=ECONNREFUSED
close fd=5
close=OK
+0.000109
close fd=5
close=OK
+0.000109
select max=6 rfds=[4] wfds=[5] efds=[] to=13.999414
select=1 rfds=[] wfds=[5] efds=[]
+0.000339
select max=6 rfds=[4] wfds=[5] efds=[] to=13.999414
select=1 rfds=[] wfds=[5] efds=[]
+0.000339
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=ECONNREFUSED
read fd=5 buflen=1
read=ECONNREFUSED
close fd=5
close=OK
+0.000084
close fd=5
close=OK
+0.000084
select max=6 rfds=[4] wfds=[5] efds=[] to=13.999290
select=1 rfds=[] wfds=[5] efds=[]
+0.000937
select max=6 rfds=[4] wfds=[5] efds=[] to=13.999290
select=1 rfds=[] wfds=[5] efds=[]
+0.000937
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
0035311f 01000001 00000000 00000474 65737403 69776a0a 72656c61 74697669
74790867 7265656e 656e6403 6f726702 756b0000 010001.
write fd=5
0035311f 01000001 00000000 00000474 65737403 69776a0a 72656c61 74697669
74790867 7265656e 656e6403 6f726702 756b0000 010001.
select max=7 rfds=[5] wfds=[6] efds=[] to=13.996699
select=1 rfds=[] wfds=[6] efds=[]
+0.003661
select max=7 rfds=[5] wfds=[6] efds=[] to=13.996699
select=1 rfds=[] wfds=[6] efds=[]
+0.003661
+ select max=7 rfds=null wfds=[6] efds=null to=0.000000
+ select=1 rfds=null wfds=[6] efds=null
++0.000001
read fd=6 buflen=1
read=EAGAIN
read fd=6 buflen=1
read=EAGAIN
write fd=6
0035311f 01000001 00000000 00000474 65737403 69776a0a 72656c61 74697669
74790867 7265656e 656e6403 6f726702 756b0000 010001.
write fd=6
0035311f 01000001 00000000 00000474 65737403 69776a0a 72656c61 74697669
74790867 7265656e 656e6403 6f726702 756b0000 010001.
select max=7 rfds=[5] wfds=[6] efds=[] to=13.996686
select=1 rfds=[] wfds=[6] efds=[]
+0.000977
select max=7 rfds=[5] wfds=[6] efds=[] to=13.996686
select=1 rfds=[] wfds=[6] efds=[]
+0.000977
+ select max=7 rfds=null wfds=[6] efds=null to=0.000000
+ select=1 rfds=null wfds=[6] efds=null
++0.000001
read fd=6 buflen=1
read=ECONNREFUSED
read fd=6 buflen=1
read=ECONNREFUSED
close fd=6
close=OK
+0.000617
close fd=6
close=OK
+0.000617
select max=7 rfds=[5] wfds=[6] efds=[] to=13.996721
select=1 rfds=[] wfds=[6] efds=[]
+0.278976
select max=7 rfds=[5] wfds=[6] efds=[] to=13.996721
select=1 rfds=[] wfds=[6] efds=[]
+0.278976
+ select max=7 rfds=null wfds=[6] efds=null to=0.000000
+ select=1 rfds=null wfds=[6] efds=null
++0.000001
read fd=6 buflen=1
read=EAGAIN
read fd=6 buflen=1
read=EAGAIN
write fd=6
0035311f 01000001 00000000 00000474 65737403 69776a0a 72656c61 74697669
74790867 7265656e 656e6403 6f726702 756b0000 010001.
write fd=6
0035311f 01000001 00000000 00000474 65737403 69776a0a 72656c61 74697669
74790867 7265656e 656e6403 6f726702 756b0000 010001.
select max=6 rfds=[4] wfds=[5] efds=[] to=13.997928
select=1 rfds=[] wfds=[5] efds=[]
+0.000536
select max=6 rfds=[4] wfds=[5] efds=[] to=13.997928
select=1 rfds=[] wfds=[5] efds=[]
+0.000536
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
002a311f 01000001 00000000 00000136 02343502 31380331 37320769 6e2d6164
64720461 72706100 000c0001.
write fd=5
002a311f 01000001 00000000 00000136 02343502 31380331 37320769 6e2d6164
64720461 72706100 000c0001.
select max=6 rfds=[4] wfds=[5] efds=[] to=13.997928
select=1 rfds=[] wfds=[5] efds=[]
+0.000536
select max=6 rfds=[4] wfds=[5] efds=[] to=13.997928
select=1 rfds=[] wfds=[5] efds=[]
+0.000536
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
00353120 01000001 00000000 00000864 6176656e 616e740a 72656c61 74697669
74790867 7265656e 656e6403 6f726702 756b0000 010001.
write fd=5
00353120 01000001 00000000 00000864 6176656e 616e740a 72656c61 74697669
74790867 7265656e 656e6403 6f726702 756b0000 010001.
select max=6 rfds=[4] wfds=[5] efds=[] to=13.998324
select=1 rfds=[] wfds=[5] efds=[]
+1.-647444
select max=6 rfds=[4] wfds=[5] efds=[] to=13.998324
select=1 rfds=[] wfds=[5] efds=[]
+1.-647444
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
002d311f 01000001 00000000 00000331 33320237 36033232 34033139 3507696e
2d616464 72046172 70610000 0c0001.
write fd=5
002d311f 01000001 00000000 00000331 33320237 36033232 34033139 3507696e
2d616464 72046172 70610000 0c0001.
select max=6 rfds=[4] wfds=[5] efds=[] to=13.997928
select=1 rfds=[] wfds=[5] efds=[]
+0.000536
select max=6 rfds=[4] wfds=[5] efds=[] to=13.997928
select=1 rfds=[] wfds=[5] efds=[]
+0.000536
+ select max=6 rfds=null wfds=[5] efds=null to=0.000000
+ select=1 rfds=null wfds=[5] efds=null
++0.000001
read fd=5 buflen=1
read=EAGAIN
read fd=5 buflen=1
read=EAGAIN
write fd=5
002a311f 01000001 00000000 00000136 02343502 31380331 37320769 6e2d6164
64720461 72706100 000c0001.
write fd=5
002a311f 01000001 00000000 00000136 02343502 31380331 37320769 6e2d6164
64720461 72706100 000c0001.
--- /dev/null
+#!/usr/bin/perl -wp
+use strict;
+
+our ($fd, $timeadj);
+
+BEGIN {
+ $fd = -1;
+}
+
+if (m/^ connect fd=(\d+) /) {
+ $fd=$1; next;
+}
+
+if (m/^ read fd=$fd buflen=1$/) {
+ die if $timeadj;
+ print
+ " select max=".($fd+1)." rfds=null wfds=[$fd]".
+ " efds=null to=0.000000\n".
+ " select=1 rfds=null wfds=[$fd] efds=null\n".
+ "+0.000001\n";
+ $timeadj = -0.000001;
+}
+
+if (m/^ \+([0-9.]+)$/ && $timeadj) {
+ $_ = sprintf " +%.6f\n", $1 + $timeadj;
+ $timeadj = 0;
+}
assert(ads->tcprecv.used==0);
assert(ads->tcprecv_skip==0);
for (;;) {
assert(ads->tcprecv.used==0);
assert(ads->tcprecv_skip==0);
for (;;) {
+ /* This function can be called even if the fd wasn't actually
+ * flagged as writeable. For asynch tcp connect we have to
+ * actually use the writeability to tell us the connect has
+ * completed (or failed), so we need to double check. */
+ fd_set writeable;
+ struct timeval timeout = { 0,0 };
+ FD_ZERO(&writeable);
+ FD_SET(ads->tcpsocket,&writeable);
+ r= select(ads->tcpsocket+1,0,&writeable,0,&timeout);
+ if (r==0) break;
+ if (r<0) {
+ if (errno==EINTR) continue;
+ adns__tcp_broken(ads,"select","failed connecting writeability check");
+ r= 0; goto xit;
+ }
+ assert(FD_ISSET(ads->tcpsocket,&writeable));
if (!adns__vbuf_ensure(&ads->tcprecv,1)) { r= ENOMEM; goto xit; }
r= read(ads->tcpsocket,&ads->tcprecv.buf,1);
if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {
if (!adns__vbuf_ensure(&ads->tcprecv,1)) { r= ENOMEM; goto xit; }
r= read(ads->tcpsocket,&ads->tcprecv.buf,1);
if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {