summaryrefslogtreecommitdiffstats
path: root/src/ssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssl.c')
-rw-r--r--src/ssl.c73
1 files changed, 61 insertions, 12 deletions
diff --git a/src/ssl.c b/src/ssl.c
index c77d57a..9f9ff0f 100644
--- a/src/ssl.c
+++ b/src/ssl.c
@@ -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);
+}