반응형
int tcp_connect_timeo(const char *hostname, const char *service,int nsec)
{
struct addrinfo hints, *res, *ressave;
int sock,n;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if( (n=getaddrinfo(hostname,service,&hints,&res)) != 0)
return -1;
ressave = res;
do
{
struct sockaddr_in *ts;
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if(sock < 0)
continue;
ts = (struct sockaddr_in *) res->ai_addr;
if(connect_nonb(sock, (struct sockaddr *)res->ai_addr, res->ai_addrlen,nsec) == 0)
break;
close(sock);
}while( (res=res->ai_next) !=NULL);
if( res == NULL)
return -1;
freeaddrinfo(ressave);
return sock;
}
int connect_nonb(int sockfd, const struct sockaddr *saptr, int salen, int nsec)
{
int flags, n, error;
socklen_t len;
fd_set rset, wset;
struct timeval tval;
flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
error = 0;
if ( (n = connect(sockfd, (struct sockaddr *) saptr, salen)) < 0)
if (errno != EINPROGRESS)
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 = select(sockfd+1, &rset, &wset, NULL,
nsec ? &tval : NULL)) == 0) {
close(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, &error, &len) < 0)
return(-1); /* Solaris pending error */
} else
err_quit("select error: sockfd not set");
done:
fcntl(sockfd, F_SETFL, flags); /* restore file status flags */
if (error) {
close(sockfd); /* just in case */
errno = error;
return(-1);
}
return(0);
}
반응형