Handling Ctrl-C in a Linux TCP/IP Server written in C - c

I'm currently working on a Linux TCP/IP server. The server program is running in C. I'm currently testing it, but each time I exit it with Ctrl-c, the port it's using is not released, neither is the database it's been writing to unlocked. How does one define a subroutine that will exit when a Ctrl+C signal is received?

Lookup setsockopt and SO_REUSEADDR. This option must have been set on the old original server process's socket or the new one will not be able to bind the port until the TIME_WAIT period expires.

#Bortds Generally the port won't be released immediately, you have to wait to for some time. I found this from a server project I worked.

Two options:
Add a cleanup routine with: int atexit(void (*function)(void));
Hook Ctrl+C with: sighandler_t signal(int signum, sighandler_t handler);
As R pointed out, sigaction is more portable than signal, but perhaps less idiomatic for Linux.
Warning: atexit routines won't run if your program is killed with SIGKILL (Ctrl+/) or any other unhandled signal is received.

Related

How to terminate a socket accept blocking

I developed a server with C code.
I used the accept() function to keep my server listening on a giving socket.
My server is launched in a thread.
Now in other thread and for some condition I want to stop the accept() blocking and then close the related socket.
How I can do that? Could shutdown() do that?
[This does not work on Windows]
Use sigaction() to install a signal handler for let's say SIGUSR1 doing nothing, but having the SA_RESTART option unset (also see section "Interruption of system calls and library functions by signal handlers" on this man-page).
Then send the blocking process a SIGUSR1 signal.
accept() will then return -1 and set errno to EINTR.
Classically, closing the socket from another thread causes the accept() call to return with an error. I have been told that this does not work on some releases of Linux, but have seen no evidence of that myself - every time, on Windows/Linux, the accept() returns with an error/exception.
The other common solution is to check some 'shutdown' atomic boolean after every accept() return. When you want to stop it, set the boolean and perform a connect() on the localhost stack, so causing the accept() to return in the 'normal' way.
I was having trouble with accept not terminating after I only called close on the socket under Linux Mint 18.3. I solved it by also calling shutdown(socket_fd, SHUT_RD); before the close
mah already mentioned it, but I wanted to highlight this, because this is the first SO result in a google search for "socket stop accept".

Interrupt a accept() that is waiting, just changing a global variable value

I'm doing a project for university, a chat system with a server and multiple clients.
In the specification document there is written:
The main thread does a controlled loop on the global var go, and at each cycle waits for a connection request by an user
And also:
Server stops with SIGTERM or SIGINT. When signal is received, the global var go is set to zero, and all threads exit from the loop cycle
So, the thread main create the socket, bind the port and at every new connection does an accept() and create a thread worker which takes care of the communication with the client.
My problem is exiting the thread main only changing the global var.
In the thread main if I do
while (go && accept(params)) {}
it doesn't enter in the while loop.
So at the moment the code is
while (go) {
accept(params);
// Do stuff
}
And, well, when I set go to zero it waits on accept, so I have to create a new connection, it accepts the connection and then exit the thread 'cause go becomes zero.
Same problem with thread worker
while (go && read(socket_id, buffer, sizeof(char)) > 0) {}
It waits for a char from the socket to exit the loop.
I don't see a way to exit loops using only the go var.
I think I've to close the socket, or find another way, am I wrong?
I'm not interested in other ways to exit threads, just to know if it's possible to exit loops just changing the go var
Thanks!
Assuming you setup a signal handler for SIGINT and SIGTERM to toggle the go to !=0 you also want to unset the SA_RESTART flag for the handler(s), which would make accept() return -1 on the signal's reception.
To do so setup the signal handler using sigaction(). For the struct sigaction you pass in do not set the member sa_flags to hold SA_RESTART.
For a detailed description which system call is influenced by the SA_RESTART flag see section "Interruption of system calls and library functions by signal handlers" of man 7 signal.
Independendly from this make sure go is defined sig_atomic_t.

Closing a server socket in C linux

I have a server program which looks like this
{
socket();
bind();
listen();
while(1)
{
accept();
recv();
send();
close();
}
close();
}
Let's say the server is running, listening at the specified port. How can I close it by pressing a keypad? I mean a proper closure, not by Ctrl+C.
When you close() a socket that is blocking in accept(), then the accept() call will return immediately with -1.
If your program is single threaded like you show, then you can't do the above. You would need to introduce at least one additional thread to actually do the close().
Have the program install a signal handler (for SIGUSR1 for example) doing nothing.
Use setsockopt() to unset the option SA_RESTART for the sockets in use.
Make the code issuing socket related system calls aware that they might return with -1 and errno set to EINTR.
Run the program.
Send it a signal for which the program has a handler installed (in 1.) from the outside (by for example using the kill <pid> -USR1 command).
Detect the reception of a signal (see 3.) and react, for example by close()ing the socket in question.

Handling 'intterupted system call' error when using timer

I'm writing an application that uses timer to do some data acquisition and processing at a fix sample rate (200Hz).
The application acts like a server and run in background. It should be controllable from other processes or other machines from UDP.
To do so, I use the timer_create() API to generate SIGUSR1 periodically and call an handler that do the acquisition and the processing.
The code to configure the timer is as follow (minus error check for clarity):
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, NULL);
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGUSR1;
sev.sigev_value.sival_ptr = &timerid;
timer_create(CLOCK_REALTIME, &sev, &timerid);
timer_settime(...)
The code above is called when a 'start' command is received from UDP. To check for command I have an infinite loop in my main program that call recvfrom() syscall.
The problem is, when a 'start' command is received, and then, the timer is properly started and running (using the code above), I get an 'interrupted system calls' error (EINTR) due the SIGUSR1 signal sent by the timer interrupting the recvfrom() call. If I check for this particular error code and ignore it, I finally get a 'connection refused' error when calling recvfrom().
So here my questions:
How to solve this 'interrupted system calls' error as it seems to
ignore it and re-do the recvfrom() doesn't work?
Why do I get the 'connection refused' error after about twenty tries?
I have the feeling that using SIGEV_THREAD could be a solution, as I understand it, create a new thread (like phread_create) without generate a signal. Am I right?
Is the signal number important here? Is there any plus to use real time signal?
Is there any other way to do what I intent to do: having a background loop checking for command from UDP and real-time periodic task?
And here the bonus question:
Is it safe to do the data acquisition and the processing in the handler or should I use a semaphore mechanism to wake up a thread that do it?
Solution:
As suggest in an answer and in the comments, using SA_RESTART seems to fix the main issue.
Solution 2:
Using SIGEV_THREAD over SIGEV_SIGNAL works too. I've read somewhere that using SIGEV_THREAD could require more ressources than SIGEV_SIGNAL. However I have not seen significant difference regarding the timing of the task.
Timers tend to be implemented using SIGALARM.
Signal receipt, including SIGALARM, tends to cause long running system calls to return early with EINTR in errno.
SA_RESTART is one way around this, so system calls interrupted by receipt of a signal, will be automatically restarted. Another is to check for EINTR from your system calls' errno's and restart them when you receive EINTR.
With read() and write() of course, you can't just restart, you need to pick up where you left off. That's why these return the length of data transmitted.
Given that you're using Linux, I would opt for using timerfd_create instead.
That way you can just select(2), poll(2) or epoll(7) instead and handle timer events without the difficulty of signal handlers in your main loop.
As for EINTR (Interrupted System Call), those are properly handled by just restarting the specific system call that got interrupted.
Restarting the interrupted system call is the correct response to EINTR. You "Connection Refused" problem is an unrelated error - on a UDP socket, it indicates that a previous packet sent on that socket was rejected by the destination (notified through an ICMP message).
Question 5: Your use of a message and real-time periodic thread is perfectly fine. However, I would suggest you avoid using timers altogether, precisely because they use signals. I've run into this problem myself and eventually replaced the timer with a simple clock_nanosleep() that uses TIMER_ABSTIME with time updated to maintain the desired rate (i.e. add the period to the absolute time). The result was simpler code, no more problems with signals, and a more accurate timer than the signal-based timer. BTW, you should measure your timer's period in the handler to make sure it is accurate enough. My experience with timers was 8 years ago, so the problem with accuracy might be fixed. However, the other problems with signals are inherent to signals themselves and thus can't be "solved" -- only worked around.
Also, I see no problem with doing data acquisition from the handler, it should certainly reduce latency in retrieving the data.

What happens to threads variables / handles when CTRL-C in main program is hit?

I have a C application running on AIX 6.1 using Websphere MQ 6.
The high level of the application is:
Main C application spawns a seperate THREAD that does the LOOP to get message off the queue.
When CTRL-C is hit I have a shutdown hook (via signals) that elegantly sets a "thread running variable" to FALSE and the thread ends.
The problem is whenever I hit CTRL-C I get the following reason code back:
2009 - MQRC_CONNECTION_BROKEN
So even though the MQGET on Websphere MQ is currently running the "connection handle" seems to "die" when I hit CTRL-C
Do I need to declare the connection handle in the thread as volatile or static or something else?
I assumed my thread shutdown was all 100%....and this connection broken issue is causing horrible logs to be generated on MQSeries...
I have posted a similar question to mqseries.net but was just wondering if I am missing some fundamental concept when CTRL-C is hit and my shutdown hook is triggered....
Any help will be greatly appreciated
Lynton
With the POSIX thread model consider this:
For any thread that calls pthread_sigmask() and blocks SIGINT, that thread will not receive the CTRC/C. Any of threads including the main thread, that have not blocked the signal will receive it. Handling the signal is different between the parent thread and the threads or LWP's you create.
So in the main program, you call sigprocmask() to set up handling SIGINT. As you described.
All of the other threads, on their own, have to block SIGINT, by calling pthread_sigmask().

Resources