If I want to accept a connection I call accept
, but how can I refuse a connection?
In a working socket echo client I have this if statement. In the echo
To my knowledge, that isn't how TCP works. The accept(..)
call will always return with the client details. There is no way to peek at the connection and selectively refuse.
The way you are doing it now is actually the correct way: accept and then close. In case you have another message structure over and above this layer, you can create a custom "Reject message". This option completely depends on your use case.
In case you are looking for rejecting on the basis of IP address, its not within your apps domain. Its the job of your firewall (As @Bart Friederichs says). That way, the request will not even touch the TCP stack.
Actually I want strictly one connection only on this particular port. Any other connection should ideally fail in a very obvious way.
Do not let the accept call in your control flow. Only when you wait on accept
will your program wait for a socket connection, never otherwise.
To get the behavior you want (only accept one connection at a time, other clients attempting should get a failure), there are two choices.
You can close your listen socket after you have accepted a connection. Re-create your listen socket after the accepted connection closes.
You can close newly established connections if there is already a connection in progress. If you want the client to see a TCP reset, most TCP stacks will trigger one if you enable the linger option with a timeout of 0.
struct linger lo = { 1, 0 };
setsockopt(s, SOL_SOCKET, SO_LINGER, &lo, sizeof(lo));
close(s);
It might be helpful
accept()
ing the client connection andIn standard socket APIs on most platforms, there is no way to reject a connection. You must accept()
the connection and then close it immediately if you don't want it.
The exception to this rule is the Winsock-specific WSAAccept() function. It provides a callback that allows an application to decide, on a per-connection basis, whether a connection should be accepted, rejected, or kept in the backlog queue.
A little late to the party, but you can use WSAAccept() instead of accept(). WSAAccept() has an optional callback function that allows you to take a peek at who's knocking at the door and decide if you want to answer. Your callback function can return the constants CF_ACCEPT, CF_REJECT and CF_DEFER. The first two are obvious. The 3rd one allows you to defer answering in case you need to decide later. Once you've decided for sure you call WSAAccept() again and either accept or reject.
Unfortunately, you have to either accept or reject in order to remove the entry from the front of the listen queue. The reason I say it's unfortunate is there is an obvious difference to the connecting machine between getting rejected and never getting a response (timeout).
If a hacker is using a port scanner they'll know you're listening on the port if you reject. At that point they can start hacking their way in. It would be nice to be able to remove the entry from the front of the queue without ever doing anything with it such that whoever's on the other end doesn't know you're listening on that port.