Skip to content

Build on QNX.#1398

Open
infrastation wants to merge 3 commits intothe-tcpdump-group:masterfrom
infrastation:build_on_qnx
Open

Build on QNX.#1398
infrastation wants to merge 3 commits intothe-tcpdump-group:masterfrom
infrastation:build_on_qnx

Conversation

@infrastation
Copy link
Member

The SA_RESTART workaround has not been tested in any regard, other than it unblocks building of tcpdump and the resulting executable seems to work as expected.

@guyharris
Copy link
Member

The SA_RESTART workaround has not been tested in any regard, other than it unblocks building of tcpdump and the resulting executable seems to work as expected.

On UN*Xes, if SA_RESTART is set for a signal, a process blocked on, for example, a read() or recvmsg() or select() on a device or socket will, if the signal is caught and the signal handler returns, cause the operation to resume; if it's not set, the call will fail with EINTR.

The SA_RESTART behavior is appropriate for a job-control signal such as SIGTSTP or SIGSTOP, to make stopping and restarting a process with job control as transparent as possible. The non-SA_RESTART behavior is, at least for tcpdump, appropriate for signals such as SIGINTR, so that the capture loop in libpcap can check whether pcap_breakloop() was called and, if so, break out of the capture loop.

The SA_RESTART behavior means that, if the signal handler, does something and *doesn'tcallpcap_breakloop(), the capture isn't disrupted as much. *However*, in practice, the handler should *really* just set an indicator as to what this signal asked the program to do, and break out of the loop, as there are limits as to what a signal handler should do - see #638 and #840. (#840 notes that part of the problem is that pcap_breakloop()` isn't guaranteed to force the capture loop to terminate - it happens to sort of work with the BPF capturing mechanism, as the call will eventually timeout, and the timeout is short enough that the program will eventually break out of the loop.)

The Single UNIX Specification requires that SA_RESTART be supported; see the sigaction() page in the SUS.

The QNX 8.0 documentation for read() says that the EINTR behavior, rather than the restart behavior, is what it provides, and the struct sigaction documentation says the same. It may be that one or both of 1) the restart behavior was difficult to implement and 2) they don't support job control and the restart behavior was not deemed necessary is true for QNX.

So I'm not surprised that tcpdump (and the libpcap capturetest program) behave as expected, at least if you ^C them. I don't know whether QNX supports ^T and SIGINFO. The only references to SIGINFO I could find on the QNX web site is in the documentation for some XZ compression and decompression pages; the xz command documentation mentions it, but that may just be because it's copied from, for example, the FreeBSD man page for xz. The other signal that would matter is the "write out buffered output to the dump file" signal; it might be interesting to try that - but see #840, which means that doing the pcap_dump_flush() in the signal handler is not what we should be doing.

@infrastation
Copy link
Member Author

Thank you for the comment, signal handling is a demanding subject, which may also be a reason why QNX is not entirely SUS-compliant in this department. SIGINFO is not in the list of supported signals.

@guyharris
Copy link
Member

SIGINFO is not in the list of supported signals.

It's not required by POSIX/the SUS; it was originally a later BSDism ("later" as in "not in 4.2BSD or even whichever earlier 4BSD introduced the TENEXisms into the tty driver), and I think only shows up in derivatives of that later BSD, i.e. FreeBSD/NetBSD/OpenBSD/DragonFly BSD/CupertinoBSD. It's not in Linux, for example.

@infrastation
Copy link
Member Author

The code compiles, but something isn't quite right somewhere. One time after Ctrl-C I observed this instead of the final packet stats at the end:

23:42:54.827288 IP [...]
tcpdump: Unable to write output: Interrupted function call
23:42:54.827377 IP [...]

Another time (with ping running in the background) capturing icmp and printing worked fine and printed the final stats at the end more or less correctly, but capturing the same traffic on the same interface and writing it to a file captured 4 packets only. Or no packets at all (0 captured, N received by the filter, 0 dropped).

This certainly requires more testing at least to say what works and what does not, but to be able to debug this code it would be necessary to compile it in the first place anyway.

@guyharris
Copy link
Member

That sounds as if whatever indication (SIGINT or whatever) was delivered to the tcpdump process while it was interruptibly blocked while writing out packet dissections to the standard output ("tcpdump: Unable to write output: Interrupted function call").

The main-branch version of tcpdump's cleanup() signal handler for SIGINT just turns off any timers set up for -G and, if we're doing a live capture, calls pcap_breakloop(). It doesn't print statistics or exits, as You're Not Supposed To Do That Sort Of Thing In A Signal Handler.

That means that, if the interrupt hits while writing out packet dissections - or, perhaps, while writing raw packets in pcap format to a pipe - tcpdump might repair that as an error.

In systems whose write() call is Single UNIX Standard-conforming:

If write() is interrupted by a signal before it writes any data, it shall return -1 with errno set to [EINTR].

If write() is interrupted by a signal after it successfully writes some data, it shall return the number of bytes written.

However, the write's probably being done as a flush of the FILE * buffer, so the question is whether those systems' C support libraries, when flushing a FILE *, use a non-negative return vaue from write() as an indication of the number of bytes written and, if that's not equal to the number of bytes that it asked to write, leaves that data in the buffer to be flushed later or does further writes to flush it.

So this raises a bunch of issues about signals.

And that's just on UN*X. At least on UN*X, we can specify whether writes will be interrupted or restarted, on a per-signal basis, but that's what SA_RESTART does, and that's not available on QNX.

See also issue #997/pull request #998, issue #1231, issue #840, issue #638/pull request #752,

(And then there's pull request #570 - unfortunately, on non-4.4BSD-flavored systems, we have only two signals to implement the three operations "print info", "flush out the buffer for the current output file", and "rotate files". Oy.)

And it's all different on Windows.

@infrastation
Copy link
Member Author

It seems a good starting point to mention some likely side effects of the missing SA_RESTART in the new README and to see if that motivates the vendor to implement it or a contributor to develop a workaround.

Same as in libpcap.

Before:
checking for gethostbyaddr... no
checking for gethostbyaddr in -lsocket... no
checking for gethostbyaddr in -lnetwork... no
configure: error: gethostbyaddr is required, but wasn't found

After:
checking for gethostbyaddr... no
checking for gethostbyaddr in -lsocket... no
checking for gethostbyaddr in -lnetwork... no
checking for gethostbyaddr in -lsocket... yes
QNX SDP 8.0.3, cross-compiling for AArch64.

tcpdump.c:3030:32: error: 'SA_RESTART' undeclared (first use in this
  function); did you mean 'ERESTART'?
@infrastation
Copy link
Member Author

Rebased on top of the cross-compiling support and has been build-matrix-tested (i.e. builds free of compiler warnings) using QNX SDP. I do not have a good solution to the signals problem, but tcpdump that does not handle signals perfectly, but runs, seems better that tcpdump that does not build. So this is is going to be merged soon unless anyone stops me.

@guyharris
Copy link
Member

So this is is going to be merged soon unless anyone stops me.

I won't stop you. :-) Looks fine to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants