packetcap / go-pcap

Packet capture library and tools in native go
Apache License 2.0
26 stars 7 forks source link

Close handle without waiting for Poll to exit #43

Closed milan-zededa closed 1 year ago

milan-zededa commented 1 year ago

After recent patches, Close() now waits for an ongoing ReadPacketData to exit before unmapping memory and closing the socket. The problem is that the reader may hang on the Poll(socket) call for as long as there is no traffic matching the filter. I tried closing the socket as the first action in Close(), but for AF_PACKET socket this didn't seem to have any effect on an ongoing Poll, even if it was told to listen on POLLERR and POLLNVAL events as well.

The solution is to add non-zero timeout to the Poll call and simply keep repeating it for as long as reading is not canceled and there is no event. A new state polling was introduced, which is set while the socket is being polled by the reader. Close() is allowed to atomically change polling to cancelling. It is ensured that when polling is cancelled, reader will not touch the ring buffer anymore and exit as soon as Poll returns. This means that if Close is called during polling, it may continue unmapping memory and closing socket without waiting for the reader to exit and avoid delaying the caller.

deitch commented 1 year ago

To be clear, this is not a general poll, is it? It only adds the poll if all of the following are true:

  1. The status is reading
  2. The packet was not ready based on h.ring[flagIndex]&syscall.TP_STATUS_USER

we already had a single Poll statement there, where it polled and waited (i.e. blocking). This turns that into a poll with a timeout of 60s, so it just waits for it, and if it fails, loops again. Is that right? So we aren't getting into heavy polling here?

milan-zededa commented 1 year ago

@deitch Yes, correct. We just need to wake up once in a while from Poll to check if by any change the Handle is in the closing state. I noticed that even if Close closes the socket, the Poll is not waken up. Only traffic that matches the capture filter will. But in a situation of low/no traffic, Poll will hang and so will the go routine from which the packet reading runs. I think that 1 minute looping interval is long enough to avoid heavy polling activity, yet it means that closed handle will release reading go routine no later that 60 seconds after Close.