Server hanging on recv method after client closes socket connection - c

Hi i am learning sockets in c, and so far everything was working fine until i tried to close connection in my client and try to reconnect after, the problem is that the server stays stuck on recv() method after the client closes the socket refering to the connection. The question is how can i close the connection in my client and detect it on server side so i could accept a new connection after and the process does not get hang. I have also tried to catch sigpipe but i read some posts and they said that sigpipe was only generated on write() method is that true?
Here is my code in case it helps understanding my problem, Thanks a lot.
int network_main_loop(int listening_socket){
signal(SIGINT, sigHandler);
signal(SIGSEGV, sigHandler);
signal(SIGTSTP, sigHandler);
signal(SIGABRT, sigHandler);
//sigaction(SIGPIPE, &(struct sigaction){pipeHandler}, NULL);
//signal(SIGPIPE, SIG_IGN);
int connsockfd;
struct sockaddr_in client;
socklen_t size_client;
while ((connsockfd = accept(listening_socket, (struct sockaddr *)&client, &size_client)) >= 0)
{
int quit = 0;
char clientADDR[100];
printf("\nConnected To a Client - %s:%d!\n", inet_ntop(AF_INET, &client.sin_addr, clientADDR, sizeof(clientADDR)), htons(client.sin_port));
while (quit == 0)
{
MessageT *clientRequest = network_receive(connsockfd);
if (clientRequest != NULL)
{
int status = invoke(clientRequest);
printf("Status:%d\n", status);
if (status == -1)
{
clientRequest->data_size = 0;
clientRequest->opcode = MESSAGE_T__OPCODE__OP_ERROR;
clientRequest->c_type = MESSAGE_T__C_TYPE__CT_NONE;
clientRequest->data_size = -1;
printf("ERROR!");
if (network_send(connsockfd, clientRequest) == -1)
quit = 1;
}
else
{
if (network_send(connsockfd, clientRequest) == -1)
quit = 1;
}
}
else
quit = 1;
}
printf("\nConnected To %s:%d is Closed!\n", inet_ntop(AF_INET, &client.sin_addr, clientADDR, sizeof(clientADDR)), htons(client.sin_port));
close(connsockfd);
}
return 0;
}

Related

close() does not close tcp connection if interface lost its ip address

My program has an established tcp connection when linux box loses its DHCP IP address lease. After that it tries to close the connection so when dhcp server recovers it will re-establish tcp connection again. It uses SO_REUSEADDR.
I did read this http://hea-www.harvard.edu/~fine/Tech/addrinuse.html but in this application reuse address is a requirement.
The way I reproduce this problem is by issuing ifconfig etho 0.0.0.0
However, the result of close(sockfd) is unpredictable. Sometimes it closes socket properly. Sometimes netstat -ant continuously shows
tcp 0 0 192.168.1.119:54322 192.168.1.41:54321 (STATE)
where (STATE) can one of ESTABLISHED, or FIN_WAIT1, or CLOSE_WAIT.
Originally my code had just close(). After reading multiple sources online, I tried some suggestions.
First I tried this (based on http://deepix.github.io/2016/10/21/tcprst.html)
if (sockFd != -1) {
linger lin;
lin.l_onoff = 1;
lin.l_linger = 0;
if (setsockopt(sockFd, SOL_SOCKET, SO_LINGER, (const char *)&lin, sizeof(linger)) == -1) {
std::cout << "Error setting socket opt SO_LINGER while trying to close " << std::endl;
}
close(sockFd);
}
It did not help, so I tried this (based on close() is not closing socket properly )
bool haveInput(int fd, double timeout) {
int status;
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = (long)timeout; // cast needed for C++
tv.tv_usec = (long)((timeout - tv.tv_sec) * 1000000); // 'suseconds_t'
while (1) {
if (!(status = select(fd + 1, &fds, 0, 0, &tv)))
return FALSE;
else if (status > 0 && FD_ISSET(fd, &fds))
return TRUE;
else if (status > 0)
break;
else if (errno != EINTR)
break;
}
}
void myClose(int sockFd)
{
if (sockFd != -1) {
int err = 1;
socklen_t len = sizeof err;
getsockopt(sockFd, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
shutdown(sockFd, SHUT_WR);
usleep(20000);
char discard[99];
while (haveInput(sockFd, 0.01))
if (!read(sockFd, discard, sizeof discard))
break;
shutdown(sockFd, SHUT_RD);
usleep(20000);
close(sockFd);
sockFd = -1;
}
}
As before, sometimes it closes connection, and sometimes it does not.
I understand that in this case the other side can send neither FIN nor ACK, so graceful close is just not possible.
Is there a reliable way to completely close tcp connection in such conditions?
Thank you

Multithreaded TCP server with C sockets and pthreads - Why does accept() block on the second request?

I've been writing a small multithreaded TCP server in C using unix sockets and pthreads, but I'm having trouble with accept(). It hangs on the second request that comes through, and only unblocks when the previously thread exits.
Here's how I set up the server socket.
int server_start(server_t *server, int port) {
int fd;
struct sockaddr_in server_addr;
// Socket file descriptor.
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
perror("socket failed");
return 1;
}
// Socket address.
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
// Bind.
if (bind(fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1) {
perror("bind failed");
return 1;
}
server->fd = fd;
listen(server->fd, server->clients_len);
pthread_create(&(server->thread), NULL, thread_entry_server, server);
return 0;
}
Here's my add_client code. It spawns a separate thread for the client.
client_t *server_add_client(server_t *server) {
int iter,
fd,
status;
client_t *client;
printf("before\n");
fd = accept(server->fd, NULL, 0);
printf("after\n");
if (fd == -1) {
perror("accept");
return NULL; // Connection failed.
}
// Find an empty spot.
client = server->get_empty_spot();
client->fd = fd;
// Start the new thread.
status = pthread_create(
&(client->thread),
NULL,
thread_entry_client,
client
);
if (status != 0) {
perror("pthread_create");
close(client->fd);
return NULL;
}
client->active = 1;
return client;
}
And here's my entry function for the client thread:
void *thread_entry_client(void *void_client) {
client_t *client = void_client;
int len;
while (1) {
len = recv(client->fd, client->recv_buffer, RECV_BUFFER_LEN, 0);
if (len < 0) {
perror("recv");
client->active = 0;
close(client->fd);
return NULL;
}
if (len == 0) { // Client disconnected.
client->active = 0;
close(client->fd);
printf("disconnect\n");
return NULL;
}
if (len > 0) {
//printf("%s\n", client->recv_buffer);
printf("msg\n");
}
}
return NULL;
}
So what I'm doing to test this is establishing two connections. The first connection goes through and works fine, but the second connection does not - instead the thread hangs on accept(). I know this from my printfs (that I've left in there), and I know that accept() unblocks AFTER the first client disconnects. I also know that my code is not closing the server socket file descriptor or changing it.
Any advice on debugging this? I can't figure it out.
EDIT: Here is thread_entry_server.
void *thread_entry_server(void *void_server) {
server_t *server = void_server;
client_t *client;
while (1) {
client = server_add_client(server);
if (client == NULL) // Server is full or connection failed.
continue;
}
return NULL;
}
I was testing with a javascript websocket, but I wasn't doing any handshaking so it wasn't completing the connection. Testing with telnet works.
This is because accept() will block (unless configured otherwise) till a client connection is available.
See Documentation which mentions -
If the listen queue is empty of connection requests and O_NONBLOCK is
not set on the file descriptor for the socket, accept() will block
until a connection is present. If the listen() queue is empty of
connection requests and O_NONBLOCK is set on the file descriptor for
the socket, accept() will fail and set errno to [EAGAIN] or
[EWOULDBLOCK].
Also, server->get_empty_spot(); should always return new client instance otherwise it would mean you are passing same client->thread to pthread_create.
I usually prefer to create new thread myself, something like -
**pthread_t newListner;**
ThreadArgs thread_args;
thread_args.client_socket = client_socket;
int rc;
if ((rc = pthread_create(&newListner, NULL, startListener, &thread_args)))
{ .. }
Give it a try.

Why does a broken network connection cause an EOF on stdin?

I have a simple server that in a separate thread waits for a network connection and then sends information periodically to the client. The main thread accepts commands via stdin. What I don't understand is why stdin receives EOF when the client is terminated.
For the sample code below, the client can be as simple as 'nc 127.0.0.1 1234' in the command line. When the client is interrupted with 'kill' or Ctl-C the server exits due to EOF on stdin. I'd certainly appreciate an explanation for this behavior and a workaround that keeps the server running.
static void *WaitForConnections(void *p) {
int sockfd, newsockfd;
struct sockaddr_in server = { sizeof(server), AF_INET, htons(1234), INADDR_ANY};
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket call failed");
exit(1);
}
if ( bind(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1){
perror("bind call failed");
exit(1);
}
if ( listen(sockfd, 0) == -1 ) {
perror("listen call failed");
exit(1);
}
for (;;) {
if ( (newsockfd = accept(sockfd, NULL, NULL)) != -1) { // new connection
for ( ;;) {
char c = 'd';
if (send(newsockfd, &c, sizeof(c), 0) != sizeof(c)) {
break;
}
sleep(1);
}
close(newsockfd);
}
else {
break;
}
}
close(sockfd);
return NULL;
}
int main(int argc, const char * argv[]) {
pthread_attr_t attr;
pthread_t p;
void * status;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (0 != pthread_create( &p, &attr, WaitForConnections, NULL )) {
fprintf(stderr, "thread creation failed\n");
exit(1);
}
while (getchar() != EOF) {}
pthread_join(p, &status);
return 0;
}
It shouldn't matter, but this is under MacOS X 10.10.1, Xcode 6.1.1 and Apple LLVM 6.0.
Your server doesn't exit because of EOF on stdin, it exits because it tries to send data on a broken TCP connection, which causes the SIGPIPE signal to be delivered - and the default action for SIGPIPE is to terminate the process.
You should ignore SIGPIPE with
signal(SIGPIPE,SIG_IGN);
And that will cause send()/write() calls to instead return -1 and set errno to EPIPE, which your code can handle.

recv: Connection reset by peer

when I close my client connected to the server I get this error from the server and server shuts itself down. I know that client can terminate the connection gracefully but I am planning to send this out to some people and do not want my server to be shut just because they did not terminate gracefully. So what could actually prevent the server to be closed?
I am using sys/socket.h
Here's a part of my code
int server() {
//Set up variables
int sockfd, new_fd; //Listen on sock_fd, new connection on new_fd
struct sockaddr_in my_addr; //My(server) address information
struct sockaddr_in their_addr; //Connector's address information
socklen_t sin_size;
//Generate the socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
//Generate the end point
my_addr.sin_family = AF_INET; //Host byte order
my_addr.sin_port = htons(MYPORT); //Short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; //Auto-fill with my IP
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
perror("bind");
exit(1);
}
//Start listnening
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
while(TERMINATE == 0) { // main accept() loop
sin_size = sizeof(struct sockaddr_in);
//Create a new connection for the accepted socket
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
&sin_size)) == -1) {
perror("accept");
continue;
}
//some semaphore stuff
}
return 0;
}
int main(int argc, char *argv[]){
//extra stuff
//Set up mutex locks
pthread_mutex_init(&mutex, NULL);
sem_init(&empty, 0, 30);
sem_init(&full, 0, 0);
//Set up and run Threads
pthread_t threads[30]; //Array of threads
pthread_t server_thread;
pthread_attr_t attr; //Set of thread attributes
//Get the default thread attributes
pthread_attr_init(&attr);
signal(SIGINT, termination);//Wait for a SIGINT
//Loop to create threads and execute consumer_thread
for (int i = 0; i < 30; i++) {
//Set up data in structure
threadArray[i].threadID = i;
threadArray[i].running = 0;
threadArray[i].line_counter_pointer = &line_counter;
threadArray[i].vid_details_pointer = &vid_details;
pthread_create(&threads[i],&attr,consumer_thread, &threadArray[i]);
}
//Execute the producer_thread
pthread_create(&server_thread,&attr,producer_thread, NULL);
//Wait for all the threads to exit
for (int i = 0; i < 30; i++) {
pthread_join(threads[i],NULL);
}
//Destroy semaphores so that it can TERMINATE gracefully
sem_destroy(&empty);
sem_destroy(&full);
return 0;
}
void *producer_thread(void *param) {
server();//Runs the server() function
return NULL;
}
void *consumer_thread(void *param) {
//Pass variable
struct thread_params *threadStruct;
threadStruct = (struct thread_params *) param;
int *line_counter = threadStruct->line_counter_pointer;
vid_details_struct *vid_details = threadStruct->vid_details_pointer;
//End of pass
char found_result [MAXDATASIZE];
int queue_item = 0;
int numbytes;
struct timeval item_wait_time;// Get the current time
while (TERMINATE == 0) { //Main accept() loop
int new_fd;
//Use a variable that would be set to 0 after the client termination
//so that the current connection will be closed on both thread and
//client, that would make thread to go back to idle
int current_connection = 1;
//Acquire full semaphore
sem_wait(&full);
//Acquire mutex lock to protect buffer
pthread_mutex_lock(&mutex);
//some extra stuff including socket information
//now handling queue[queue_item]
new_fd = queue[queue_item].new_fd;
queue[queue_item].waiting = 0;
//Release mutex lock and empty semaphore
pthread_mutex_unlock(&mutex);
sem_post(&empty);
while (current_connection == 1) {
char buf[MAXDATASIZE];
//Receive the query
if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
perror("recv");
exit(1);
}
buf[numbytes] = '\0';//Set the end point of the string
if (!strcmp(buf,"q")) {//Client prompts to TERMINATE
current_connection = 0;//Flag the connection as closed
}
if (current_connection == 1) {//If still connected
//do something
if (send(new_fd, found_result, MAXDATASIZE, 0) == -1) {
perror("send");
close(new_fd);
exit(0);
}
}
}
close(new_fd); // Close the socket connection
//Wait for half a second before accepting a new request
usleep(500000);
}//End of the main while loop
FINISHEDSEMS++;
printf("Thread %d is closing\n", threadStruct->threadID);
return NULL;
}
This if-statement is what you need to look at:
if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
perror("recv");
exit(1);
}
It's the only place you posted that has recv, so that's the error.
Take a look at the man page: recv returns the length of the message on successful completion. If a message is too long to fit in the supplied buffer, excess bytes may be discarded depending on the type of socket the message is received from. If no messages are available at the socket, the receive calls wait for a message to arrive, unless the socket is nonblocking (see fcntl(2)), in which case the value -1 is returned and the external variable errno is set
So instead of having a call to exit (which terminates the process), try handling the error gracefully:
if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) < 0) {
// user disconnected or timeout (if you set a timeout)
// NO call to exit; use "continue" or "return", or something else
// to gracefully handle the break;
my_error_function("client disconnected\n");
break;
}
'Connection reset by peer' has a number of causes, but the most common one is that you have written to a connection that has already been closed by the peer. In other words, an application protocol error.

Block Socket with Unix and C/C++ Help

I'm trying to figure out what is blocking my program. I'm running a server that uses POSIX threads. I have to for my computer programming lab. The main function listens for new connections. Once it accepts a connection, it creates a new thread by passing the FD to the thread. I'm able to successfully connect to the server using multiple telnet/client connections. I can send data to the server successfully once, but if I try sending again the server won't do anything.
Part of the main function
int active_thread = 0;
//The Running loop
while(running)
{
if(active_thread > NUMBTHREADS)
{
printf("Unable to accept client connection! Threads are all used up");
running = false;
}
else
{
if(FD_ISSET(sockfd, &readfds))
{
if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1)
{
fprintf(stderr, "Unable to accept client \n");
perror("What");
break;
}
activethreads[active_thread] = pthread_create( &threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]);
//close(bindfd[active_thread]);
//pthread_join( threads[active_thread], NULL);
active_thread++;
//running = false;
}
}
}
close(sockfd);
return 0;
}
Part of the POSIX THREAD CODE
void *server_handler( void *sockfd)
{
int bindfd = *( (int *) sockfd);
char buffer[MESSAGELENGTH];
bool running = true;
printf("Thread was created successfully\n");
char intro[] = "Successfully Connected to server!\n";
struct pollfd pfd;
pfd.fd = bindfd;
pfd.events = POLLIN;
if ( (send(bindfd, intro, strlen(intro), 0)) < 0)
{
perror("Unable to send");
}
while(running){
char msg[] = "\nYou have the following options!\n1) Insert an integer: insert <integer>\n2) Remove An Integer: remove <integer>\n3) Get number of integers in list: get_count\n4) Get first integer: get_first\n5) Get last integer: get_last\n6) Quit program: quit\n ";
if ( (send(bindfd, msg, strlen(msg), 0)) < 0)
{
perror("Unable to send");
}
memset(&buffer, 0, MESSAGELENGTH);
if (recv(bindfd, buffer, MESSAGELENGTH, 0) > 0)
{
//SOme other code
}
}
I think its blocking at either the accept or recv. I've heard of select() and various other methods, but I'm having difficulty trying to implement them. Thanks!
The root cause of your issue appears to be that you are unconditionally executing close(sockfd); return 0; at the bottom of your while (running) loop, which means that the loop only ever executes once.
Additionally, you should not be using FD_ISSET() unless you are also using select(). Your main loop should look something more like:
int active_thread = 0;
while (active_thread < NUMBTHREADS)
{
if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1)
{
fprintf(stderr, "Unable to accept client \n");
perror("What");
break;
}
activethreads[active_thread] = pthread_create( &threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]);
active_thread++;
}
if (active_thread >= NUMBTHREADS)
{
printf("Unable to accept client connection! Threads are all used up.\n");
}
running = false;
close(sockfd);
return 0;
By default network sockets are blocking. You need to set the O_NONBLOCK flag on the socket.
if(fcntl(fd, F_GETFL, &flags) < 0 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
perror("Failed to set socket as non-blocking");
Now, instead of blocking when there is no input (or buffer space to store output), the error EAGAIN (or EWOUDLBLOCK) is returned. Lastly, you will need to use select() or poll() when you have nothing else to do but wait on I/O. These calls will only wake the process when either there is input, room for output, or possibly a time-out period passes.
int maxFd;
fdset fds;
FD_ZERO(&fds);
FD_SET(listenFd, &fds);
FD_SET(sockFd1, &fds);
FD_SET(sockFd2, &fds);
maxFd = listenFd+1;
maxFd = sockFd1 > maxFd ? sockFd1+1 : maxFd;
maxFd = sockFd2 > maxFd ? sockFd2+1 : maxFd;
if(select(maxFd, &fds, &fds, &fds, NULL) < 0) {
perror("Failed on select()");
exit(1);
}
if(FD_ISSET(listenFd, &fds))
...
This example is not complete or neccessarily 100% correct, but should be a good start. Also, I tend to reserve using send*() and recv*() when dealing with SOCK_DGRAM sockets and just use read(), write() on SOCK_STREAM sockets.

Resources