Hello all
 
I hope this mailing list is active, and that this is the right place to post 
to. In any case, I believe I have discovered a bug: get_selectable_fd() does 
not work well when used with pcap_open_offline(). The symptom is that if you 
use, as was the poet's intention, get_selectable_fd()'s return value in a call 
to select() and then use pcap_next() to get a packet, you will fail to read the 
last few packets if reading from a pipe (for example: reading from stdin when 
it's piped).
 
The reason is that savefile.c implements the read_op using fread, which is 
stdio and uses *buffering*, while select() is kernel IO and is unaware of the 
buffers in stdlib. So while the last packets are inside stdlib's buffer, 
select() will not see the fd as "ready for read", will never return, and you 
will never see these packets.
 
(Assume that the pipe doesn't close -- it stays open but simply has no more 
input. For example: it's the output of tcpdump -w)
 
In general, it's a bad thing to mix buffered IO (stdlib, such as 
fread,fread,fseek, etc) with kernel io (read/write/seek/select, etc).
 
There are 2 obvious solutions, with pros and cons each, and possibly more 
solutions as well:
 
1) Use setvbuf( fp, NULL, _IONBF, 0 ) inside pcap_fopen_offline. I tried this 
and it works, on both Solaris and Red-Hat. There are several drawbacks which I 
will detail later.
 
2) Stop using stdlib in savefile.c: use read instead of fread. There are only a 
handful of places to change, and it seems easy enough. The "downsize" is that 
you can't simply replace a call to fread with a call to read, because read() 
may be interrupted, so you need to loop if you get EINTR. Another downside is 
that you have to remove pcap_fopen_offline(), and replace it with something 
like pcap_fdopen_offline(). Again: no stdio at all.
 
The downsides for (1) above:
 
a) setvbuf(), in glibc, does what you want:removes buffers *also from the 
input, that is: if you use fread()*. It is *NOT* guaranteed to be the case in 
the official stdio documentation. All the documentation I found only talks 
about fwrite() and flushing. So it works for glibc, but maybe not for other 
stdio libs.
 
b) The documentation states that you must call setvbuf() prior to doing any IO 
on the FILE* object (but after having fopen'ed it, of course). In 
pcap_fopen_offline() we don't know whether somebody has done any IO on the 
FILE* object we are passed. It works well in glibc, again, because it zeros its 
read pointer, write point, in buf, out buf, the works. It may not, again, work 
well in other stdio libs, or may not work well if we've done some reading which 
is still buffered (but not consumed) even in glibc. It *does* work well if you, 
right on program start, try to pcap_open_offline( "-", errbuf ) without reading 
from stdin, but that's the only case I checked.
 
... so: distinguished forum: what do you think? Is the description enough? 
Should I provide a patch? Should I open a bug in sf.net?
 
Best,
Nitzan
-
This is the tcpdump-workers list.
Visit https://cod.sandelman.ca/ to unsubscribe.

Reply via email to