potential bug in David Brownell's zcip code
Michael Schmidt <[email protected]> Wed, 22 Dec 2004 15:24:35 +0100
| Newsgroups | gmane.network.zeroconf.workers |
|---|---|
| Organization | University of Siegen |
| Message-ID | <[email protected]> |
--Boundary-00=_tOYyBLuh63sjBg3
Content-Type: multipart/signed;
boundary="nextPart6137151.QDFUCVXP1Q";
protocol="application/pgp-signature";
micalg=pgp-sha1
Content-Transfer-Encoding: 7bit
--nextPart6137151.QDFUCVXP1Q
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
Hi,
Now that I'm seeing a bit clearer about the legal status of David Brownell'=
s=20
zcip code, I'd like to discuss a potential bug I have discovered recently.=
=20
The bug is about time measurement and time/timeout calculation and=20
recalculation around the call to 'poll()'.=20
But first, let me explain how I understand certain parts of the code:
1. meaning of 'tv1':
if (timeout > 0) {
gettimeofday(&tv1, NULL);
tv1.tv_usec +=3D (timeout % 1000) * 1000;
if (tv1.tv_usec > 1000000) {
tv1.tv_usec -=3D 1000000;
tv1.tv_sec++;
}
tv1.tv_sec +=3D timeout / 1000;
} else if (timeout =3D=3D 0) {
timeout =3D ms_rdelay(PROBE_WAIT);
'tv1' seems to be the timeout for the subsequent call to 'poll()' as=20
"absolute" time value for finite, non-zero timeouts.
2. interpretation of 'poll()' return codes:
switch (poll(fds, 1, timeout)) {
// timeouts trigger protocol transitions
case 0:
.
. /* this is the 'timeout' branch */
.
break;
// packets arriving
case 1:
.
. /* this is the 'packet has arrived' branch */
.
break;
default:
.
. /* this is the 'error' branch */
.
3. recalculation of timeout in 'packet has arrived' branch:
// maybe adjust timeout
if (timeout > 0) {
struct timeval tv2;
gettimeofday(&tv2, NULL);
if (timercmp(&tv1, &tv2, <)) {
timeout =3D -1;
} else {
timersub(&tv1, &tv2, &tv1);
timeout =3D 1000 * tv1.tv_sec
+ tv1.tv_usec / 1000;
}
}
'tv2' is the time when the protocol has returned from 'poll()'. Apparently,=
=20
the code calculates the time difference between the expected, absolute expi=
ry=20
time ('tv1') and the current time ('tv2'). If the current time is greater,=
=20
the code seems to assume that the timeout has elapsed. In this case, the co=
de=20
also assumes that the protocol negotiation phase (PROBE/ANNOUNCE) is over,=
=20
and it may go into an infinte wait state where it would only defend the=20
successfully acquired IP address if necessary.=20
There are two problems with this:
a)
When the code is in the 'packet has arrived' branch, the timeout cannot hav=
e=20
elapsed by definition of 'poll()'. Exceeding of the timeout leads into=20
the 'timeout' branch.
b)
This code may erroneously assume that the timeout has elapsed, if an=20
unexpected ARP packet arrives within the regular, finite timeout (still in=
=20
the protocol negotiation phase), and the OS preempts the zcip code between=
=20
the return of 'poll()' and the timeout recalculation above. When the code i=
s=20
reactivated by the scheduler, the timeout may indeed have elapsed, and=20
'timercmp(&tv1, &tv2, <)' will hold true. In this case, the code will=20
erroneously assume that the protocol negotiation phase is finished, and wil=
l=20
set the subsequent timeout to -1 (infinite). zcip will seem to hang.
I can reproduce this problem here more or less consistently by executing zc=
ip=20
on more than one node concurrently, so that "unexpected" ARP request packet=
s=20
are received within the protocol negotiation phase.
I have fixed the problem by replacing 'poll()' with 'select()' and by=20
simplifying the timeout recalculation (which is an obvious consequence of=20
using 'select()'. 'select()' returns with the timeout parameter containing=
=20
the remaining timeout value when it is woken up by a packet before the=20
timeout has elapsed. This value can directly be used for re-invoking=20
'select()'. Please note that this behavior is only implemented in Linux, bu=
t=20
not in other Unices, so that my patch is not compatible with other Unices.
My patch, which applies to David Brownell's initial code posting on=20
zeroconf-workers from 26/10/04, is attached.
Any comments???
Michael
=2D-=20
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
Michael Schmidt
=2D-------------------------------------------
Institute for Digital Communications Systems
University of Siegen, Germany
=2D-------------------------------------------
http: www.dcs.uni-siegen.de
e-mail: [email protected]
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--nextPart6137151.QDFUCVXP1Q
Content-Type: application/pgp-signature
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
iD8DBQBByYOtQxcxBvLsRaoRAg7uAJ9EAYeO/snEatrCDawe/51/gfhjBwCg23M8
jr3DTFjBR+R9YkY4iIrxcNQ=
=705B
-----END PGP SIGNATURE-----
--nextPart6137151.QDFUCVXP1Q--
--Boundary-00=_tOYyBLuh63sjBg3
Content-Type: text/x-diff;
charset="us-ascii";
name="zcip.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="zcip.patch"
--- zcip.c.orig 2004-12-20 17:09:12.000000000 +0100
+++ zcip.c 2004-12-22 10:29:02.717064544 +0100
@@ -369,28 +369,28 @@
// - use it
// - defend it, within limits
while (1) {
- struct pollfd fds[1];
- struct timeval tv1;
+ fd_set rfds, efds;
+ struct timeval to, *pto;
- fds[0].fd = fd;
- fds[0].events = POLLIN | POLLERR;
- fds[0].revents = 0;
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+ FD_ZERO(&efds);
+ FD_SET(fd, &efds);
// poll, being ready to adjust current timeout
- if (timeout > 0) {
- gettimeofday(&tv1, NULL);
- tv1.tv_usec += (timeout % 1000) * 1000;
- if (tv1.tv_usec > 1000000) {
- tv1.tv_usec -= 1000000;
- tv1.tv_sec++;
- }
- tv1.tv_sec += timeout / 1000;
- } else if (timeout == 0) {
+ if (timeout == 0) {
timeout = ms_rdelay(PROBE_WAIT);
}
VDBG("...wait %ld %s nprobes=%d, nclaims=%d\n",
timeout, intf, nprobes, nclaims);
- switch (poll(fds, 1, timeout)) {
+ if (timeout == -1)
+ pto = NULL;
+ else {
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
+ pto = &to;
+ }
+ switch (select(fd + 1, &rfds, NULL, &efds, pto)) {
// timeouts trigger protocol transitions
case 0:
@@ -437,19 +437,10 @@
case 1:
// maybe adjust timeout
if (timeout > 0) {
- struct timeval tv2;
-
- gettimeofday(&tv2, NULL);
- if (timercmp(&tv1, &tv2, <)) {
- timeout = -1;
- } else {
- timersub(&tv1, &tv2, &tv1);
- timeout = 1000 * tv1.tv_sec
- + tv1.tv_usec / 1000;
- }
+ timeout = to.tv_sec * 1000 + to.tv_usec / 1000;
}
- if ((fds[0].revents & POLLIN) == 0) {
- if (fds[0].revents & POLLERR) {
+ if (FD_ISSET(fd, &rfds) == 0) {
+ if (FD_ISSET(fd, &efds) != 0) {
// FIXME: links routinely go down;
// this shouldn't necessarily exit.
fprintf(stderr, "%s %s: poll error\n",
--Boundary-00=_tOYyBLuh63sjBg3--
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/