send( ) problem - c

When I test my program using a web browser I can write to the socket/FD just fine so i decided to loop it and cut the connection mid-connection and I noticed a problem. send() is capable of closing down the entire program when the socket is unavailable. I thought the problem was that the program caught itself in a catch-22 and closed itself. So I set the socket to not block. No change. Any ideas of why this is happening?
else if ( b->temp_socket_list[read].revents & POLLOUT ) {
printf ( "#Write#\n" );
char *done = "Done!";
int sent = send ( sock, done, 5, 0 );
printf ( "end\n", sent );
}

This is likely due to the default action of the SIGPIPE signal. To ignore this signal, use something like:
signal(SIGPIPE, SIG_IGN);
Socket errors will then be reported as return values from socket functions, rather than a signal.

Which platform is this?
On UNIX in some cases you can get a signal when the connection goes down (SIGPIPE) and this terminates the program by default... the solution is to install a signal handler for SIGPIPE that does nothing.

Try this:
sigset_t set, oldset;
sigemptyset(&set);
sigaddset(&set, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &set, &oldset);
/* use send all you like here */
sigtimedwait(&set, 0, (struct timespec [1]){0});
pthread_sigmask(SIG_SETMASK, &oldset, 0);
I'm not 100% sure it works, but I believe it should, and if it's correct then it's a solution that can be used from library code without messing up the state of the caller or other potentially-signal-using threads.
Also note that if the program (or even just the current thread) does not want to make use of SIGPIPE, you can simplify this a lot by just leaving SIGPIPE permanently blocked:
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &set, &oldset);

Related

master error when multiple signal are sent

I got this issue:
I made a program in c, where the main process creates some child process, and these, after a while, are able to send a signal to the main process:
the signal is sent with this code:
kill(getppid(), SIGUSR1);
and the main process, in the while loop is waiting the SIGUSR1 message...
everything is fine, but if I increase the child number and automatically the possibility to have more signals in the same time, the program crash printing the message:
User defined signal 1
the main code is like this:
void signalHandler(int sig, siginfo_t* info, void* vp) {
if (sig == SIGUSR1) {
printf("SIGUSR1 has arrived\n");
} else if (sig == SIGUSR2) {
printf("SIGUSR2 has arrived\n");
}
}
int main(int argc, char const *argv[]) {
struct sigaction action, old_action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_sigaction = signalHandler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_RESTART | SA_NODEFER;
while (1) {
sigaction(SIGUSR1, &action, &old_action);
sigaction(SIGUSR2, &action, &old_action);
}
}
I think the problem is that the signal is sent when the master is still working on the previous signal...but how can I do to fix this thing
thank you very much
It means that the child is sending the signal before the parent process was able to call sigaction() to configure the signal handler. When this happens, the default signal reaction to SIGUSR1 terminates the program:
SIGUSR1 P1990 Term User-defined signal 1
https://man7.org/linux/man-pages/man7/signal.7.html
However, there are many problems with your code. printf() is not safe to be called inside a signal handler (it's AS-Unsafe as defined by POSIX):
https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/V2_chap02.html#tag_15_04_03
Also, using SA_NODEFER may create nested signals (another signal handler is called while some signal handler is running) but your program does not protect against a flood. Given enough children this will generate a stack overflow. Finally, the main program keeps running a non-stop infinite loop reconfiguring the signals, while it should have configured them only once outside the loop and blocked inside the loop (for example sigwait() or pselect()):
https://man7.org/linux/man-pages/man2/select.2.html
Finally, if you expect to run a large number of children that might flood the parent with signals, then it would be better to use the real time signal generation function (sigqueue()) rather than kill(). The difference is that with sigqueue(), all signals are queued and SA_NODEFER is not necessary to avoid discarding signals while some other signal handler is running:
https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/V2_chap02.html#tag_15_04_02
Final conclusion: the code should be completely rewritten.

Handle signals with epoll_wait and signalfd

I'm writing my own echo server using sockets and syscalls. I am using epoll to work with many different clients at the same time and all the operations done with clients are nonblocking. When the server is on and doing nothing, it is in epoll_wait. Now I want to add the possibility to shut the server down using signals. For example, I start the server in bash terminal, then I press ctrl-c and the server somehow handles SIGINT. My plan is to use signalfd. I create new signalfd and add it to epoll instance with the following code:
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGINT);
signal_fd = signalfd(-1, &mask, 0);
epoll_event event;
event.data.fd = signal_fd;
event.events = EPOLLIN;
epoll_ctl(fd, EPOLL_CTL_ADD, signal_fd, &event);
Then I expect, that when epoll is waiting and I press ctrl-c, event on epoll happens, it wakes up and then I handle the signal with the following code:
if (events[i].data.fd == signal_fd)
{
//do something
exit(0);
}
Though in reality the server just stops without handling the signal. What am I doing wrong, what is the correct way to solve my problem? And if I'm not understanding signals correctly, what is the place, where the one should use signalfd?
epoll_wait returns -1 and errno == EINTR when it is interrupted by a signal. In this case you need to read from signal_fd.
Set the signal handler for your signals to SIG_IGN, otherwise signals may terminate your application.
See man signal 7:
The following interfaces are never restarted after being interrupted by
a signal handler, regardless of the use of SA_RESTART; they always fail
with the error EINTR when interrupted by a signal handler:
File descriptor multiplexing interfaces: epoll_wait(2),
epoll_pwait(2), poll(2), ppoll(2), select(2), and pselect(2).
Though in reality the server just stops without handling the signal. What am I doing wrong, what is the correct way to solve my problem? And if I'm not understanding signals correctly, what is the place, where one should use signalfd?
Signal handlers are per process. You left the signal handler at the default, which is to terminate the processes.
So you need to add something like this,
struct sigaction action;
std::memset(&action, 0, sizeof(struct sigaction));
action.sa_handler = your_handler;
sigaction(signum, &action, NULL);
for each signum that you want your application to receive interrupts for. Also handle the return value of sigaction. My experience is that if you use SIG_IGN as handler than you still interrupt a system call like epoll_pwait from the "outside", but it won't work when you try to wake up the thread from the program itself by sending the signal directly to that thread using pthread_kill.
Next you need to mask all signals from every thread, so that by default no thread will receive it (otherwise a random thread is woken up to handle the signal). The easiest way to do that is by doing it in main before creating any thread.
For example,
sigset_t all_signals;
sigemptyset(&all_signals);
sigaddset(&all_signals, signum); // Repeat for each signum that you use.
sigprocmask(SIG_BLOCK, &all_signals, NULL);
And then unblock the signals per thread when you want that thread to receive the signal.
If you use signalfd, then you do not want to unblock them - that system call unblocks the signals itself, just pass the appropriate mask (set bits for signalfd (it uses the passed mask to unblock). See also the man page of signalfd).
epoll_pwait works differently; like pselect you unblock the signal that you are interested in. You set a handler for that signal (see above) that sets a flag. Then just before calling epoll_pwait you block the signal, then test the flag and handle it, and then call epoll_pwait without first unblocking the signal. After epoll_wait returns you can unblock the signal again so that your handler can be called again.
You have to block all the signals you want to handle with your signal-FD before you create that signal-FD. Otherwise, those signals still interrupt blocked system calls such as epoll_wait() - as you observed.
See also the signalfd(2) man page:
Normally, the set of signals to be received via the file descriptor
should be blocked using sigprocmask(2), to prevent the signals being
handled according to their default dispositions.
Thus, you have to change your example like this:
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGINT);
int r = sigprocmask(SIG_BLOCK, &mask, 0);
if (r == -1) {
// XXX handle errors
}
signal_fd = signalfd(-1, &mask, 0);
if (signal_fd == -1) {
// XXX handle errors
}
epoll_event event;
event.data.fd = signal_fd;
event.events = EPOLLIN;
r = epoll_ctl(fd, EPOLL_CTL_ADD, signal_fd, &event);
if (r == -1) {
// XXX handle errors
}

C: fork() inform parent when child process disconnects

I am doing a simple server/client program in C which listens on a network interface and accepts clients. Each client is handled in a forked process.
The goal I have is to let the parent process know, once a client has disconnected from the child process.
Currently my main loop looks like this:
for (;;) {
/* 1. [network] Wait for new connection... (BLOCKING CALL) */
fd_listen[client] = accept(fd_listen[server], (struct sockaddr *)&cli_addr, &clilen);
if (fd_listen[client] < 0) {
perror("ERROR on accept");
exit(1);
}
/* 2. [process] Call socketpair */
if ( socketpair(AF_LOCAL, SOCK_STREAM, 0, fd_comm) != 0 ) {
perror("ERROR on socketpair");
exit(1);
}
/* 3. [process] Call fork */
pid = fork();
if (pid < 0) {
perror("ERROR on fork");
exit(1);
}
/* 3.1 [process] Inside the Child */
if (pid == 0) {
printf("[child] num of clients: %d\n", num_client+1);
printf("[child] pid: %ld\n", (long) getpid());
close(fd_comm[parent]); // Close the parent socket file descriptor
close(fd_listen[server]); // Close the server socket file descriptor
// Tasks that the child process should be doing for the connected client
child_processing(fd_listen[client]);
exit(0);
}
/* 3.2 [process] Inside the Parent */
else {
num_client++;
close(fd_comm[child]); // Close the child socket file descriptor
close(fd_listen[client]); // Close the client socket file descriptor
printf("[parent] num of clients: %d\n", num_client);
while ( (w = waitpid(-1, &status, WNOHANG)) > 0) {
printf("[EXIT] child %d terminated\n", w);
num_client--;
}
}
}/* end of while */
It all works well, the only problem I have is (probably) due to the blocking accept call.
When I connect to the above server, a new child process is created and child_processing is called.
However when I disconnect with that client, the main parent process does not know about it and does NOT output printf("[EXIT] child %d terminated\n", w);
But, when I connect with a second client after the first client has disconnected, the main loop is able to finally process the while ( (w = waitpid(-1, &status, WNOHANG)) > 0) part and tell me that the first client has disconnected.
If there will be only ever one client connecting and disconnecting afterwards, my main parent process will never be able to tell if it has disconnected or not.
Is there any way to tell the parent process that my client already left?
UPDATE
As I am a real beginner with c, it would be nice if you provide some short snippets to your answer so I can actually understand it :-)
Your waitpid usage is not correct. You have a non-blocking call so if the child is not finished then then the call gets 0:
waitpid(): on success, returns the process ID of the child whose state
has changed; if WNOHANG was specified and one or more child(ren)
specified by pid exist, but have not yet changed state, then 0 is
returned. On error, -1 is returned.
So your are going immediately out of the while loop. Of course this can be catched later when the first children terminates and a second one lets you process the waitpid again.
As you need to have a non-blocking call to wait I can suggest you not to manage termination directly but through SIGCHLD signal that will let you catch termination of any children and then appropriately call waitpid in the handler:
void handler(int signal) {
while (waitpid(...)) { // find an adequate condition and paramters for your needs
}
...
struct sigaction act;
act.sa_flag = 0;
sigemptyset(&(act.sa_mask));
act.sa_handler = handler;
sigaction(SIGCHLD,&act,NULL);
... // now ready to receive SIGCHLD when at least a children changes its state
If I understand correctly, you want to be able to servicve multiple clients at once, and therefore your waitpid call is correct in that it does not block if no child has terminated.
However, the problem you then have is that you need to be able to process asynchronous child termination while waiting for new clients via accept.
Assuming that you're dealing with a POSIXy system, merely having a SIGCHLD handler established and having the signal unmasked (via sigprocmask, though IIRC it is unmasked by default), should be enough to cause accept to fail with EINTR if a child terminates while you are waiting for a new client to connect - and you can then handle EINTR appropriately.
The reason for this is that a SIGCHLD signal will be automatically sent to the parent process when a child process terminates. In general, system calls such as accept will return an error of EINTR ("interrupted") if a signal is received while they are waiting.
However, there would still be a race condition, where a child terminates just before you call accept (i.e. in between where already have waitpid and accept). There are two main possibilities to overcome this:
Do all the child termination processing in your SIGCHLD handler, instead of the main loop. This may not be feasible, however, since there are significant limits to what you are allowed to do within a signal handler. You may not call printf for example (though you may use write).
I do not suggest you go down this path, although it may seem simpler at first it is the least flexible option and may prove unworkable later.
Write to one end of a non-blocking pipe in your SIGCHLD signal handler. Within the main loop, instead of calling accept directly, use poll (or select) to look for readiness on both the socket and the read end of the pipe, and handle each appropriately.
On Linux (and OpenBSD, I'm not sure about others) you can use ppoll (man page) to avoid the need to create a pipe (and in this case you should leave the signal masked, and have it unmasked during the poll operation; if ppoll fails with EINTR, you know that a signal was received, and you should call waitpid). You still need to set a signal handler for SIGCHLD, but it doesn't need to do anything.
Another option on Linux is to use signalfd (man page) to avoid both the need to create a pipe and set up a signal handler (I think). You should mask the SIGCHLD signal (using sigprocmask) if you use this. When poll (or equivalent) indicates that the signalfd is active, read the signal data from it (which clears the signal) and then call waitpid to reap the child.
On various BSD systems you can use kqueue (OpenBSD man page) instead of poll and watch for signals without needing to establish a signal handler.
On other POSIX systems you may be able to use pselect (documentation) in a similar way to ppoll as described above.
There is also the option of using a library such as libevent to abstract away the OS-specifics.
The Glibc manual has an example of using select. Consult the manual pages for poll, ppoll, pselect for more information about those functions. There is an online book on using Libevent.
Rough example for using select, borrowed from Glibc documentation (and modified):
/* Set up a pipe and set signal handler for SIGCHLD */
int pipefd[2]; /* must be a global variable */
pipe(pipefd); /* TODO check for error return */
fcntl(pipefd[1], F_SETFL, O_NONBLOCK); /* set write end non-blocking */
/* signal handler */
void sigchld_handler(int signum)
{
char a = 0; /* write anything, doesn't matter what */
write(pipefd[1], &a, 1);
}
/* set up signal handler */
signal(SIGCHLD, sigchld_handler);
Where you currently have accept, you need to check status of the server socket and the read end of the pipe:
fd_set set, outset;
struct timeval timeout;
/* Initialize the file descriptor set. */
FD_ZERO (&set);
FD_SET (fdlisten[server], &set);
FD_SET (pipefds[0], &set);
FD_ZERO(&outset);
for (;;) {
select (FD_SETSIZE, &set, NULL, &outset, NULL /* no timeout */));
/* TODO check for error return.
EINTR should just continue the loop. */
if (FD_ISSET(fdlisten[server], &outset)) {
/* now do accept() etc */
}
if (FD_ISSET(pipefds[0], &outset)) {
/* now do waitpid(), and read a byte from the pipe */
}
}
Using other mechanisms is generally simpler, so I leave those as an exercise :)

Where to declare sig_t signal for SIGPIPE

I'm currently using a kqueue to handle multiple Clients per Thread in a Serverprocess
so I don't want the thread to be terminated when the Signal SIGPIPE appears, i would just like to remove the according socked id from the kqueue.
So My question is: Is there a way to get the according socketid inside a Signalhandle and parse it back to the Process to remove it from the event kqueue or would i have jsut to SIG_IGN the SIGPIPE
and handle the remove by returning of -1 from send? and would it return the -1 value after a timeout time or returns send -1 instantly?
And finally, if the signal ignore is my solution: where id have to put the declaration of the
typedef void (*sig_t) (int);
sig_t
signal(int sig, sig_t func);
Would it have to be in the main function?
or in the beginning of the corresponding thread? or just as global element?
I can't think of an easy way for the signal handler to come to know the current socket being processed unless you are setting some global state each time you do a socket operation.
You can ignore SIGPIPE from main. You do not define your own handler, instead you use SIG_IGN.
signal(SIGPIPE, SIG_IGN);
Or, if you are using sigaction:
struct sigaction act;
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGPIPE, &act, NULL);
Alternatively, you can issue the MSG_NOSIGNAL flag when you call send. This will suppress the generation of SIGPIPE, and instead generate an EPIPE error (which is what would happen if you ignored SIGPIPE):
ssize_t sent = send(sock, buf, sizeof(buf), MSG_NOSIGNAL);
if (sent > 0) {
/* ... */
} else {
assert(sent < 0);
swtich (errno) {
case EPIPE:
/* ...handle sending on a closed socket */
/* ...handle other error cases */
}
}
'signal( ...' code should be in 'main'.

c / interrupted system call / fork vs. thread

I discovered an issue with thread implementation, that is strange to me. Maybe some of you can explain it to me, would be great.
I am working on something like a proxy, a program (running on different machines) that receives packets over eth0 and sends it through ath0 (wireless) to another machine which is doing the exactly same thing. Actually I am not at all sure what is causing my problem, that's because I am new to everything, linux and c programming.
I start two threads,
one is listening (socket) on eth0 for incoming packets and sends it out through ath0 (also socket)
and the other thread is listening on ath0 and sends through eth0.
If I use threads, I get an error like that:
sh-2.05b# ./socketex
Failed to send network header packet.
: Interrupted system call
If I use fork(), the program works as expected.
Can someone explain that behaviour to me?
Just to show the sender implementation here comes its code snippet:
while(keep_going) {
memset(&buffer[0], '\0', sizeof(buffer));
recvlen = recvfrom(sockfd_in, buffer, BUFLEN, 0, (struct sockaddr *) &incoming, &ilen);
if(recvlen < 0) {
perror("something went wrong / incoming\n");
exit(-1);
}
strcpy(msg, buffer);
buflen = strlen(msg);
sentlen = ath_sendto(sfd, &btpinfo, &addrnwh, &nwh, buflen, msg, &selpv2, &depv);
if(sentlen == E_ERR) {
perror("Failed to send network header packet.\n");
exit(-1);
}
}
UPDATE: my main file, starting either threads or processes (fork)
int main(void) {
port_config pConfig;
memset(&pConfig, 0, sizeof(pConfig));
pConfig.inPort = 2002;
pConfig.outPort = 2003;
pid_t retval = fork();
if(retval == 0) {
// child process
pc2wsuThread((void *) &pConfig);
} else if (retval < 0) {
perror("fork not successful\n");
} else {
// parent process
wsu2pcThread((void *) &pConfig);
}
/*
wint8 rc1, rc2 = 0;
pthread_t pc2wsu;
pthread_t wsu2pc;
rc1 = pthread_create(&pc2wsu, NULL, pc2wsuThread, (void *) &pConfig);
rc2 = pthread_create(&wsu2pc, NULL, wsu2pcThread, (void *) &pConfig);
if(rc1) {
printf("error: pthread_create() is %d\n", rc1);
return(-1);
}
if(rc2) {
printf("error: pthread_create() is %d\n", rc2);
return(-1);
}
pthread_join(pc2wsu, NULL);
pthread_join(wsu2pc, NULL);
*/
return 0;
}
Does it help?
update 05/30/2011
-sh-2.05b# ./wsuproxy 192.168.1.100
mgmtsrvc
mgmtsrvc
Failed to send network header packet.
: Interrupted system call
13.254158,75.165482,DATAAAAAAmgmtsrvc
mgmtsrvc
mgmtsrvc
Still get the interrupted system call, as you can see above.
I blocked all signals as followed:
sigset_t signal_mask;
sigfillset(&signal_mask);
sigprocmask(SIG_BLOCK, &signal_mask, NULL);
The two threads are working on the same interfaces, but on different ports. The problem seems to appear still in the same place (please find it in the first code snippet). I can't go further and have not enough knowledge of how to solve that problem. Maybe some of you can help me here again.
Thanks in advance.
EINTR does not itself indicate an error. It means that your process received a signal while it was in the sendto syscall, and that syscall hadn't sent any data yet (that's important).
You could retry the send in this case, but a good thing would be to figure out what signal caused the interruption. If this is reproducible, try using strace.
If you're the one sending the signal, well, you know what to do :-)
Note that on linux, you can receive EINTR on sendto (and some other functions) even if you haven't installed a handler yourself. This can happen if:
the process is stopped (via SIGSTOP for example) and restarted (with SIGCONT)
you have set a send timeout on the socket (via SO_SNDTIMEO)
See the signal(7) man page (at the very bottom) for more details.
So if you're "suspending" your service (or something else is), that EINTR is expected and you should restart the call.
Keep in mind if you are using threads with signals that a given signal, when delivered to the process, could be delivered to any thread whose signal mask is not blocking the signal. That means if you have blocked incoming signals in one thread, and not in another, the non-blocking thread will receive the signal, and if there is no signal handler setup for the signal, you will end-up with the default behavior of that signal for the entire process (i.e., all the threads, both signal-blocking threads and non-signal-blocking threads). For instance, if the default behavior of a signal was to terminate a process, one thread catching that signal and executing it's default behavior will terminate the entire process, for all the threads, even though some threads may have been masking the signal. Also if you have two threads that are not blocking a signal, it is not deterministic which thread will handle the signal. Therefore it's typically the case that mixing signals and threads is not a good idea, but there are exceptions to the rule.
One thing you can try, is since the signal mask for a spawned thread is inherited from the generating thread, is to create a daemon thread for handling signals, where at the start of your program, you block all incoming signals (or at least all non-important signals), and then spawn your threads. Now those spawned threads will ignore any incoming signals in the parent-thread's blocked signal mask. If you need to handle some specific signals, you can still make those signals part of the blocked signal mask for the main process, and then spawn your threads. But when you're spawning the threads, leave one thread (could even be the main process thread after it's spawned all the worker threads) as a "daemon" thread waiting for those specific incoming (and now blocked) signals using sigwait(). That thread will then dispatch whatever functions are necessary when a given signal is received by the process. This will avoid signals from interrupting system calls in your other worker-threads, yet still allow you to handle signals.
The reason your forked version may not be having issues is because if a signal arrives at one parent process, it is not propagated to any child processes. So I would try, if you can, to see what signal it is that is terminating your system call, and in your threaded version, block that signal, and if you need to handle it, create a daemon-thread that will handle that signal's arrival, with the rest of the threads blocking that signal.
Finally, if you don't have access to any external libraries or debuggers, etc. to see what signals are arriving, you can setup a simple procedure for seeing what signals might be arriving. You can try this code:
#include <signal.h>
#include <stdio.h>
int main()
{
//block all incoming signals
sigset_t signal_mask;
sigfillset(&signal_mask);
sigprocmask(SIG_BLOCK, &signal_mask, NULL);
//... spawn your threads here ...
//... now wait for signals to arrive and see what comes in ...
int arrived_signal;
while(1) //you can change this condition to whatever to exit the loop
{
sigwait(&signal_mask, &arrived_signal);
switch(arrived_signal)
{
case SIGABRT: fprintf(stderr, "SIGABRT signal arrived\n"); break;
case SIGALRM: fprintf(stderr, "SIGALRM signal arrived\n"); break;
//continue for the rest of the signals defined in signal.h ...
default: fprintf(stderr, "Unrecognized signal arrived\n");
}
}
//clean-up your threads and anything else needing clean-up
return 0;
}

Resources