1

Let's suppose I've created a listening socket:

sock = socket(...);
bind(sock,...);
listen(sock, ...);

Is it possible to do epoll_wait on sock to wait for incoming connection? And how do I get client's socket fd after that?

The thing is on the platform I'm writing for sockets cannot be non-blocking, but there is working epoll implementation with timeouts, and I need to accept connection and work with it in a single thread so that it doesn't hang if something goes wrong and connection doesn't come.

olegst
  • 1,209
  • 1
  • 13
  • 33
  • 1
    Yes, you need to set the socket to non_blocking mode and should do an accept once you get any read event eg : https://stackoverflow.com/questions/29729561/asynchronous-c-client-for-a-multiclient-c-server – Akhil Thayyil Dec 13 '17 at 08:10
  • 1
    Non-blocking is not needed. Just poll for the listening socket to be *readable*. – Some programmer dude Dec 13 '17 at 08:16

2 Answers2

0

Without knowing what this non-standard platform is it's impossible to know exactly what semantics they gave their epoll call. But on the standard epoll on Linux, a listening socket will be reported as "readable" when an incoming connection arrives, and then you can accept the connection by calling accept. If you leave the socket in blocking mode, and always check for readability using epoll's level-triggered mode before each call to accept, then this should work – the only risk is that if you somehow end up calling accept when no connection has arrived, then you'll get stuck. For example, this could happen if there are two processes sharing a listening socket, and they both try to accept the same connection. Or maybe it could happen if an incoming connection arrives, and then is closed again before you call accept. (Pretty sure in this case Linux still lets the accept succeed, but this kind of edge case is exactly where I'd be suspicious of a weird platform doing something weird.) You'd want to check these things.

Non-blocking mode is much more reliable because in the worst case, accept just reports that there's nothing to accept. But if that's not available, then you might be able to get away with something like this...

Nathaniel J. Smith
  • 11,613
  • 4
  • 41
  • 49
-1

Since this answer is the first up in the results in duckduckgo. I will just chime in to say that under GNU/Linux 4.18.0-18-generic (Ubuntu 18.10).

The asynchronously accept an incoming connection using one has to watch for errno value EWOULDBLOCK (11) and then add the socket to epoll read set.

Here is a small shot of scheme code that achieves that:

(define (accept fd)
  (let ((out (socket:%accept fd 0 0)))
    (if (= out -1)
        (let ((code (socket:errno)))
          (if (= code EWOULDBLOCK)
              (begin
                (abort-to-prompt fd 'read)
                (accept fd))
              (error 'accept (socket:strerror code))))
        out)))

In the above (abort-to-prompt fd 'read) will pause the coroutine and add fd to epoll read set, done as follow:

(epoll-ctl epoll EPOLL-CTL-ADD fd (make-epoll-event-in fd)))

When the coroutine is unpaused, the code proceed after the abort to call itself recursively (in tail-call position)

In the code I am working in Scheme, it is a bit more involving since I rely on call/cc to avoid callbacks. The full code is at source hut.

That is all.

amirouche
  • 7,682
  • 6
  • 40
  • 94