Is it possible (and safe) to make an accepting socket non-blocking? - c

I'm looking for a way to interrupt an accept() call on a blocking socket. Using signals is not an option, as this is meant to be in a library and I don't want to clutter the user signals. Using select() is another option, buf for various reason it's not very appealing in my case.
What would work well, if possible, is to set the socket to non-blocking mode (using fcntl() and O_NONBLOCK) from another thread, while the socket is blocked on an accept() call. The expected behaviour is that the accept() call will return with EAGAIN or EWOULDBLOCK in errno.
Would it indeed work like that? Is it safe? Portable?
If you know about the applicability of this method to Windows (where you need to use WSAIoctl() and FONBIO), I'm also interested.

No idea about Windows, but the behavior you want is guaranteed by POSIX:
If the listen queue is empty of connection requests and O_NONBLOCK is not set on the file descriptor for the socket, accept() shall block until a connection is present. If the listen() queue is empty of connection requests and O_NONBLOCK is set on the file descriptor for the socket, accept() shall fail and set errno to [EAGAIN] or [EWOULDBLOCK].
Source: http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html
Also, select or poll can be used to check for incoming connections by polling for the listening socket in the reading set.

In the question, You are saying that you do not want to use select (or poll or epoll) which are the best ways for IO multiplexing. I would recommend you using one another thread just for listening sockets while this is a bad idea!

Related

Is it possible to do epoll on accept event?

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.
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...
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.

are there any ways to use send or recv temporarily in blocking mode when the socket is set non-blocking

if a socket is set non-blocking,
but at a certain moment, I want to use send or recv with this socket in blocking mode,
can I temporarily sent it as blocking mode and then recover to non-blocking.
if so, how about the other way around? use send or recv temporarily in non-blocking mode if the socket is in blocking mode?
thanks!
You can use fcntl() with the O_NONBLOCK flag.
Use it to set the socket the blocking mode, send(or recv) your data and use fcntl again to set to the socket the non-blocking mode.
can I temporarily sent it as blocking mode and then recover to non-blocking.
Yes, of course, just use FIONBIO the other way round.
if so, how about the other way around? use send or recv temporarily in non-blocking mode if the socket is in blocking mode?
Yes, of course. There are two ways to do that: with FIONBIO or with the MSG_DONTWAIT flag to recv().
You could change the mode, or you could just use select() or epoll() to detect when a socket is readable/writable before performing a recv/send() that would normally block, or to simulate blocking behavior by reading/sending in a loop while the intended data is still pending.
Well, as already has been said, you can of course change the state whenever you want with the fcntl() call. However I don't really understand the requirement, because when you implement a non blocking algorithm, you can of course make it appear as if it were blocking by simply looping.
And you will need a protocoll anyway, so this seems to me as if you were relying on some particular behaviour.

Windows socket seems to be Non Duplex

I'm writing a client-server program, where the client is C++/winapi and the server is C#/.net.
the client have a loop where it reads from server (and may block the calling thread [denote t1] , which is fine with me). it also have another thread [denote t2] , that wait on an Event object with a timeout.
if the timeout is reached (and the Event is yet to be singled) the t2 thread, will write (exacly on byte) on the same socket.
The problem I have, is that it seems like the write won't return untill the read on t1 returns (in some legitimate scnerions it will never happen) , as if the socket was not full-duplex.
P.S : socket is an AF_INET/ SOCK_STREAM and I'm using Readfile and WriteFile for socket IO.
thanks.
Neither sockets not read() and write(), or send() and recv(), behave that way. You must have some synchronization of your own.
I have been programming with WinSock for over a decade, and I can assure you that sockets are always full duplex.
The only way WriteFile() (or send() or WSASend()) would block the calling thread for any amount of time is if the socket is running in blocking mode and its outbound queue of data waiting to be transmitted has been completely full (the size of the queue is controlled by the SO_SNDBUF socket option). That indicates that the other party (your C# server) is not reading inbound data from its socket endpoint and acknowledging the received data in a timely manner so your socket endpoint can remove that data from its outbound queue so new data can be accepted for transmission.
If you don't want your call to WriteFile() to block, you can either:
enable the SO_SNDTIMEO socket option to specify a timeout for blocking writes.
use select(), WSAAsyncSelect(), or WSAAsyncEvent() to detect when the socket is actually writable (ie, when it can accept data without blocking) before writing anything new to the socket.
switch to non-blocking I/O, asynchronous overlapped I/O, or I/O completion ports.

Linux sockets terminating listening thread

I have a thread that is essentially just for listening on a socket. I have the thread blocking on accept() currently.
How do I tell the thread to finish any current transaction and stop listening, rather than staying blocked on accept?
I don't really want to do non-blocking if I don't have to...
Use the select(2) call to check which fd are ready to read.
The file descriptors from call can be read with out it blocking. eg accept() on the returned fd will immediately create a new connection.
Basically you have two options, the first one is to use interrupts: i.e
http://www.cs.cf.ac.uk/Dave/C/node32.html (see the signal handler section, it also supply a th_kill example).
From accept man page:
accept() shall fail if:
EINTR
The system call was interrupted by a signal that was caught before a valid connection arrived.
Another option is to use Non blocking sockets and select(): i.e.:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzab6%2Frzab6xnonblock.htm
Anyhow, usually in multi-threaded servers there's one thread which accepts new connections and spawns other threads for each connections. Since accept()ing and than recv()ing, can delay new connections requests... (Unless you're working with one client, and then accept()ing and recieving might be OK)
Use pthread_cancel on the thread. You'll need to make sure you've installed appropriate cancellation handlers (pthread_cleanup_push) to avoid resource leaks, and you should disable cancellation except for the duration of the accept call to avoid race conditions where the cancellation request might get acted upon later by a different function than accept.
Note that, due to bugs in glibc's implementation of cancellation, this approach could lead to lost connections and file descriptor leaks. This is because glibc/NPTL provides no guarantee that accept did not already finish execution and allocate a new file descriptor for the new connection before the cancellation request is acted upon. It should be a fairly rare occurrence but it's still an issue to consider...
See: http://sourceware.org/bugzilla/show_bug.cgi?id=12683
and for a discussion of the issue: Implementing cancellable syscalls in userspace
From Wake up thread blocked on accept() call
I just used the shutdown() system call and it seems to work...

Make select() crack without writing to a file desc?

I have this thread in my application that monitors a set of client sockets. I use select() to block until a client makes a request, so that I can handle it efficiently without multiplying threads.
Now, problem is, when I add a new client to the list of clients, I have to wait for the timeout of select() (set to 10 seconds) to actually add the new socket to the listened sockets.
So I'd like to make select() crack before the timeout so that a client can be listened to immediately.
I already have a solution to that: create a dummy socketpair that I always include in my listened sockets list, and in which I write to make select() crack, but I'm hoping there's a better solution out there.
Edit:
I have no access to eventfd() because the GLibc I use is too old (and I have no mean to update it). So I might have to use a fifo or a socket.
Do you know any?
Thanks!
The usual way of waking up a select loop is to add the read end of a pipe() fd pair to the select's watching set. When you need to wake up the select loop, write some dummy data to the write end of the file descriptor.
Note that on linux you might also want to consider using an eventfd() instead of a pipe() - it may be somewhat more efficient (although less portable).
You could also handle the listen socket in the select loop instead of handing it off to another thread - this would wake up the select loop implicitly when a new client comes.
You can use the same select() call to wait for the incoming connection by including the listener socket in the FD set; this way, when it indicates that a connection is waiting, you can accept the connection without blocking and add the new file descriptor to the set.
You can raise signal to force EINTR from select(), but signal processing in multithreaded programs is black magic and socketpair() is simpler and more reliable.
You can use WSAEventSelect to link a windows socket with HEVENT and wait then linked to socket HEVENT with another descriptors using WaitForMultipleObjects.

Resources