diff options
Diffstat (limited to 'xpa/timedconn.c')
-rw-r--r-- | xpa/timedconn.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/xpa/timedconn.c b/xpa/timedconn.c new file mode 100644 index 0000000..ff8202f --- /dev/null +++ b/xpa/timedconn.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +#if HAVE_MINGW32==0 + +static int alarm_flag=0; + +#ifdef ANSI_FUNC +static void AlarmFunc (int signo) +#else +static void AlarmFunc (signo) + int signo; +#endif +{ + alarm_flag = 1; +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: alrmconnect + * + * Purpose: connect with alarm-based timeout + * + * Returns: status + * + * adapted from the connect_alarm() code in: + * W. Richard Stevens + * "Advanced Programming in the Unix Environment" + * Addison-Wesley Publishing Co, 1992 + * p. 350 + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int alrmconnect(int sockfd, void *saptr, int salen, int nsec) +#else +int alrmconnect(sockfd, saptr, salen, nsec) + int sockfd; + void *saptr; + int salen; + int nsec; +#endif +{ + int status=0; + struct sigaction act1, oact1; + + /* no error yet */ + alarm_flag = 0; + errno = 0; + + /* set up alarm */ + if( nsec ){ + act1.sa_handler = AlarmFunc; + sigemptyset(&act1.sa_mask); + act1.sa_flags = 0; +#ifdef SA_INTERRUPT + act1.sa_flags |= SA_INTERRUPT; +#endif + if( sigaction(SIGALRM, &act1, &oact1) < 0 ){ + goto done; + } + /* start alarm */ + alarm(nsec); + } + + /* try to connect */ + status=connect(sockfd, (struct sockaddr *)saptr, salen); + + /* turn off alarm if it did not go off */ + if( nsec ) + alarm(0); + +done: + /* check for alarm => we timed out */ + if( alarm_flag ){ + xclose(sockfd); + errno = ETIMEDOUT; + status = -1; + } + + return(status); +} + +#endif + +/* + *---------------------------------------------------------------------------- + * + * Routine: noblkconnect + * + * Purpose: non-blocking connect with select-based timeout + * + * Returns: status + * + * adapted from the connect_nonb() code in: + * W. Richard Stevens + * "Advanced Programming in the Unix Environment" + * Addison-Wesley Publishing Co, 1992 + * p. 411 + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int noblkconnect(int sockfd, void *saptr, int salen, int nsec) +#else +int noblkconnect(sockfd, saptr, salen, nsec) + int sockfd; + void *saptr; + int salen; + int nsec; +#endif +{ + int flags, n, error; + socklen_t len; + fd_set rset, wset; + struct timeval tval; + + /* save state and set in non-blocking mode */ + xfcntl_nonblock(sockfd, flags); + + error = 0; + if( (n = connect(sockfd, (struct sockaddr *) saptr, salen)) < 0){ + if((xerrno != EINPROGRESS) && (xerrno != EWOULDBLOCK)) + return(-1); + } + + /* Do whatever we want while the connect is taking place. */ + if(n == 0) + goto done; /* connect completed immediately */ + + FD_ZERO(&rset); + FD_SET(sockfd, &rset); + wset = rset; + tval.tv_sec = nsec; + tval.tv_usec = 0; + + if( (n = xselect(sockfd+1, &rset, &wset, NULL, + nsec ? &tval : NULL)) == 0) { + xclose(sockfd); /* timeout */ + errno = ETIMEDOUT; + return(-1); + } + + if(FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) { + len = sizeof(error); + if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&error, &len) <0) + return(-1); /* Solaris pending error */ + } else{ + errno = ETIMEDOUT; + } + +done: + xfcntl_restore(sockfd, flags); /* restore file status flags */ + + if(error) { + xclose(sockfd); /* just in case */ + errno = error; + return(-1); + } + return(0); +} + +#ifdef DO_MAIN +/* + * solaris: gcc -o atest atest.c -lsocket -lnsl + * linux: gcc -o atest atest.c + * os x: gcc -o atest atest.c + */ +#include <stdio.h> + +extern char *optarg; +extern int optind; + +int main(int argc, char **argv) +{ + int c; + int args; + int status; + int fd; + int doalarm=0; + int nsec=2; + unsigned int ip; + char *sip; + struct sockaddr_in sock_in; + + /* process switch arguments */ + while ((c = getopt(argc, argv, "ab")) != -1){ + switch(c){ + case 'a': + doalarm = 1; + break; + case 'b': + doalarm = 0; + break; + } + } + + args = argc - optind; + if( args > 0 ) + sip = argv[optind]; + /* this ip is bogus and normally will cause connect to hang */ + else + sip ="209.1.1.1"; + + /* set up socket to a bogus ip and port */ + if( (int)(ip = inet_addr(sip)) == -1 ){ + perror("inet_addr"); + exit(1); + } + if( (fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ + perror("socket"); + exit(1); + } + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = ip; + sock_in.sin_port = htons(80); + + if( doalarm ){ + fprintf(stderr, "alarm-based connect() ...\n"); + status=alrmconnect(fd, (void *)&sock_in, sizeof(sock_in), nsec); + } + else{ + fprintf(stderr, "non-blocking connect() ...\n"); + status=noblkconnect(fd, (void *)&sock_in, sizeof(sock_in), nsec); + } + + /* if alarm_flag is 1, alarm went off and interrupted connect */ + fprintf(stderr, "alarm_flag=%d status=%d\n", alarm_flag, status); + if( status != 0 ) + perror("connect"); +} + +#endif |