[socket] connectでのタイムアウト

socketをconnectするときに、相手につながらないとconnectがエラー終了する。このときのエラーコードは、ETIMEOUTだ。perrorでのメッセージは Connection timed outだったり、Operation timed outになる。
先日、non blockingに設定したsocketを使ってconnectするプログラムを書いていた。non blocking なので、connectは完了しなくても抜ける。これをselectで待って接続する、というのが本来やりたいことだった。

テストのための小さいプログラムは以下のように書いた。
細かいところは違っているが、だいたいこんな感じ。

main()
{
    int sock_id;
    struct in_addr inaddr;
    fd_set rfd,wfd;
    struct sockaddr_in dstaddr;
    int value;
    int n;
    int error;
    int len;
    sock_id = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock_id < 0) {
        perror("client socket");
        return;
    }
    value = 1;
    // non blocking socket
    if (ioctl(sock_id, FIONBIO, &value) < 0) {
        perror("client ioctl");
        close (sock_id);
    }
    inaddr.s_addr = htonl(0xc0a80082);
    dstaddr.sin_family      = AF_INET;
    dstaddr.sin_port        = htons(10080);
    dstaddr.sin_addr        = inaddr;
    if ((n = connect(sock_id,  (struct sockaddr *) &dstaddr,
    sizeof(struct sockaddr))) < 0) {
    perror("connect");
    if (errno != EINPROGRESS)
        return;
    }
    if (n == 0)
    {
        printf("done\n");
        return;
    }
    // in progress
    FD_ZERO(&rfd);
    FD_ZERO(&wfd);
    FD_SET(sock_id, &wfd);
    if ((n =select(sock_id + 1, &rfd, &wfd, NULL, NULL)) < 0)
    {
        perror("select");
        return;
    }
    if (FD_ISSET(sock_id, &rfd) || FD_ISSET(sock_id, &wfd))
    {
        len = sizeof(error);
        if (getsockopt(sock_id, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
        {
             printf("getsockopt error");
             return;
        }
    }
    else
    {
        printf("select error");
        return;
    }
    if (error)
    {
        close(sock_id);
        errno = error;
        perror("select return but:");
        return;
    }
}

selectにはタイムアウトを設定していないので、connectの作業が終了するまで抜けてこないだろうと思って書いていたところ、つながらないのに抜けてくることがある。
timeoutのことを忘れていたことに気が付き、selectの後にgetsockoptでerror状態を取得して、エラーのときは接続エラーとして処理するように変更した。
テストプログラムはエラーを検知するだけで終わっているが、実際のコードはエラーは除外して正常状態のsocketで通信を行う。
FreeBSDのプロトコルスタックではconnectのタイムアウトは約75秒だ。
この長さはOSごとに違っている。