If I got a file descriptor (socket fd), how to check this fd is avaiable for read/write?
In my situation, the client has connected to server and we know the fd.
However, the server will disconnect the socket, are there any clues to check it ?
You want fcntl() to check for read/write settings on the fd:
#include <unistd.h>
#include <fcntl.h>
int r;
r = fcntl(fd, F_GETFL);
if (r == -1)
/* Error */
if (r & O_RDONLY)
/* Read Only */
else if (r & O_WRONLY)
/* Write Only */
else if (r & O_RDWR)
/* Read/Write */
But this is a separate issue from when the socket is no longer connected. If you are already using select() or poll() then you're almost there. poll() will return status nicely if you specify POLLERR in events and check for it in revents.
If you're doing normal blocking I/O then just handle the read/write errors as they come in and recover gracefully.
You can use select() or poll() for this.
In C#, this question is answered here
In general, socket disconnect is asynchronous and needs to be polled for in some manner. An async read on the socket will typically return if it's closed as well, giving you a chance to pick up on the status change quicker. Winsock (Windows) has the ability to register to receive notification of a disconnect (but again, this may not happen for a long time after the other side "goes away", unless you use some type of 'keepalive' (SO_KEEPALIVE, which by default may not notice for hours, or an application-level heartbeat).
I found the recv can check. when socket fd is bad, some errno is set.
ret = recv(socket_fd, buffer, bufferSize, MSG_PEEK);
if(EPIPE == errno){
// something wrong
}
Well, you could call select(). If the server has disconnected, I believe you'll eventually get an error code returned... If not, you can use select() to tell whether you're network stack is ready to send more data (or receive it).
Related
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.
I have a socket which waits for recv and then after receiving data, sends data forward for processing. However, then it again goes for recv, and this time it receives nothing returns -1 and when printed the errno it prints 35 (which is EAGAIN).
This happens only on MAC OS Lion operating system, for other OS this runs perfectly fine
do{
rc = recv(i, buffer, sizeof(buffer), 0);
if (rc < 0){
printf("err code %d", errno);
}
if(rc == 0){
//Code for processing the data in buffer
break;
}
....
}while(1);
EDIT: Corrected indentation and errno
You either set the socket to non-blocking mode or enabled the receive timeout. Here's from recv(2) on a mac:
The calls fail if:
[EAGAIN] The socket is marked non-blocking, and the receive operation would block, or a receive timeout had been set, and the timeout expired before data were received.
Edit 0:
Hmm, apologies for quoting again. This time from intro(2):
11 EDEADLK Resource deadlock avoided. An attempt was made to
lock a system resource that would have resulted in a deadlock
situation.
...
35 EAGAIN Resource temporarily
unavailable. This is a temporary condition and later calls to the
same routine may complete normally.
Just use strerror(3) to figure out the actual issue.
Your socket is in non-blocking mode. EAGAIN is the normal return from recv() (and other system calls) when there is no data available to read. In that sense it's not really an error.
If you meant for your socket to be nonblocking then you need to monitor it to find out when it has data available and only call recv() when there is data available. Use poll() (or kqueue, which is specific to FreeBSD and MacOS) to monitor is. Usually this is done in your application's main event loop.
If you did not mean for your socket to be nonblocking, then you should set it to blocking more with fcntl():
flags = fcntl(i, F_GETFL, 0); /* add error checking here, please */
flags &= ~O_NONBLOCK;
fcntl(i, F_SETFL, flags); /* add more error checking here! */
But you should be aware that the default blocking state of sockets (and all file descriptors) is blocking, so if your socket is in nonblocking mode then that means someone or something has manually made it nonblocking.
In blocking mode, the recv call will block and wait for more data instead of returning EAGAIN (or EWOULDBLOCK which is the same thing as EAGAIN).
I am a newbie dabbling in C and my little project is to write a simple SOCKS4 proxy. Thanks to the help here i got so far to use non-blocking sockets and poll() for my routine. However at this point i seem to have 2 problems:
The outgoing Socket dstSocket doesn't get closed if the incoming Socket rcvSocket gets closed and vice versa. I don't check for this in the loop, but i don't know how. I tried POLLHUP as revents, but that doesn't seem to do the trick. A normal check seems to be whether recv() returns 0, but is that also valid for non-blocking sockets? And if so, how does that work with revents, i can't seem to figure out where i would put this, since if POLLIN | POLLPRI are set it seems to me recv() never should return 0? Also i don't understand what the exact difference is between POLLIN and POLLPRI, seems to me just a check "data is available for reading" in either case?
The proxy seems to work for connections i tested with netcat. However if i use a browser, it says (when i target a website) whether i want to save "binary data". I checked the data in wireshark and what is received from the server is correctly forwarded to the client byte by byte it seems. If anyone maybe has an idea why that could happen with this program it would be nice :)
Attached the relevant code (beware programming newbie):
fds[1].fd = dstSocket;
fds[0].fd = rcvSocket;
fds[1].events = POLLIN | POLLPRI | POLLHUP;
fds[0].events = POLLIN | POLLPRI | POLLHUP;
timer = poll(fds, 2, timeout_msecs); /* i dont use this yet */
fcntl(rcvSocket, F_SETFL, O_NONBLOCK);
fcntl(dstSocket, F_SETFL, O_NONBLOCK);
while (1 == 1)
{
if (fds[0].revents & POLLIN | POLLPRI)
{
recvMsgSize = recv(rcvSocket, rcvBuffer, RCVBUFSIZE, 0);
if (recvMsgSize > 0) {send(dstSocket, rcvBuffer, recvMsgSize, 0);}
}
if (fds[1].revents & POLLIN | POLLPRI)
{
sndMsgSize = recv(dstSocket, sndBuffer, RCVBUFSIZE, 0);
if (sndMsgSize > 0) { send(rcvSocket, sndBuffer, sndMsgSize, 0);}
}
if ((fds[0].revents & POLLHUP) || (fds[1].revents & POLLHUP))
{
close(rcvSocket);
close(dstSocket);
}
}
recv() returns 0 on a clean remote shutdown - this is true even for nonblocking sockets. In this case, POLLIN will be returned - the notification that the remote side has closed the socket is considered a "readable" event.
You shouldn't need to use POLLPRI for SOCKS / HTTP connections - it indicates TCP "urgent data", which isn't used by those protocols (or indeed, much used at all).
Apart from your direct questions, you need to do more to implement a reliable proxy:
You need to be calling poll() on every loop, not just once. The way you have it written it is busy-looping, which is generally not considered acceptable practise.
You should be setting the disposition of SIGPIPE to ignored with signal(SIGPIPE, SIG_IGN);. This allows you to gracefully handle write failures.
You should be checking the result of send(). Note that it can write less than the amount you requested - in this case, you will have to keep the unsent data buffered, return to the poll() and try sending the remaining data again if POLLOUT is raised on the socket. You only want to request POLLOUT if there is unsent data remaining, so you need to make sure .events is set correctly before every poll() call.
You should be checking errno if recv() or send() returns a value less than 0. EINTR and EWOULDBLOCK should be ignored; any other error should be treated as a connection failure.
You should not be closing both directions immediately when one socket closes - you must support asymmetric shutdowns. This means that when you see that fds[0] has been closed by the remote end, you should call shutdown(fds[1], SHUT_WR);, and vice-versa; only when both have been shutdown (or a connection failure has occured) should you call close() on both file descriptors and finish up.
I have an application that is going to work like a p2p-software where all peer are going to talk to each other. Since the communication will be TCP i thought that I could use epool(4) so that multiple connections can be handled. Since each peer will send data very often, I thought that I will establish a persistent connection to each peer that will be used under the applications lifetime.
Now, one thing that I don't know how to handle is that since the connection is never closed how do I know when i should stop receiving data with read() and call epool_wait() again to listen after more packages? Or is there a better way of dealing with persistent TCP connections?
You should set the socket to non-blocking, and when epoll indicates there is data to read
you should call read() in a loop until read() returns -1 and errno is EWOULDBLOCK
That is, your read loop could look sometihng like:
for(;;)
ssize_t ret;
ret = read(...);
if(ret == 0) {
//client disconnected, handle it, remove the fd from the epoll set
break;
} else if(ret == -1) {
if(errno == EWOULDBLOCK) {
// no more data, return to epoll loop
} else {
//error occured, handle it remove the fd from the epoll set
}
break;
}
// handle the read data
}
If you're not using edge triggered mode with epoll, you don't really need the loop - you could get away with doing just 1 read and return to the epoll loop. But handle the return values just like the above code.
That should have been 'epoll', not 'epool'...not familiar with epoll, but have a look here at the Beej's guide to see an example of the sockets using 'poll'...look at section 7.2 in there to see how it is done, also look at the section 9.17 for the usage of 'poll'...
Hope this helps,
Best regards,
Tom.
read() reads as much data as is immediately available (but no more that you request). Just run read() on the active socket, with a big-enough buffer (you probably don't need it bigger than your MTU… 2048 bytes will do) and call epoll_wait() when it completes.
From one thread I got the following code:
int next_stuff(char **code){
...
len=read(file_desc,buffer+end_len,packet_size-end_len);
if(len<=0)
{
if(len==-1 && errno==EAGAIN) return(0);
else return(-1);
}
...
}
while (next_stuff(&buff) == 0)
{
...
}
On the other thread I'd like to finish that socket and exit this operation, but only doing a
close(file_desc);
does not cause read to return nonblocked. Am I missing something?
EDIT:
shutdown does not work as well. And I am trying that on Linux 2.6.23
shutdown(fd, SHUT_RD);
$ man -s 2 shutdown
NAME
shutdown -- shut down part of a full-duplex connection
SYNOPSIS
#include <sys/socket.h>
int shutdown(int socket, int how);
DESCRIPTION
The shutdown() call causes all or part of a full-duplex connection on the socket
associated with socket to be shut down.
If how is SHUT_RD, further receives will be disallowed. If how is
SHUT_WR, further sends will be
disallowed. If how is SHUT_RDWR, further sends and receives will be disallowed.
RETURN VALUES
The shutdown() function returns the value 0 if successful; otherwise the value -1 is
returned and the global variable errno is set to indicate the error.
In general, if you do not want blocking socket calls, you would use select() to see if the socket is ready to read, write, or is in the error state. In addition, pass a timeout value to select() so that this call isn't blocking forever. After the select() call returns, you can see if the application wants to quit and if so do the "right" thing (that's for you to decide).
If your read() call is nonblocking, it should return fairly fast, as all it will be doing is inserting memory.
To prevent doing any damage, you would use a mutex around your call to read() and close() such that they cant both run at the same time.
If your socket is blocking, i think you should make it nonblocking.
The other answers about non-blocking sockets are good, and I recommend recoding to use that approach.
As a direct answer to your question, though, try calling shutdown() and see if that will break the other thread out of read. I'm afraid close() is just decrementing the usage count, while shutdown() will actively tear down the socket.
I don't think you've provided enough information to answer this question, yet. For example if the socket that you've opened is UDP, then a close on the sending side will have no effect on the receiving side. If it is TCP, then something else is broken. I suggest that if you are really dealing with sockets, you use recv or recvfrom instead of read.
In the case of TCP, your read will return 0 bytes, an indication that the other side has closed the connection.
If you are really doing this between two threads instead of two processes, a pipe may be more appropriate. That's not to say that a pipe could not also be used between two separate processes, it just takes a bit more set up in that case.