0

I've a client/server program, now I want to handle signals. When the client closes the connection (if for example I close the terminal), the server has to handle a SIGPIPE, am I right? I'd like to implement something like this. Is it possible?

server.c:

void function(){
   printf("...");
   read(socket,buff,size);
   //IF THE CLIENT CLOSES, THE SERVER RECEIVES A SIGPIPE
   ...the resting part of the scheduled code should be ignored if sigpipe is received, and the program should begin from where I wrote on the handler of the sigpipe...
   printf("not working"); //this should be ignored, but it's printed 2 times immediatly, and when I've finished the actions indicated in the function by the handler, it prints it another time, because the program counter restarts from here...
}

void sigpipehandler(){
   close(socket);
   main(); //I'd like that the program restarts from the main when I've received a SIGPIPE. It restarts from the main, but only after having printed "not working" two times...
}

int main(){
   sigPipe.sa_sigaction = &sigpipehandler;
   sigPipe.sa_flags = SA_SIGINFO;
   sigaction(SIGPIPE, &sigpipehandler, NULL);
   ...code...
}
testermaster
  • 1,031
  • 6
  • 21
  • 40
  • You get SIGPIPE when you write to a closed pipe; you get EOF (zero bytes read) when you read from a closed pipe. – Jonathan Leffler Oct 22 '14 at 05:54
  • @JonathanLeffler Thanks for your reply. So, if I change the read with a write in the example.. How can I handle the SIGPIPE like explained? – testermaster Oct 22 '14 at 06:00
  • 3
    Simplest is to ignore SIGPIPE and then monitor the return value from `write()`. If it comes back with -1 and `errno` set to EINTR, you can suspect you got a SIGPIPE, especially if you don't have any other signal handling set. Of course, you should be looking at the return value from `write()` — and `read()` — anyway. You do not want to recursively call `main()` from your signal handler. You can write a loop in `main()`, and have the signal handler set a flag which you test in the loop. Per Standard C, about the only thing you can do in a signal handler is modify a variable or exit. – Jonathan Leffler Oct 22 '14 at 06:02

1 Answers1

1

Converting comments into an answer.

Note that you only get SIGPIPE when you write to a pipe where there is no process with the read end of the pipe open. You get EOF (zero bytes read) when you read from a pipe that has no process with the write end of the pipe open.

So, if I change the read() with a write() in the example. How can I handle the SIGPIPE?

Simplest is to ignore SIGPIPE (signal(SIGPIPE, SIG_IGN)) and then monitor the return value from write(). If it comes back with -1 and errno set to EINTR, you can assume you got interrupted by some signal, and most probably a SIGPIPE, especially if you don't have any other signal handling set. Of course, you should be looking at the return value from write() — and read() — anyway.

Alternatively, if you want an explicit SIGPIPE handler, then you definitely do not want to recursively call main() from your signal handler. You can write a loop in main(), and have the signal handler set a flag which you test in the loop. Per Standard C, about the only thing you can do in a signal handler is modify a variable or exit.

static volatile sigatomic_t sig_recvd = 0;
static int sock_fd = -1;

void sigpipehandler(int signum)
{
   close(sock_fd);
   sock_fd = -1;
   sig_recvd = signum;
}

int main(void)
{
    sigPipe.sa_sigaction = &sigpipehandler;
    sigPipe.sa_flags = SA_SIGINFO;
    sigemptyset(&sigPipe.sa_mask);
    sigaction(SIGPIPE, &sigpipehandler, NULL);

    int done = 0;

    while (!done)
    {
        if (sock_fd == -1)
        {
            if (sig_recvd != 0)
            {
                ...report signal received...
                sig_recvd = 0;
            }
            ...(re)open socket on sock_fd...
        }
        ...code as before - sets done = 1 when loop should terminate...
    }
    return 0;
}

Note that naming a variable the same as a system call (socket in your code) is treading on thin ice; hence, I renamed it sock_fd. A global variable called socket would be a really bad idea.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278