diff options
Diffstat (limited to 'src/ssl.c')
-rw-r--r-- | src/ssl.c | 73 |
1 files changed, 61 insertions, 12 deletions
@@ -340,6 +340,7 @@ int ast_connect(struct mansession *a) { return -1; if (a->server->use_ssl) { + debugmsg("initiating ssl connection"); if ((s=sec_getslot())!=-1) { /* find a slot for the ssl handle */ sec_channel[s].fd = fd; /* remember the real fd */ @@ -360,6 +361,7 @@ int ast_connect(struct mansession *a) { } } + debugmsg("returning ast_connect with %d", fd); pthread_mutex_lock(&a->lock); a->fd = fd; pthread_mutex_unlock(&a->lock); @@ -369,22 +371,69 @@ int ast_connect(struct mansession *a) { int connect_nonb(struct mansession *a) { - int s, flags, one=1; + int flags, n, error; + socklen_t len; + fd_set rset, wset; + struct timeval tval; + int nsec = 1, sockfd; + + sockfd = get_real_fd(a->fd); + + flags = fcntl(sockfd, F_GETFL, 0); + fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + + error = 0; + if ( (n = connect(sockfd, (struct sockaddr *) &a->sin, sizeof(a->sin)) ) < 0 ) { + /* TODO: This seems like the nine pound hammer to me... */ + /* perhaps something a bit more elegant; errno seems to change too */ + if (errno == EISCONN || errno == 103 || errno==111) { + debugmsg("connect_nonb: error %d, closing old fd and grabbing a new one...", errno); + /* looks like our old socket died, let's round up a new one and try again */ + close_sock(a->fd); + pthread_mutex_lock(&a->lock); + a->fd = socket(AF_INET, SOCK_STREAM, 0); + pthread_mutex_unlock(&a->lock); + return(-1); + } + if (errno != EINPROGRESS) + return(-1); + } - s = get_real_fd(a->fd); + /* Do whatever we want while the connect is taking place. */ -/* flags = fcntl(s, F_GETFL, 0); - fcntl(s, F_SETFL, flags | O_NONBLOCK); */ + if (n == 0) + goto done; /* connect completed immediately */ - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one))==-1) { - (void)close(s); - return -1; + 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);*/ /* we want to retry */ + errno = ETIMEDOUT; + return(-1); } - if (connect(s, (struct sockaddr *) &a->sin, sizeof(a->sin)) < 0) { - if (errno != EINPROGRESS) - 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");*/ + logmsg("select error: sockfd not set"); + return(-1); } - return s; -} +done: + fcntl(sockfd, F_SETFL, flags); /* restore file status flags */ + + if (error) { + /* close(sockfd); */ /* disable for now, we want to retry... */ + errno = error; + return(-1); + } + return(sockfd); +} |