From ThirdMartini

[edit] Introduction

Often times we want to have connect timeout faster then the default socket time out interval. The code below demonstrates one way of doing this. If you find this useful feel free to drop me an e-mail.

[edit] Sample Code

* Copyright (c) 2007, Sebastian Sobolewski
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of ThirdMartini.com nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Sebastian Sobolewski/ThirdMartini.com ``AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

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

/*
 * @brief connect to an address with a user timeout
 * @param fd file descriptor previously opened with "socket()"
 * @param addr the address to connect to
 * @param size sizeof(addr)
 * @param seconds the number of seconds to wait wait on theconnection
 * @returns 0 on success, otherwise -1 and errno set to the correct error
 *          Remember to properly handle EINTR
 */
int connect_with_timeout(int fd, struct sockaddr * addr, unsigned size, unsigned seconds ) 
{ 
   int ret;
   int opt;
   fd_set fdset; 
   struct timeval tv; 
   
   /* Set the socket to nonblocking first */
   opt = fcntl(fd, F_GETFL, NULL); 
   opt |= O_NONBLOCK; 
   fcntl(fd, F_SETFL, opt); 

   for(;;)
   { 
       /* open the connection */
       ret = connect(fd,addr,size); 
       if( ret == 0 )
       {
           /* connection worked */
           break;
       }
       else if( errno != EINPROGRESS )
       {
           /* no connection yet, and errno is not EINPROGRESS
            * this means we have some sort of a connection error
            */
           break;
       }

       opt = 0;
       tv.tv_sec = seconds; 
       tv.tv_usec = 0; 

       FD_ZERO(&fdset); 
       FD_SET(fd, &fdset); 

       /* wait for something to see if the socket becomes
        * writeable ( it will become writable on error as well */
       ret = select(fd+1, NULL, &fdset, NULL, &tv);
       if ( ret == 0) 
       { 
           errno = ETIMEDOUT;
           ret = -1;
           break;
       }
       else if( ret == -1 )
       {
           break;
       }
   }

   /* Set socket back to blocking mode */
   opt = fcntl(fd, F_GETFL, NULL); 
   opt &= (~O_NONBLOCK); 
   fcntl(fd, F_SETFL, opt); 

#if __DEBUG__
   /* debug junk for those that want to see how this works */
   if( ret == 0 )
   {
       printf("Returning Success\n");
   }
   else
   {
       printf("Returning Failure(%d),errno=%d,%s\n",ret,errno,strerror(errno));
   }
#endif

   return ret;
}

[edit] Sample Usage

This code check to see if there is anyone listening to a specific on an address:port
main(argc, argv)
int argc; char **argv;
{
   char hostname[100];
   unsigned port;
   unsigned packet = 0;
   int sd;
   struct sockaddr_in sin;
   struct sockaddr_in pin;
   struct hostent *hp;

   if( argc < 3 )
   {
       printf("Usage: sping <host> <port>\n");
       return -1;
   }

   strcpy(hostname,argv[1]);
   sscanf(argv[2],"%u",&port);

   printf("Startup: %s:%d\n",hostname,port);

   if ((hp = gethostbyname(hostname)) == 0) {
       perror("gethostbyname");
       return -1;
   }

   /* fill in the socket structure with host information */
   memset(&pin, 0, sizeof(pin));
   pin.sin_family = AF_INET;
   pin.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
   pin.sin_port = htons(port);

   printf("Monitoring %s:%d\n",hostname,port);
   while( 1 )
   {
       packet++;
       /* connect to PORT on HOST */
       if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
           printf("socket:errno=%d,s=%s",errno,strerror(errno));
           return -1;
       }

       if (connect_with_timeout(sd,(struct sockaddr *)  &pin, sizeof(pin),5) == -1) {
           //printf("connect:errno=%d,s=%s",errno,strerror(errno));
           printf(" %s:%d --> down (%d)\n",hostname,port,packet);
           if( errno != ETIMEDOUT )
           {
               sleep(5);
           }
       }
       else
       {
           printf(" %s:%d --> up (%d)\n",hostname,port,packet);
           sleep(5);
       }
       close(sd);
   }
   return 0;
}
Personal tools