close tcp socket when the program was stopped by kill command - c

I developed an application which contains a small http server.
my application is launched in the boot. if the application is stopped normally (etc/init.d/myappli stop) the socket will be closed
close (socket_desc);
but if I kill it with kill -9 the socket will not be closed
http server code :
void http_server_init(void)
{
struct sockaddr_in server;
int cr_port;
for(;;) {
cr_port = conf.port;
int i = (DEFAULT_PORT == cr_port)? 1 : 0;
//Create socket
cr_socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (cr_socket_desc == -1)
{
LOG (ERROR,"Could not open server socket, Error no is : %d, Error description is : %s", errno, strerror(errno));
sleep(1);
continue;
}
/* enable SO_REUSEADDR */
int reusaddr = 1;
if (setsockopt(cr_socket_desc, SOL_SOCKET, SO_REUSEADDR, &reusaddr, sizeof(int)) < 0) {
LOG (WARNING,"setsockopt(SO_REUSEADDR) failed");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
for(;;i++) {
server.sin_port = htons(cr_port);
//Bind
if( bind(cr_socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
LOG (ERROR,"Could not bind server socket on the port %d, Error no is : %d, Error description is : %s", cr_port, errno, strerror(errno));
cr_port = DEFAULT_PORT + i;
LOG (INFO,"Trying to use another port: %d", cr_port);
continue;
}
break;
}
break;
}
LOG (INFO,"server initiated with the port: %d", cr_port);
}
Questions:
1) How to close socket if the program was killed?
2)And what is the type of socket should be used in this case to avoid that the socket will not be used by another process using tcp socket?

If you kill a program with kill -9 the port will be closed, not by the program, but by the operating system. The fact it is being closed is precisely what is making it available for being taken over by another process.
Ports are not 'reserved' for particular programs. The only reservation of ports after the death of the program is if you don't set SO_REUSEADDR in which case it's reserved for (from memory) 2 TIME_WAIT periods. But you've told us in the comments you do set SO_REUSEADDR. What that means is 'make the port available to the next program that tries to listen on it'. It doesn't differentiate between that program being the same program or a different one.
I think you think that SO_REUSEADDR means 'this program may want to reuse the port so don't give it to anyone else'. That is categorically not what SO_REUSEADDR does. SO_REUSEADDR (broadly speaking, and on Unix anyway) releases the port for use by any program to the operating system immediately after your program dies, as opposed to waiting for a while. On MS it is (somewhat bizarrely) used to bind to a port that's already in use. For more information, see Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems? - however note that on no operating system does it mean what I'm guessing you think it means.

Your problem is that the old socket will be in TIME_WAIT state a short while before it is released.
If you want to reduce the time spent in the TIME_WAIT state you can reduce the linger time. Note that there are risks attached to reducing it too much.
You can change the linger time for your socket using setsockopt(2).
Related links:
The ultimate SO_LINGER page
TCP option SO_LINGER (zero)

Related

how to detect a connected Unix domain datagram socket was closed

app A and app B created Unix domain datagram socket,A call connect to connect B,so A can use read and write 0r send and recv to communicate with B.but if B crashed,A will block at recv.B restart,sending msg to A will get error 1 operation not permitted.is there any way A can detect B crashed ?
OS:Ubuntu 18.04 kernel 4.18.0
If you want to detect connection errors, a connection-orientated socket might be more appropriate, like SOCK_STREAM or SOCK_SEQPACKET
From the man page of socket:
...
If a piece of data for which the peer protocol has buffer space cannot be successfully transmitted within a reasonable length of time, then the connection is considered to be dead. When SO_KEEPALIVE is enabled on the socket the protocol checks in a protocol-specific manner if the other end is still alive.
...
SOCK_SEQPACKET sockets employ the same system calls as SOCK_STREAM sockets.
Nonblocking reads can be achieved via the O_NONBLOCK flag (on the descriptor) or the recv flag MSG_DONTWAIT.
Connection error detection on connectionless protocols has to be implemented in the application. You could implement a simple ping/heartbeat mechanism, where a client has to send (empty) packets within a specific time interval to indicate that it is still alive or still participating in the communication.
Edit: I've used TCP/UDP synonymously for SOCK_STREAM/SOCK_DGRAM (as the user Shawn pointed out in the comments below).
I had the same problem recently, and the solutions that I found on the web did not entirely convince me. Therefore, I came up with this:
// Client: replace every close() with this close_dgram_socket():
int close_dgram_socket(int fd)
{
if (send(fd, "Bye-bye.", 8) == -1)
perror("send");
close(fd)
}
// Server loop:
do
{
fd_set readfds; FD_ZERO(&readfds); FD_SET(fd, &readfds);
struct timeval timeout = { 0, 300000 }; // 300 ms
if (select(fd+1, &readfds, 0, 0, &timeout) == 0) // nothing reveived
{
if (kill(getppid(), 0)
break; // client has died
else
continue;
}
rx_len = recv(fd, buf, sizeof(buf), 0);
} while(rx_len != 8 || strncmp(buffer, "Bye-bye.", 8));
close(fd); // peer has closed, so do we.
The idea is that (1) the server sends a Bye-bye datagram if she closes the socket orderly and (2) the client checks with kill() if the server is still alive to handle the case where the server crashes and cannot send the Bye-bye datagram. Works fine for socketpair() but not for UDP.

select() returning 1 even in case process on remote host bound to a given port is killed

I have written a program using non-blocking connect() and select() combination to check the connection to a remote host at a
particular port. select() has some timeout value also, in my case 2.5s. I am testing the program to connect to a process running the SMTP service on the remote host which is
which is bound to port 25 . If I kill that process running on remote host , then also select() returning 1 to tell that writing (socket added to write fd_set ) to that process
is possible. What can be the reason behind this, and also Is it possible to use select() in this case. I tried using connect() which returns immediately when such connection is not possible but it doesn't work in case some timeout is required for connection, that is why I am using select().
select() doesn't tell you that reading or writing is possible, it just tells you that it won't block (or return the error EWOULDBLOCK if the socket is in non-blocking mode). A socket is always writable as long as the local socket buffer is not full. Also, if anything was sent after the remote process has died, you will receive a RST packet, and attempts to write after that will return ECONNRESET immediately. So the socket will be marked writable when that happens.
I was able to accomplish by using another connect() after select() function call.
Posting the code snippet
error = connect(soc, (struct sockaddr *)serveraddr, sizeof(struct sockaddr)) ;
if(error == 0){
DIAGC("vsrserv", 1, "Returning while connect is 0");
return 0;
}
if(errno != EINPROGRESS)
return -1;
int retVal = select (soc+1, &writeFD, (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)(&timeout));
if (retVal == 0){
close(soc);
return -1;
}
socklen_t len = 0;
int m = getsockopt(soc, SOL_SOCKET, SO_ERROR, &error, &len) ;
if(m < 0){
close(soc);
return -1;
}
//connect() returns immediately if it is able to connect to that particular port
//Since select() returned 1 it means host was reachable so just need to verify the port on the remote host which we can do with another with connect() call
error = connect(soc, (struct sockaddr *)serveraddr, sizeof(struct sockaddr)) ;
if(error < 0){
close(soc);
return -1;
}

Why is non-blocking socket connect so slow?

when I do 100 non-block socket connection in 1 thread,it is very slow(the number of connection increased one by one),but if I do a blocking socket connection in 100 parallel threads(one connect per thread), it is very fast(get done immediately )
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fcntl(sock, F_SETFL,O_NONBLOCK)!=0)
{
perror("fcntl nonblock");
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,&reuseAddr, sizeof(reuseAddr))!=0)
{
perror("reuse addr");
return -1;
}
sAddr.sin_addr.s_addr = inet_addr(SRV_ADDR);
sAddr.sin_port = htons(1972);
if ((n=connect(sock, (const struct sockaddr *) &sAddr, sizeof(sAddr))) < 0)
{
if (errno !=EINPROGRESS) {
perror("client connect error");
return -1;
}
}
else if (n>=0)
{
printf("#%d connected\n",sock);
}
return sock;
Awesome question :-). Here's why I think this is happening. The standard says this:
If the connection cannot be established immediately and O_NONBLOCK is
set for the file descriptor for the socket, connect() shall fail and
set errno to [EINPROGRESS]
The question of course is what "immediately" means. I believe that "immediately" is actually some small time that allows the SYN, SYN-ACK, ACK to happen. If it didn't wait at all, it would have 0-chance of actually succeeding.
So basically:
The client sends a SYN
Waits (blocks) for a small period of time ("immediately") for a SYN-ACK.
Completes the connection
In doing so it returns successfully instead of EADDRINUSE.
Now, when using threads, each thread does this so nobody waits. They all just connect(2) and context switching allows everybody to do it almost simultaneously.

How to find the socket connection state in C?

I have a TCP connection. Server just reads data from the client. Now, if the connection is lost, the client will get an error while writing the data to the pipe (broken pipe), but the server still listens on that pipe. Is there any way I can find if the connection is UP or NOT?
You could call getsockopt just like the following:
int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len);
To test if the socket is up:
if (retval != 0) {
/* there was a problem getting the error code */
fprintf(stderr, "error getting socket error code: %s\n", strerror(retval));
return;
}
if (error != 0) {
/* socket has a non zero error status */
fprintf(stderr, "socket error: %s\n", strerror(error));
}
The only way to reliably detect if a socket is still connected is to periodically try to send data. Its usually more convenient to define an application level 'ping' packet that the clients ignore, but if the protocol is already specced out without such a capability you should be able to configure tcp sockets to do this by setting the SO_KEEPALIVE socket option. I've linked to the winsock documentation, but the same functionality should be available on all BSD-like socket stacks.
TCP keepalive socket option (SO_KEEPALIVE) would help in this scenario and close server socket in case of connection loss.
There is an easy way to check socket connection state via poll call. First, you need to poll socket, whether it has POLLIN event.
If socket is not closed and there is data to read then read will return more than zero.
If there is no new data on socket, then POLLIN will be set to 0 in revents
If socket is closed then POLLIN flag will be set to one and read will return 0.
Here is small code snippet:
int client_socket_1, client_socket_2;
if ((client_socket_1 = accept(listen_socket, NULL, NULL)) < 0)
{
perror("Unable to accept s1");
abort();
}
if ((client_socket_2 = accept(listen_socket, NULL, NULL)) < 0)
{
perror("Unable to accept s2");
abort();
}
pollfd pfd[]={{client_socket_1,POLLIN,0},{client_socket_2,POLLIN,0}};
char sock_buf[1024];
while (true)
{
poll(pfd,2,5);
if (pfd[0].revents & POLLIN)
{
int sock_readden = read(client_socket_1, sock_buf, sizeof(sock_buf));
if (sock_readden == 0)
break;
if (sock_readden > 0)
write(client_socket_2, sock_buf, sock_readden);
}
if (pfd[1].revents & POLLIN)
{
int sock_readden = read(client_socket_2, sock_buf, sizeof(sock_buf));
if (sock_readden == 0)
break;
if (sock_readden > 0)
write(client_socket_1, sock_buf, sock_readden);
}
}
Very simple, as pictured in the recv.
To check that you will want to read 1 byte from the socket with MSG_PEEK and MSG_DONT_WAIT. This will not dequeue data (PEEK) and the operation is nonblocking (DONT_WAIT)
while (recv(client->socket,NULL,1, MSG_PEEK | MSG_DONTWAIT) != 0) {
sleep(rand() % 2); // Sleep for a bit to avoid spam
fflush(stdin);
printf("I am alive: %d\n", socket);
}
// When the client has disconnected, this line will execute
printf("Client %d went away :(\n", client->socket);
Found the example here.
I had a similar problem. I wanted to know whether the server is connected to client or the client is connected to server. In such circumstances the return value of the recv function can come in handy. If the socket is not connected it will return 0 bytes. Thus using this I broke the loop and did not have to use any extra threads of functions. You might also use this same if experts feel this is the correct method.
get sock opt may be somewhat useful, however, another way would to have a signal handler installed for SIGPIPE. Basically whenever you the socket connection breaks, the kernel will send a SIGPIPE signal to the process and then you can do the needful. But this still does not provide the solution for knowing the status of the connection. hope this helps.
You should try to use: getpeername function.
now when the connection is down you will get in errno:
ENOTCONN - The socket is not connected.
which means for you DOWN.
else (if no other failures) there the return code will 0 --> which means UP.
resources:
man page: http://man7.org/linux/man-pages/man2/getpeername.2.html
On Windows you can query the precise state of any port on any network-adapter using:
GetExtendedTcpTable
You can filter it to only those related to your process, etc and do as you wish periodically monitoring as needed. This is "an alternative" approach.
You could also duplicate the socket handle and set up an IOCP/Overlapped i/o wait on the socket and monitor it that way as well.
#include <sys/socket.h>
#include <poll.h>
...
int client = accept(sock_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
pollfd pfd = {client, POLLERR, 0}; // monitor errors occurring on client fd
...
while(true)
{
...
if(not check_connection(pfd, 5))
{
close(client);
close(sock[1]);
if(reconnect(HOST, PORT, reconnect_function))
printf("Reconnected.\n");
pfd = {client, POLLERR, 0};
}
...
}
...
bool check_connection(pollfd &pfd, int poll_timeout)
{
poll(&pfd, 1, poll_timeout);
return not (pfd.revents & POLLERR);
}
you can use SS_ISCONNECTED macro in getsockopt() function.
SS_ISCONNECTED is define in socketvar.h.
For BSD sockets I'd check out Beej's guide. When recv returns 0 you know the other side disconnected.
Now you might actually be asking, what is the easiest way to detect the other side disconnecting? One way of doing it is to have a thread always doing a recv. That thread will be able to instantly tell when the client disconnects.

How to Create a TCP socket connect using C to a predefined port

I have a very simple question. I want to test whether a particular port is currently under use or not. For this, I want to bind a TCP socket to the port, if the connection is refused means the port is in use and if not that mean the port is free.
Can someone please tell me how can I write the TCP socket code in C? I am on a solaris platform.
I know its very basic. But I appreciate your help. Thanks in advance.
The call to bind function will return -1 if there is an error. This includes the case where the address is already in use.
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 12345
int main()
{
struct sockaddr_in addr;
int fd;
fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1)
{
printf("Error opening socket\n");
return -1;
}
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = 0;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
if(bind(fd, (struct sockaddr *)&addr,sizeof(struct sockaddr_in) ) == -1)
{
printf("Error binding socket\n");
return -1;
}
printf("Successfully bound to port %u\n", PORT);
}
It depends slightly on exactly what you're trying to test.
Using bind() in the way that joelc suggested will tell you if the port is open on any interface on your machine. Although to be thorough, you should not only be checking the return value from bind(), but also checking errno == EADDRINUSE.
ie. (modification of joelc's code)
if(bind(socket, (struct sockaddr *)&sin,sizeof(struct sockaddr_in) ) == -1)
{
if( errno == EADDRINUSE )
{
// handle port already open case
}
else
{
// handle other errors
}
}
By changing the address used in the line: eg.
sin.sin_addr.s_addr = inet_addr("192.168.1.1");
...you can test whether a port is available on a specific interface.
Be aware though that this isn't a perfect test for port state. If another process had the port open and was terminated before it gracefully closed the port (ie. before calling close() on the socket) then you will usually get the same EADDRINUSE error.
(depending on whether the SO_REUSEADDR option had been set on the socket)
(side note: unless your test application is running with sufficient privileges you won't be able to bind() to any ports below 1024)
As Anonymous suggested, you can also have a look at netstat. This will give you all of the same information that you can get by repeatedly calling bind() much more quickly and without any of the side effects (like it doesn't have to actually bind to the ports, which would make them unusable to any other processes).
Just calling netstat -a --numeric-ports -t and analysing the output should give you everything that you're after.
A comment on moogs suggestion though - calling telnet on each port will only tell you if a socket is listening on that port - not whether it's actually open.
Do you just want to test if the particular port is currently in use? (and don't really need to make a program).
If so, you can use telnet:
telnet host port
If the connection fails, it's not in use. If it connects and waits for input from you, it's in use :)
You might want to look at the source code of netstat. I believe there is a netstat in Solaris as well.

Resources