using TCP Keep-Alives in server to get rid of idle client - linux

I have a server to collect Tcp data from different clients to a certain port. I have a scenario that whenever the client creates tcp connection and remain idle for more than let's say 30 min then I need to close the connection.
I have learned about TCP keep alive to track that the peer is dead or not and Mostly I found examples used in client side. Similarly can I used in the server side to poll the connection whether it is active or not?
Further In linux sysctl.conf , there is a configuration file to edit the values. This seems that the whole tcp connection is destroyed after certain inactivity. I am in need such that certain connection form the device are destroyed after certain time inactivity but not the whole tcp port connection closed.
I am using ubuntu to create the server to collect tcp connection. Can I use TCP Keep-Alives in server code to find the inactive client and close the particular client? or is there any other way in server side to implement such feature?
and while going through the web it is mentioned that
(getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen)
this getsockopt is for the main tcp connection and setting here seems the setting is for whole connection to the server.
However what I need is for the specific client. I have the event server code as
here client_fd is accepted and now I need to close this client_fd if next data through this client is not received within certain time.
void event_server(EV_P_ struct ev_io *w, int revents) {
int flags;
struct sockaddr_in6 addr;
socklen_t len = sizeof(addr);
int client_fd;
// since ev_io is the first member,
// watcher `w` has the address of the
// start of the _sock_ev_serv struct
struct _sock_ev_serv* server = (struct _sock_ev_serv*) w;
server->socket_len = len;
for (;;) {
if ((client_fd = accept(server->fd, (struct sockaddr*) &addr, &len)) < 0) {
switch (errno) {
case EINTR:
case EAGAIN:
break;
default:
zlog_info(_c, "Error accepting connection from client \n");
//perror("accept");
}
break;
}
char ip[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &addr.sin6_addr, ip, INET6_ADDRSTRLEN);
char *dev_ip = get_ip(ip);
server->device_ip = dev_ip;
zlog_debug(_c,"The obtained ip is %s and dev_ip is %s", ip, dev_ip);
/** check for the cidr address for config_ip **/
char *config_ip;
config_ip = get_config_ip(dev_ip, _client_map);
zlog_debug(_c,"The _config ip for dev_ip:%s is :%s", dev_ip, config_ip);
if (config_ip == NULL) {
zlog_debug(_c,"Connection attempted from unreigistered IP: %s", dev_ip);
zlog_info(_c, "Connection attempted from unregistered IP : %s", dev_ip);
AFREE(server->device_ip);
continue;
}
json_t *dev_config;
dev_config = get_json_object_from_json(_client_map, config_ip);
if (dev_config==NULL) {
zlog_debug(_c,"Connection attempted from unreigistered IP: %s", dev_ip);
zlog_info(_c, "Connection attempted from unregistered IP : %s", dev_ip);
AFREE(server->device_ip);
continue;
}
if ((flags = fcntl(client_fd, F_GETFL, 0)) < 0 || fcntl(client_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
zlog_error(_c, "fcntl(2)");
}
struct _sock_ev_client* client = malloc(sizeof(struct _sock_ev_client));
client->device_ip = dev_ip;
client->server = server;
client->fd = client_fd;
// ev_io *watcher = (ev_io*)calloc(1, sizeof(ev_io));
ev_io_init(&client->io, event_client, client_fd, EV_READ);
ev_io_start(EV_DEFAULT, &client->io);
}
}

TCP keep alives are not to detect idle clients but to detect dead connections, i.e. if a client crashed without closing the connection or if the line is dead etc. But if the client is only idle but not dead the connection is still open. Any attempts to send an empty packet (which keep-alive packets are) to the client will result in an ACK from the client and thus keep alive will not report a dead connection.
To detect idle clients instead use either timeouts for read (SO_RCVTIMEO) or use a timeout with select, poll or similar functions.

I have implemented below mechanism to detect idle status on Socket IO activity.
My Socket is wrapped in some class like UserConnection. This class has one more attribute lastActivtyTime. Whenever I get a read on write on this Socket, I will update this attribute.
I have one more background Reaper thread, which will iterate through all UserConnection objects and check for lastActivtyTime. If current time - lastActivtyTime is greater than configured threshold parameter like 15 seconds, I will close the idle connection.
In your case, when you are iterating through all UserConnections, you can check client_id and your threshold of 30 minutes inactivity to close idle connection.

Related

Linux abstract socket refuse connection on SOCK_DGRAM

I am writing a simple client-server app using AF_UNIX sockets, but my code does not work. When I want to send to socket I get transport endpoint not connected error. Any advices?
SERVER:
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family=AF_UNIX;
strcpy(addr.sun_path+1,"example");
addr.sun_path[0]=0;
int mysock = socket(AF_UNIX, SOCK_DGRAM, 0);
if((bind(mysock, (struct sockaddr *)&addr,sizeof(addr)))<0)
{
perror("bind() error");
return false;
}
if (send(mysock, path, sizeof(path), 0)<0)
{
perror("send");
}
CLIENT:
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
int mysock = socket(AF_UNIX, SOCK_DGRAM, 0);
if(mysock<0)
{
perror("socket() error");
return false;
}
addr.sun_family=AF_UNIX;
strcpy(addr.sun_path+1,"example");
addr.sun_path[0]=0;
if((connect(mysock, (struct sockaddr *)&addr,sizeof(addr)))<0)
{
perror("connects() error");
return false;
}
recv(mysock, buf, sizeof(buf),0);
printf("%s\n",buf);
You haven't connected the server side. Binding a socket to an address establishes the address of the local peer. However, immediately after binding the socket, you're doing a send but you haven't specified a destination. I.e. where is the data to be sent?
Furthermore, Unix domain datagram sockets are different than others in that both sides need to establish a local address before bidirectional data transfer can occur.
So each side needs to create a socket and bind it to an address of their choosing. The client side can then either connect to the server's address (which permanently establishes the destination address), or it may use sendto to specify the destination address for each buffer.
The server will typically use recvfrom to receive data and the client's address, then use sendto to return the response to the client.
For the sake of clarity, this example in python3. Server code:
import socket
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(b'\x00server') # Our address
data, addr = sock.recvfrom(1024)
print("Data:", data)
print("Client Address:", addr)
sock.sendto(data, addr)
Client code:
import socket
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(b'\x00client') # Our address
sock.connect(b'\x00server') # Server's address
data = b"Hello"
sock.send(data)
print("Sent", data)
rdata, saddr = sock.recvfrom(1024)
print("ReturnedData:", rdata)
print("ServerAddr returned:", saddr)
transport not connected
You can't use send() on an unconnected UDP socket. You need to either connect() it or use sendto(). This is all documented.
NB What does 'Linux abstract socket' mean? I don't see anything abstract about your code. You are also lacking error-checking on recv(), which needs to be recvfrom() if the socket is unconnected.

Detect port connection without loosing data

I have been trying to write a small program for Linux, to detect a client connection on a port, say 8080, and upon a connection close the socket and execvp some program.
I setup the socket for the port.
After that I do a select to wait for incoming client connections.
if(select(listener+1, &master, NULL, NULL, NULL) == -1)
{
perror("Server-select() erro!");
exit(1);
}
printf("Close socket...\n");
close(listener);
After this I execvp a program, that should read then data on the port.
This all works fine, but the client which tries to connect, always fails first time, because, I guess the data send from the client to the program is lost when I close the socket.
Is there anyway to wait for port connections, without loosing the data send?
I was thinking something like not acknowledging the connection.
When I do accept() as suggested:
{
struct sockaddr_in clientName = { 0 };
int slaveSocket, clientLength = sizeof(clientName);
(void) memset(&clientName, 0,sizeof(clientName));
slaveSocket = accept(listener,(struct sockaddr *) &clientName,&clientLength);
if (-1 == slaveSocket)
{
perror("accept()");
exit(1);
}
}
printf("Close socket...\n");
close(listener);
if ((child = fork()) == 0) { /* Child process. */
printf("Child: PID of Child = %ld\n", (long) getpid());
execvp(argv[2], &argv[2]); /* arg[0] has the command name. */
/* If the child process reaches this point, then *//* execvp must have failed. */
fprintf(stderr, "Child process could not do execvp.\n");
exit(1);
} else { /* Parent process. */
if (child == (pid_t) (-1)) {
fprintf(stderr, "Fork failed.\n");
exit(1);
} else {
c = wait(&cstatus); /* Wait for child to complete. */
printf("Parent: Child %ld exited with status = %d\n", (long) c,
cstatus);
}
}
The executed shell program fails with:
bind() error (port number: 8554): Address already in use
So I guess I need to release the port somehow?
See this example how to do it correctly: http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/023/2333/2333l1.html
You don't close your listening socket. You call accept to get a new fd for the incoming connection, then fork. After forking, you may close the listening socket, and use the accept'ed socket to transfer data. The parent process just closes the accepted socket and continues listening.
As you aren't accepting the incoming connection, it must get closed when you close the listening socket. You need to call accept() first.

Is it possible that Accept return a same socket value for different tcp connections on the same machine

Is there possible that accept() (on redhat Enterprise 4/linux kernel 2.6) return a same socket value for different tcp connections from the same process of a same application and same machine?
I am so surprised that when I got such a result that many connections have the same socket value on server side when I checked the log file!! How is it possible?!!
By the way, I am using TCP blocking socket to listen.
main(){
int fd, clientfd, len, clientlen;
sockaddr_in address, clientaddress;
fd = socket(PF_INET, SOCK_STREAM, 0);
....
memset(&address, 0, sizeof address);
address.sin_address = AF_INET;
address.sin_port = htons(port);
....
bind(fd, &address, sizeof address);
listen(fd, 100);
do {
clientfd = accept(fd, &clientaddress, &clientlen);
if (clientfd < 0) {
....
}
printf("clientfd = %d", clientfd);
switch(fork()){
case 0:
//do something else
exit(0);
default:
...
}
} while(1);
}
my question is that why printf("clientfd = %d"); prints a same number for different connections!!!
If server runs in multiple processes (like Apache with mpm worker model), then every process has its own file descriptor numbering starting from 0.
In other words, it is quite possible that different processes will get exact same socket file descriptor number. However, fd number it does not really mean anything. They still refer to different underlying objects, and different local TCP ports.
The socket is just a number.It is a hook to a data structure for the kernel.
BTW TCP uses IP. Look up the RFC
That printf() doesn't print any FD at all. It's missing an FD parameter. What you are seeing could be a return address or any other arbitrary junk on the stack.

How to handle all possible errors on async socket?

I have decided to use async io for my project and simply do a single threaded loop where I try to read some data each frame from each open socket. This worked quite well and overall I'm happy with it for now. The problem is weird problems I'm having with the async sockets.
I have code like this:
accept a connection...
fcntl(O_NONBLOCK) on the client socket...
int rc;
if((rc = recv(socket))>0)
process data
if rc == 0
close socket and cleanup
The problem is that I get rc == 0 sometimes even though I know that the connection is not closed. If I don't clean up then my app works as normal. But if I do cleanup then the client receives a disconnect before the connection is even established.
So my question is: Do I have to check somehow whether the socket is ready before doing a recv in order to get the correct return value from it?
Most of the information I have been able to find was inconclusive. I found a references to select() but it seems to block until there is a status change on the socket - but I need the socket to be nonblocking.
What I'm looking for is just the intuitive behavior that if there is data, it is read to the buffer and recv returns number of bytes read, if there is no data it returns -1 and if the socket is disconnected then it should return 0.
Do I have to do anything else to the socket before calling recv to make it work as expected?
First, taking on the heavy lifting of going "all asynchronous" with a socket server is a good start for a design and will enable scalability very easily.
As for your question.
recv() will return the following values:
A postive value returned by recv() indicates the number of bytes
copied to your buffer.(i.e you actually received these bytes)
recv() will return 0 when the socket was closed by the remote side.
For async sockets, recv() will return -1 and set errno to either
EAGAIN or EWOULDBLOCK if the connection is still valid, but there's
no new data to be consumed. Call select() or poll() on the socket to
wait for data.
Otherwise, any general connection failure will result in -1 being returned by recv(). (And the only thing you can do is close the socket).
So when you say, "rc == 0 sometimes even though I know that the connection is not closed", I suspect your pseudocode is not checking the return value, but instead checking the result of (rc > 0).
This is closer to the logic you want:
int rc;
rc = recv(s, buf, buffersize, 0);
if (rc == 0)
{
/* socket closed by remote end */
close(s); s=-1;
}
else if ((rc == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)) )
{
// need to wait. Call select() or poll()
}
else if (rc == -1)
{
close(s); s=-1;
}
else
{
ProcessNewData(s, buffer, rc);
}

React on client disconnect in linux

I am writing a simple socket daemon witch listens to a port and reads the incoming data. It works fine until i choose to disconnect a client from the server...then it enters in a infinte loop recv() returns the last packet never gets to -1. My question is how can i detect that the client had been disconnected and close the thread/ socket el
My thread is as follows :
void * SocketHandler(void* lp){
int * csock = (int*)lp;
int test = 0;
char buffer[1024];
int buffer_len = 1024;
int bytecount,ierr;
memset(buffer,0,buffer_len);
while (test == 0)
{
if ((bytecount = recv(*csock, buffer, buffer_len, 0))== -1){
close(csock);
free(csock);
test++;
return 0;
}
else
{
syslog(LOG_NOTICE,"%s",buffer);
}
}
return 0;
};
A cleanly closed socket will end up in a ZERO read, while a broken connection is an error state returning -1. You need to catch the 0 return of your recv.
What happens here is that your end may not detect the fact the socket is dead (especially, if you are just reading from it).
What you can do is set keepalive on the socket. This will turn on periodic checks of the socket liveness. But don't expect fast reactions, the default timeout is something like 20 minutes.
i = 1;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i));
Another option is to do your own keep-alive communication.
recv() will indicate a proper shutdown of the socket by returning 0 (see the manpage for details). It will return -1 if and only if an error occurred. You should check errno for the exact error, since it may or may not indicate that the connection failed (EINTR, EAGAIN or EWOULDBLOCK [non-blocking sockets assumed] would both be recoverable errors).
Side note: there's no need to pass the fd of the socket as pointer and since you're returning a void * you may want to change return 0 to return NULL (just for readability).

Resources