Re: maximum timeout on socket connection

From: Sean Burke (foobar_at_mystery.org)
Date: 03/22/04


Date: Mon, 22 Mar 2004 05:46:43 GMT


JoJoTwilligo@hotmail.com (Jo) writes:

> Sean Burke <foobar@mystery.org> wrote in message news:<x7ptb9eubz.fsf@bolo.xenadyne.com>...
> > "Marc Rochkind" <rochkind@basepath.com> writes:
> >
> > > --
> > > Marc Rochkind
> > > "Advanced UNIX Programming" (publishing April 2004)
> > > www.basepath.com/aup
> > >
> > > "Jo" <JoJoTwilligo@hotmail.com> wrote in message
> > > news:72ce7f0c.0403181136.3def0332@posting.google.com...
> > > > A few weeks ago I posted a question about setting a maximum timeout on
> > > > the connect() function. I also wanted to avoid the complexity of
> > > > making the function non-blocking, and working with select(). The
> > > > conclusion was unclear, but it seemed the best method was to set an
> > > > alarm. For some reason this didn't work at all--the alarm seemed to
> > > > have no affect. Here's my code:
> > > >
> > > > int connectex(int sockfd, const struct sockaddr *serv_addr, socklen_t
> > > > addrlen, long maxTimeOut) {
> > > > sig_t oldhandler;
> > > > if (maxTimeOut != -1) {
> > > > oldhandler = signal(SIGALRM, SIG_IGN);
> > > > alarm(maxTimeOut);
> > > > }
> > > > int returned = connect(sockfd, serv_addr, addrlen);
> > > > if (maxTimeOut != -1) {
> > > > alarm(0);
> > > > signal(SIGALRM, oldhandler);
> > > > }
> > > >
> > > > return returned;
> > > > }
> > > >
> > > > I was told to set SIGALRM to SIG_IGN. Presumably, this would not
> > > > prevent the alarm from affecting connect(). In fact, the tests I did
> > > > with and without the signal() call were just the same.
> > > > I do have a signal handler, but it is only handles SIGSEGV.
>
> [snip]
>
> >
> > I would suggest that you question your assumption that
> > using signals is the easist way to do it. You may find
> > that using select() is not nearly as complicated as you
> > expect.
>
> I'm not quite sure what question to ask. Can you tell me how I
> might use the select in a simple way, such that it would set a maximum
> timeout on the connect()? I'd prefer it not interfere with the other
> operations on the socket.

Something similar to this should do it.
Note that I haven't actually compiled it.

-SEan

#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <string.h>

#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>

/*
 * Connect a socket.
 *
 * returns zero on success, ETIME on timeout, errno on connect failure.
 */
int connectex(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen, long maxTimeOut)
{
   /* Make socket nonblocking.
    */
   socket_set_nonblocking(sockfd, true);

   /* Connect the socket.
    */
    if (connect(sockfd, serv_addr, addr_len)) < 0)
    {
        if (errno == EINPROGRESS)
        {
            fd_set fds;
            int numfds = 0;
            struct timeval timeout;
            int r, error;

            /* Clear the fd_set.
             */
            FD_ZERO(&fds);
            FD_SET(sockfd, &fds);
            numfds = sockfd + 1;

            timeout.tv_sec = maxTimeOut;
            timeout.tv_usec= 0;

            switch (r = select(numfds, NULL, &fds, NULL, &timeout))
            {
            case -1:
                perror("select failed");
                return errno;

            case 0:
                /* select timed out.
                 */
                close(sockfd);
                return ETIME;

            case 1:
                if ((error = socket_get_error(sockfd)) == 0)
                {
                    /* Connect succeeded asynchronously.
                     */
                    socket_set_nonblocking(sockfd, false);
                    return 0;
                }
                else
                {
                    fprintf(stderr, "connect(%d) failed with error %d - %s",
                            sockfd, error, strerror(error));
                    return error;
                }
            }
        }
        else
        {
            fprintf(stderr, "connect(%d) failed with error %d - %s",
                    sockfd, errno, strerror(errno));
            return errno;
        }
    }
    else
    {
        /* Connect succeeded immediately.
         */
        return 0;
    }
}

static int
socket_set_nonblocking(int sock, bool mode)
{
    int flags = fcntl(sock, F_GETFL, 0);
    if (flags == -1)
        return errno;
    else if ( mode && !(flags & O_NONBLOCK))
        flags |= O_NONBLOCK;
    else if (!mode && (flags & O_NONBLOCK))
        flags ^= O_NONBLOCK;
    else
        return OK; /* blocking mode is already good. */

    if (fcntl(sock, F_SETFL, flags) < 0)
    {
        fprintf(stderr, "fcntl failed: errno %d - %s", errno, safe_strerror(errno));
        return errno;
    }

    return 0;
}

static int
socket_get_error(int sock)
{
    int error;
    int len = sizeof(error);

    if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) == 0)
    {
        return error;
    }
    else
    {
        fprintf(stderr, "getsockopt(%d) failed with errno %d - %s", sock, errno, strerror(errno));
        return errno;
    }
}



Relevant Pages

  • [PATCH] Delete superfluous source file "net/wanrouter/af_wanpipe.c".
    ... 2000 Nenad Corbic o Fixed the corrupt sock lcn problem. ... -/* SECURE SOCKET IMPLEMENTATION ... * routine in the wanpipe driver. ... -static void * dbg_kmalloc(unsigned int size, int prio, int line) { ...
    (Linux-Kernel)
  • [PATCH 1/6] x25: Allow 32 bit socket ioctl in 64 bit kernel
    ... The following patch provides 32 bit userland ioctl support for modular ... socket ioctls in a 64 bit kernel. ... SOCKCALL_WRAP(name, ioctl, (struct socket *sock, unsigned int cmd, \ ... SOCKCALL_WRAP(name, listen, (struct socket *sock, int len), (sock, ...
    (Linux-Kernel)
  • Re: freeing port - winsock
    ... When I create and destroy many sockets without specifying the local port to bind, It seems that this local port is not free after using the function closesocket. ... It's goal is to create a socket, connect to a remote server on port 80, close the socket and to loop on these actions. ... int host ... SOCKET sock = INVALID_SOCKET; ...
    (comp.programming)
  • select() returns and indicates writability before a non-blocking TCP socket has actually connect
    ... selectwill return if either the connection is made (server starts up ... and begins accepting connections) or the timeout expires. ... the socket is closed and a new socket along with a new call to ... int connectRC; ...
    (comp.os.linux.networking)
  • select() indicates writability before a non-blocking TCP socket has actually connected
    ... selectwill return if either the connection is made (server starts up ... and begins accepting connections) or the timeout expires. ... the socket is closed and a new socket along with a new call to ... int connectRC; ...
    (comp.os.linux.development.apps)