9c918a797291419d4c83699c997d72df815941eb galt Tue May 31 21:07:33 2011 -0700 https:adding ability to wait on sockets of both sides of the conversation, in particular this enables using PUT to upload a large file e.g. Amazon Storage diff --git src/lib/https.c src/lib/https.c index c641bd2..1eeb45a 100644 --- src/lib/https.c +++ src/lib/https.c @@ -1,189 +1,231 @@ /* Connect via https. */ #ifdef USE_SSL #include "openssl/ssl.h" #include "openssl/err.h" #include #include #include "common.h" #include "errabort.h" int netConnectHttps(char *hostName, int port) /* Return socket for https connection with server or -1 if error. */ { fflush(stdin); fflush(stdout); fflush(stderr); int sv[2]; /* the pair of socket descriptors */ socketpair(AF_UNIX, SOCK_STREAM, 0, sv); int pid = fork(); if (pid < 0) errnoAbort("can't fork in netConnectHttps"); if (pid == 0) { /* child */ fclose(stdin); fclose(stdout); close(sv[0]); /* close unused half of pipe */ /* close other file descriptors */ int fd=0; for (fd = STDERR_FILENO+1; fd < 64; fd++) if (fd != sv[1]) close(fd); char hostnameProto[256]; BIO *sbio; int len; SSL_CTX *ctx; SSL *ssl; SSL_library_init(); ERR_load_crypto_strings(); ERR_load_SSL_strings(); OpenSSL_add_all_algorithms(); /* We would seed the PRNG here if the platform didn't * do it automatically */ ctx = SSL_CTX_new(SSLv23_client_method()); /* future extension: checking certificates char *certFile = NULL; char *certPath = NULL; if (certFile || certPath) { SSL_CTX_load_verify_locations(ctx,certFile,certPath); #if (OPENSSL_VERSION_NUMBER < 0x0090600fL) SSL_CTX_set_verify_depth(ctx,1); #endif } */ /* We'd normally set some stuff like the verify paths and * mode here because as things stand this will connect to * any server whose certificate is signed by any CA. */ sbio = BIO_new_ssl_connect(ctx); BIO_get_ssl(sbio, &ssl); if(!ssl) { errAbort("Can't locate SSL pointer\n"); return -1; } /* Don't want any retries */ SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); /* We might want to do other things with ssl here */ snprintf(hostnameProto,sizeof(hostnameProto),"%s:https",hostName); BIO_set_conn_hostname(sbio, hostnameProto); BIO_set_conn_int_port(sbio, &port); if(BIO_do_connect(sbio) <= 0) { ERR_print_errors_fp(stderr); errAbort("Error connecting to server\n"); return -1; } if(BIO_do_handshake(sbio) <= 0) { ERR_print_errors_fp(stderr); errAbort("Error establishing SSL connection\n"); return -1; } /* future extension: checking certificates if (certFile || certPath) if (!check_cert(ssl, host)) return -1; */ /* Could examine ssl here to get connection info */ + /* we need to wait on both the user's socket and the BIO SSL socket + * to see if we need to ferry data from one to the other */ + + /* Get underlying file descriptor, needed for select call */ + fd = BIO_get_fd(sbio, NULL); + if (fd == -1) + { + errAbort("BIO doesn't seem to be initialized in https, unable to get descriptor."); + return(-1); + } + + fd_set readfds; + fd_set writefds; + boolean done; + int err; + + char buf[32768]; + done = FALSE; + while (!done) + { + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_SET(fd, &readfds); + FD_SET(sv[1], &readfds); + + err = select(max(fd,sv[1]) + 1, &readfds, &writefds, NULL, NULL); + + /* Evaluate select() return code */ + if (err < 0) + { + errAbort("error during select()"); + return(-1); + } + if (err == 0) + { + return(-1); /* Timeout (not currently in use) */ + } + + if (FD_ISSET(sv[1], &readfds)) + { int rd = 0; - while((rd = read(sv[1], buf, 32768)) > 0) + rd = read(sv[1], buf, 32768); + if (rd == -1) + errnoAbort("error reading https socket"); + if (rd > 0) { if(BIO_write(sbio, buf, rd) <= 0) { ERR_print_errors_fp(stderr); errAbort("Error writing SSL connection\n"); return -1; } - - // TODO may someday need to readywait on both connections - break; // for now, just get input once and move on - } - if (rd == -1) - errnoAbort("error reading https socket"); + else + break; + } - for(;;) + if (FD_ISSET(fd, &readfds)) { len = BIO_read(sbio, buf, 32768); if(len < 0) { ERR_print_errors_fp(stderr); errAbort("Error reading SSL connection\n"); return -1; } if(len == 0) break; int wt = write(sv[1], buf, len); if (wt == -1) errnoAbort("error writing https socket"); } + } BIO_free_all(sbio); close(sv[1]); /* we are done with it */ exit(0); /* child will never get to here */ } /* parent */ close(sv[1]); /* close unused half of socket */ return sv[0]; } #else #include #include "common.h" #include "errabort.h" int netConnectHttps(char *hostName, int port) /* Start https connection with server or die. */ { errAbort("No openssl available in netConnectHttps for %s : %d", hostName, port); return -1; /* will never get to here, make compiler happy */ } #endif