szymon hrapkowicz
szymon hrapkowicz

Reputation: 143

C socket recv() error handling

I have a question about recv() function in socket (on linux Raspberri Pi)

Why does my program stops at:

if ((numbytes = recv(fd, odp, 100, 0)) == -1) {
    printf("\n error while test recv 1");
    perror("recv");
    reconnect = 1;
}

Yes, there is an error: "Resource remporarily unavaliable"

When i see: printf("\n error while test recv 1");

i want to handle reconnect what is made later. But i see on terminal window that my program stops on:

error while test recv 1

I've tried with:

signal(SIGPIPE, SIG_IGN);

than with:

signal(SIGPIPE, my_function);

but it stops at either.

Some code:

int main(int argc, char *argv[])
{

while(1) {          

    if(reconnect){
        close(fd);
        fd = createSocket(argv[1]);
        reconnect=0;
    }

reconnect = connectionTest(fd);

}


int connectionTest(int *fd) {

  numbytes=send(fd, buf, 100,0);

  if ((numbytes = recv(fd, reply, 100, 0)) == -1) {
/* HERE IT STOPS */
    perror("recv");
    printf("\n error while test recv 1");

    reconnect = 1;

  }

    return reconnect;
}

int createSocket(char *server_addr){

 int sockfd;
 struct addrinfo hints, *servinfo, *p;
 int rv;
 char s[INET6_ADDRSTRLEN];
 int set = 1;

signal(SIGPIPE, SIG_IGN);

printf("connect to: %s", server_addr); 

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    if ((rv = getaddrinfo(server_addr, PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    // loop through all the results and connect to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("client: socket");
            continue;
        }
        else printf("socketd created! \n");

    int set = 1;
setsockopt(sockfd, SOL_SOCKET, MSG_NOSIGNAL, (void *)&set, sizeof(int));

      if (setsockopt( sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&set, sizeof(int)) < 0 )
      perror("setsockopt failed \n");

struct timeval timeout;
  timeout.tv_sec = 4;
  timeout.tv_usec = 0;


      if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0 ) 
      perror("setsockopt failed \n");

      if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0 ) 
      perror("setsockopt failed \n");

      printf("Try to connect \n");
      if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("client: connect");
      }
      else {
        printf("i have connection");
        break;
     }
   }

printf("next1");  

    if (p == NULL) {
        fprintf(stderr, "client: failed to connect\n");
        return 2;
    }

    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
            s, sizeof s);
    printf("client: connecting to %s\n", s);
    freeaddrinfo(servinfo); // all done with this structure

return  sockfd;
}

Upvotes: 1

Views: 11995

Answers (2)

zakinster
zakinster

Reputation: 10698

You program may stop at the recv because it receive the SIGPIPE signal.

If you already try ignoring this signal with signal(SIGPIPE, SIG_IGN) note that you should do this before starting any thread otherwise one may be able to catch the signal before you ignore it.


Also note that you may be able to use setsockopt to configure your socket not to generate a SIGPIPE signal :

int optval = 1;
setsockopt(cs, SOL_SOCK, SO_NOSIGPIPE, (void *)&optval, sizeof(int))

This may not be available in your system.


Your system may also allow you to use the MSG_NOSIGNAL option in the recv to avoid the raise of the SIGPIPE signal :

recv(fd, odp, 100, MSG_NOSIGNAL ))

I think it works on Linux 2.2+


Once the signal is correctly ignored, your recv should return and you should be able to handle the error.

EDIT

Also you may have a XY problem here, if you want to detect if the pipe is broken, you don't actually have to read or write to it, you can use poll, also see : Linux: Checking if a socket/pipe is broken without doing a read()/write().

Upvotes: 2

alk
alk

Reputation: 70981

read() shall not return EPIPE.

If a write() is issued against a connection which had been shutdown() or even close()d by the other side the issueing process erros in any case.

A SIGPIPE is raised and if not handled nor is blocked the process will terminate. If SIGPIPE is handled or blocked write() shall return -1 and sets errno to EPIPE.

Upvotes: 2

Related Questions