Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: socket connection timeout

I have a simple program to check if a port is open, but I want to shorten the timeout length on the socket connection because the default is far too long. I'm not sure how to do this though. Here's the code:

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

int main(int argc, char **argv) {
    u_short port;                /* user specified port number */
    char addr[1023];             /* will be a copy of the address entered by u */
    struct sockaddr_in address;  /* the libc network address data structure */
    short int sock = -1;         /* file descriptor for the network socket */

    if (argc != 3) {
        fprintf(stderr, "Usage %s <port_num> <address>", argv[0]);
        return EXIT_FAILURE;
    }

    address.sin_addr.s_addr = inet_addr(argv[2]); /* assign the address */
    address.sin_port = htons(atoi(argv[2]));            /* translate int2port num */

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (connect(sock,(struct sockaddr *)&address,sizeof(address)) == 0) {
        printf("%i is open\n", port);
    }  
    close(sock);
    return 0;
}
like image 474
The.Anti.9 Avatar asked Apr 08 '10 04:04

The.Anti.9


People also ask

What is socket connection timeout?

socket timeout — a maximum time of inactivity between two data packets when exchanging data with a server.

How do you set a socket timeout?

Java socket timeout Answer: Just set the SO_TIMEOUT on your Java Socket, as shown in the following sample code: String serverName = "localhost"; int port = 8080; // set the socket SO timeout to 10 seconds Socket socket = openSocket(serverName, port); socket.

Why is socket timing out?

Socket timeouts can occur when attempting to connect to a remote server, or during communication, especially long-lived ones. They can be caused by any connectivity problem on the network, such as: A network partition preventing the two machines from communicating. The remote machine crashing.


3 Answers

Set the socket non-blocking, and use select() (which takes a timeout parameter). If a non-blocking socket is trying to connect, then select() will indicate that the socket is writeable when the connect() finishes (either successfully or unsuccessfully). You then use getsockopt() to determine the outcome of the connect():

int main(int argc, char **argv) {     u_short port;                /* user specified port number */     char *addr;                  /* will be a pointer to the address */     struct sockaddr_in address;  /* the libc network address data structure */     short int sock = -1;         /* file descriptor for the network socket */     fd_set fdset;     struct timeval tv;      if (argc != 3) {         fprintf(stderr, "Usage %s <port_num> <address>\n", argv[0]);         return EXIT_FAILURE;     }      port = atoi(argv[1]);     addr = argv[2];      address.sin_family = AF_INET;     address.sin_addr.s_addr = inet_addr(addr); /* assign the address */     address.sin_port = htons(port);            /* translate int2port num */      sock = socket(AF_INET, SOCK_STREAM, 0);     fcntl(sock, F_SETFL, O_NONBLOCK);      connect(sock, (struct sockaddr *)&address, sizeof(address));      FD_ZERO(&fdset);     FD_SET(sock, &fdset);     tv.tv_sec = 10;             /* 10 second timeout */     tv.tv_usec = 0;      if (select(sock + 1, NULL, &fdset, NULL, &tv) == 1)     {         int so_error;         socklen_t len = sizeof so_error;          getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len);          if (so_error == 0) {             printf("%s:%d is open\n", addr, port);         }     }      close(sock);     return 0; } 
like image 70
caf Avatar answered Oct 28 '22 23:10

caf


This article might help:

Connect with timeout (or another use for select() )

Looks like you put the socket into non-blocking mode until you've connected, and then put it back into blocking mode once the connection's established.

void connect_w_to(void) {    int res;    struct sockaddr_in addr;    long arg;    fd_set myset;    struct timeval tv;    int valopt;    socklen_t lon;     // Create socket    soc = socket(AF_INET, SOCK_STREAM, 0);    if (soc < 0) {       fprintf(stderr, "Error creating socket (%d %s)\n", errno, strerror(errno));       exit(0);    }     addr.sin_family = AF_INET;    addr.sin_port = htons(2000);    addr.sin_addr.s_addr = inet_addr("192.168.0.1");     // Set non-blocking    if( (arg = fcntl(soc, F_GETFL, NULL)) < 0) {       fprintf(stderr, "Error fcntl(..., F_GETFL) (%s)\n", strerror(errno));       exit(0);    }    arg |= O_NONBLOCK;    if( fcntl(soc, F_SETFL, arg) < 0) {       fprintf(stderr, "Error fcntl(..., F_SETFL) (%s)\n", strerror(errno));       exit(0);    }    // Trying to connect with timeout    res = connect(soc, (struct sockaddr *)&addr, sizeof(addr));    if (res < 0) {       if (errno == EINPROGRESS) {          fprintf(stderr, "EINPROGRESS in connect() - selecting\n");          do {             tv.tv_sec = 15;             tv.tv_usec = 0;             FD_ZERO(&myset);             FD_SET(soc, &myset);             res = select(soc+1, NULL, &myset, NULL, &tv);             if (res < 0 && errno != EINTR) {                fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));                exit(0);             }             else if (res > 0) {                // Socket selected for write                lon = sizeof(int);                if (getsockopt(soc, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) {                   fprintf(stderr, "Error in getsockopt() %d - %s\n", errno, strerror(errno));                   exit(0);                }                // Check the value returned...                if (valopt) {                   fprintf(stderr, "Error in delayed connection() %d - %s\n", valopt, strerror(valopt)  );                   exit(0);                }                break;             }             else {                fprintf(stderr, "Timeout in select() - Cancelling!\n");                exit(0);             }          } while (1);       }       else {          fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));          exit(0);       }    }    // Set to blocking mode again...    if( (arg = fcntl(soc, F_GETFL, NULL)) < 0) {       fprintf(stderr, "Error fcntl(..., F_GETFL) (%s)\n", strerror(errno));       exit(0);    }    arg &= (~O_NONBLOCK);    if( fcntl(soc, F_SETFL, arg) < 0) {       fprintf(stderr, "Error fcntl(..., F_SETFL) (%s)\n", strerror(errno));       exit(0);    }    // I hope that is all  } 
like image 24
3 revs, 3 users 97% Avatar answered Oct 28 '22 21:10

3 revs, 3 users 97%


The answers about using select()/poll() are right and code should be written this way to be portable.

However, since you're on Linux, you can do this:

int synRetries = 2; // Send a total of 3 SYN packets => Timeout ~7s
setsockopt(fd, IPPROTO_TCP, TCP_SYNCNT, &synRetries, sizeof(synRetries));

See man 7 tcp and man setsockopt.

I used this to speed up the connect-timeout in a program I needed to patch quickly. Hacking it to timeout via select()/poll() was not an option.

like image 27
schieferstapel Avatar answered Oct 28 '22 22:10

schieferstapel