48

I write a client program based on posix sockets. The program creates multiple threads and is going to lock the server. But during debug in gdb time the program gives an info (error)

(gdb) n
Program received signal SIGPIPE, Broken pipe. [Switching to Thread 0xb74c0b40 (LWP 4864)] 0xb7fdd424 in __kernel_vsyscall () 
(gdb) 

Here's the code:

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

int get_hostname_by_ip(char* h , char* ip)
{
    struct hostent *he;
    struct in_addr **addr_list;
    int i;

    if ((he = gethostbyname(h)) == NULL) 
    {
        perror("gethostbyname");
        return 1;
    }
    addr_list = (struct in_addr **) he->h_addr_list;
    for(i = 0; addr_list[i] != NULL; i++) 
    {
        strcpy(ip , inet_ntoa(*addr_list[i]) );
        return 0;
    }

    return 1;
}

void client(char* h, int s)
{
    int fd;
    struct sockaddr_in addr;
    char ch[]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    fd = socket(AF_INET, SOCK_STREAM, 0);
    addr.sin_family=AF_INET;
    char* ip = new char[20];
    get_hostname_by_ip(h, ip);
    addr.sin_addr.s_addr=inet_addr(ip);
    int port = 80;
    addr.sin_port=htons(port);
    if(connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) 
    {
        perror("connect error");
        return;
    }
    while(1)
    {
        if(send(fd, ch, sizeof(ch), 0) < 0)
        {   
            perror("send");
        }
    }
    //char buffer[1024];
    //if(recv(fd, &buffer, sizeof(buffer), 0) < 0)
    //{ 
    //  perror("recive");
    //}

    //printf("nReply from Server: %s\n", buffer);
    close(fd);
}

struct info
{
    char* h;
    int c;
};


void* thread_entry_point(void* i)
{
    info* in = (info*)i;
    client(in->h, in->c);
}

int main(int argc, char** argv)
{
    int s = atoi(argv[2]);
    pthread_t t[s];
    info in = {argv[1], s};
    for(int i = 0; i < s; ++i)
    {
        pthread_create(&t[i], NULL, thread_entry_point, (void*)&in);
    }
    pthread_join(t[0], NULL);

    return 0;
}

What it is and what to do?

alk
  • 69,737
  • 10
  • 105
  • 255
  • Possible duplicate of [How to prevent SIGPIPEs (or handle them properly)](https://stackoverflow.com/questions/108183/how-to-prevent-sigpipes-or-handle-them-properly) – iammilind May 14 '19 at 07:22

5 Answers5

67

The process received a SIGPIPE. The default behaviour for this signal is to end the process.

A SIGPIPE is sent to a process if it tried to write to a socket that had been shutdown for writing or isn't connected (anymore).

To avoid that the program ends in this case, you could either

  • make the process ignore SIGPIPE

    #include <signal.h>
    
    int main(void)
    {
      sigaction(SIGPIPE, &(struct sigaction){SIG_IGN}, NULL);
    
      ...
    

    or

  • install an explicit handler for SIGPIPE (typically doing nothing):

    #include <signal.h>
    
    void sigpipe_handler(int unused)
    {
    }
    
    int main(void)
    {
      sigaction(SIGPIPE, &(struct sigaction){sigpipe_handler}, NULL);
    
      ...
    

In both cases send*()/write() would return -1 and set errno to EPIPE.

alk
  • 69,737
  • 10
  • 105
  • 255
  • would this work? if(signal(SIGPIPE, signalHandler) == EINVAL) how would I get the error -1 and EPIPE. – n0minal Oct 03 '13 at 08:11
  • @Dreyfus15: To clarify uncertainties on how to sert up signal handlers please post another question on this. – alk Oct 04 '13 at 05:58
44

When debugging with 'gdb', it is possible to manually disable SIGPIPE as follows:

(gdb) handle SIGPIPE nostop

Jason Chagas
  • 441
  • 4
  • 2
  • 20
    It's actually `handle SIGPIPE nostop noprint pass` – Treviño Nov 20 '18 at 00:56
  • That will then terminate the program instead of stopping in gdb (unless the program ignores SIGPIPE or installed a handler for it, as per the accepted answer). – Carlo Wood Jun 30 '19 at 18:14
13

A workaround for SIGPIPE, you can ignore this signal by this code:

#include <signal.h>

/* Catch Signal Handler functio */
void signal_callback_handler(int signum){

        printf("Caught signal SIGPIPE %d\n",signum);
}

in your code (main or globally)

/* Catch Signal Handler SIGPIPE */
signal(SIGPIPE, signal_callback_handler);
ralight
  • 11,033
  • 3
  • 49
  • 59
Hatem Mashaqi
  • 610
  • 1
  • 7
  • 18
  • 9
    Your signal handler for SIGPIPE writes a message out to stdout. But suppose writing to stdout is what caused the SIGPIPE in the first place...? – tetsujin Feb 28 '17 at 19:22
  • 6
    Using non-reentrant stdio from signal handlers is not safe. – ulix Oct 21 '17 at 07:47
  • It's true that you have to worry about reentrant code if you are doing a printf() in the handler. However seeing it's just an example I feel a printf() is fine, just throw a signal(SIGPIPE, SIG_DFL); before the printf() and you should be fine. – Paul Hutchinson Aug 15 '20 at 23:25
  • or you could just ignore it directly without providing any fake handler, i.e. `signal(SIGPIPE, SIG_IGN);` – ad3angel1s Aug 30 '23 at 13:36
9

You have written to a connection that has already been closed by the peer.

user207421
  • 305,947
  • 44
  • 307
  • 483
5

I sort of experienced the same problem and it let me to this SO post. I got sporadic SIGPIPE signals causing crashes of my fastcgi C program run by nginx. I tried to signal(SIGPIPE, SIG_IGN); without luck, it kept crashing.

The reason was that nginx's temp dir had a permission problem. Fixing the permissions solved the SIGPIPE problem. Details here on how to fix and more here.

neoneye
  • 50,398
  • 25
  • 166
  • 151