1

I have written simple forward proxy server which accepts the connection on range of ports from the client and forwards them.

After the connection is established, I add them to a socket list which I monitor using select(). I do know better way could be using read() with one thread per fd.

I have some restrictions because of which I can not use one thread per connection and so am using select(). But then I dont get to know if client has closed the connection as select does not tell me. Is there any way to figure that out?

agent.smith
  • 9,134
  • 9
  • 37
  • 49
  • I think I found the answer. I was passing exceptfd value as NULL. :( I suppose if I pass exceptfd with same set of file descriptors which I pass in readfds then I should be good. I will try it. Let me know if there is something more. – agent.smith Aug 08 '12 at 20:46

3 Answers3

3

When select() tells you there is an event on the filedescriptors you have placed in the read set, you have to read the data by calling e.g. read() or recv().

If read() returns 0, the other end has closed its end of the connection. If read() returns -1, some error has occured, and you have to inspect errno to see what it was. If errno is EAGAIN or EWOULDBLOCK, you should simply return to your select() loop, otherwise you should close the socket.

nos
  • 223,662
  • 58
  • 417
  • 506
  • Hey, is exceptfd of any use or this suffice? – agent.smith Aug 08 '12 at 20:53
  • 1
    It's generally of little use, I'd stay away from it alltogether. See http://stackoverflow.com/questions/1342712/nix-select-and-exceptfds-errorfds-semantics – nos Aug 08 '12 at 21:02
  • one more question: In case of client crash is there any use of exceptfds? – agent.smith Aug 08 '12 at 21:07
  • No, not any useful usage at least. – nos Aug 08 '12 at 21:08
  • So, how to close socket in case of client crash? – agent.smith Aug 08 '12 at 21:15
  • @agent.smith read() returns -1 and errno is set to something appropriate. If it's just the application crashing, the TCP stack will reset the connection (i.e. send you an RST). Just note that there are many ways your host might never receive any information that the peer is gone. You either need to write something to the peer to detect that, or you need to implement an overall timeout so you can close the connection if you get no data from the peer during that timeout. – nos Aug 08 '12 at 21:29
1

When connection is closed the select return read event for the socket. When you read data from the socket after close the retuning value is 0.

Using select is better idea than using thread per connection. You can choose your own tactic between latency (more connection per one thread) and resources usage (less connections per thread).

Dmitry Poroh
  • 3,705
  • 20
  • 34
0

The fourth argument to select() takes a bitmask of file descriptors to watch for exceptions. Set the bits there just like you do for read and/or write and test them after select returns. If they are set, you can retrieve the error by calling read() normally.

Andy Ross
  • 11,699
  • 1
  • 34
  • 31
  • When connection is closed you get 0 byte-read event (eof but not the error) – Dmitry Poroh Aug 08 '12 at 20:48
  • Right, sorry. I should have made that clear. Obviously you *do* get an error if the syscall returns one though. – Andy Ross Aug 08 '12 at 20:50
  • For example if ICMP error have been received for the packets bound to the socket you'll get the error. But if connection is closed normally (with shutdown or close on remote side) and the FIN packet received via socket than you'll get read event and read 0 bytes from the socket indicating EOF. – Dmitry Poroh Aug 08 '12 at 20:56
  • There is no timeouts on data in established TCP connection. It is your own task to maintain the timeouts for the connections. – Dmitry Poroh Aug 08 '12 at 21:00
  • Yes, as soon as we receive a FIN from the other side, select reports the socket as ready for read and when we issue read, it will return 0. – Maksim Skurydzin Aug 08 '12 at 21:00
  • No FIN-marked paket can have the associated data. First you read the rest of data and then you read 0 bytes from the socket. – Dmitry Poroh Aug 08 '12 at 21:02
  • What happens if client crashed without closing the socket? – agent.smith Aug 08 '12 at 21:09
  • @DmitryPoroh That is not correct. A FIN can appear in any packet except the initial SYN packet, and it is frequently piggybacked on the last data packet by the operation of the Nagle algorithm. But the application won't see it until it has read all the buffered data first. – user207421 Aug 08 '12 at 23:31
  • @agent.smith if client crashed you have options: 1. client died and you send something to it => TCP get RST and you get the scoket write error (and may be SIGPIPE signal). 2. client died and you wouldn't send him anything => you'll get nothing. 3. client died via network disconnectivity and network devices between server and client supporess ICMP messages => you'll get nothing. Summing up: you have not guarantee from TCP socket that it ever closed. It is application level issue to keep connection alive state (by timeouts keep-alive messages or other mechanism). – Dmitry Poroh Aug 10 '12 at 18:56
  • @EJP Exactly. My statement was that event of receiving of the FIN-marked packet do not lead at once to 0-read event (it lead only after the reading the associated and buffered data even this hidden from application). – Dmitry Poroh Aug 10 '12 at 19:32
  • @DmitryPoroh I am commenting on your statement "No FIN-marked packet can have the associated data", which remains incorrect. – user207421 Aug 11 '12 at 08:30