tcpdump mailing list archives
Re: Bug in libpcap: savefile.c / get_selectable_fd()
From: "Shaked, Nitzan" <nshaked () paypal com>
Date: Thu, 19 Mar 2009 09:39:46 -0000
Hello again Thanks for the reply. With your permission, I'd like to keep this up a little bit (I am actually quoting not in the original order, to cover the "easy" part first):
If that means that you can't tell the difference between "end of file
on the pipe", "no more packets available right now", and "an error occurred while reading from the pipe", as might be the case, file a bug on that.
Actually, it *will* mean that. pcap_next_ex() calls pcap_offline_read() (in the case of a savefile), which in turns calls sf_next_packet(), which does the fread(). If we introduce the notion of non-blocking, then two things happen: 1) The translation of return values from sf_next_packet() and from pcap_offline_read() cannot, indeed, distinguish between EOF / IO error / truncated packet, and needs to be somewhat changed. 2) I believe the current code doesn't have the notion of "non-blocking", which it doesn't have the notion of "I read only part of what was request, maybe half a packet, or half a header", so there will have to be a new return value just for that. See below for a more elaborate suggestion.
I think you should put the pipe in non-blocking mode and, when select() says the descriptor is readable, keep calling pcap_next() until you get an error or EOF indication.
This seems like a good idea, and I'd love to actually do it. However, there are currently several issues with it. I hope I am not overstepping my boundaries here by listing my thoughts: 1) Encapsulation. From your suggestion to put the fd in non-blocking mode, I understand you mean to actually call fcntl() myself (not from inside libpcap, since pcap_setnonblock() does nothing on savefiles). This means a flow which goes something like this: if ( is_tty(filename) || is_pipe(filename) || is_socket(filename) ... ) { fp = fopen( ... ); fcntl( fp, ... ); pcap_fopen_offline( fp, ... ); } ... I can't use pcap_open_offline(), since it will do its own fopen() and I'll lose the non-blocking effect. So in effect pcap_open_offline() becomes redundant. Everybody will have to know about the special non-blocking thing, do the logic I just mentioned above, and call pcap_fopen_offline(). 2) Bug (?) in the current code. In savefile.c, in pcap_fopen_offline(), there's an fread() to read the savefile's header. The fread goes something like "amt_read = fread( &hdr, 1, sizeof(hfr), fp )", and then asking "if ( amt_read != sizeof(hdr) )". So we're asking to read sizeof(hdr) chars (portability issue: not all platforms have 8bit chars). If we're in non-blocking mode, and reading from a pipe, say, it could be that there are only 4 bytes available right now, but there will be more available later. The current code will give an error (truncated header), because the amount returned will be 4. This raises 2 issues: 2.1) The code perhaps should do headers_read = fread( &hfr, sizeof(hdr), 1, fp ) and then ask whether headers_read==1 or not. 2.2) A more general issue, see below in #3. 3) The "non-blocking may return less than what you asked for" beast will also manifest in all other freads. For example, the fread() to read a packet header. Or the subsequent fread() to read the packet itself. In those cases, maybe half the packet is available now and the other half will be available in a subsequent call to fread(). This will happen "all" the time (well, often enough), and so cannot result in an error. Something like a state should be added here, saying "I am currently reading a packet, and expecting 200 more bytes". If you get less than 200 bytes (say 50), return a new error code (something like ERR_SF_AGAIN), and save those 50 bytes. Next time you are called continue from there until you've read all 200 (or got a "real" error, or EOF). Of course the same goes for reading the sf's header, and each packet's header. 4) Regarding the SF_ERR_AGAIN I mention above, and regarding the translation of return values from sf_next_packet() and pcap_offline_read() I mention: once we introduce the notion of non-blocking IO, it seems to me that we need to introduce new return values all across: 4.1) sf_next_packet() should return: SF_OK (value: 1), in case everything went well SF_ERR (value: -1), in case of an IO error or a truncated header/packet SF_EOF (value: 0), in case of EOF SF_AGAIN (value: -2), in case... well... that not enough data is available right now, but might be available later. 4.2) pcap_offline_read() should return: "n" (n>0), in case everything went well, return the number of packets read OFFLINE_READ_EOF (value: 0), in case sf_next_packet() returns SF_EOF OFFLINE_READ_ERR (value: -1), in case sf_next_packet() returns SF_ERR OFFLINE_READ_AGAIN (value: -2), in case sf_next_packet() returns SF_AGAIN OFFLINE_READ_BREAK_LOOP (value: -3), if we were told to break out of the loop 4.3) pcap_next_ex(), should return: PCAP_NEXT_OK (value: 1), in case everything went well PCAP_NEXT_AGAIN (value: 0), in case pcap_offline_read() returned OFFLINE_READ_AGAIN (when reading from a savefile), or read_op() returned 0 (no packets before timeout, when reading from a live capture) PCAP_NEXT_ERR (value: -1), in case pcap_offline_read() returned OFFLINE_READ_ERR (when reading from savefile), or read_op() returned -1 PCAP_NEXT_EOF (value: -2), in case pcap_offline_read() returned OFFLINE_READ_EOF Note that a return value of 0 from pcap_next_ex(), according to my suggestion, merges "no packets before timeout" when reading from live, with "no data in non-blocking" when reading a savefile. I think they have the same meaning to the application (basically: select() again and call pcap_next_ex() the next time you can). Anxiously awaiting comments, Nitzan - This is the tcpdump-workers list. Visit https://cod.sandelman.ca/ to unsubscribe.
Current thread:
- Bug in libpcap: savefile.c / get_selectable_fd() Shaked, Nitzan (Mar 17)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Guy Harris (Mar 17)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Guy Harris (Mar 17)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Shaked, Nitzan (Mar 19)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Guy Harris (Mar 19)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Shaked, Nitzan (Mar 19)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Shaked, Nitzan (Mar 22)
- Re: Bug in libpcap: savefile.c / get_selectable_fd() Guy Harris (Mar 17)