Mercurial > dovecot > original-hg > dovecot-1.2
changeset 54:71fc142c2d7b HEAD
Last changes broke SSL. Also handshaking is now non-blocking.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 28 Aug 2002 02:16:19 +0300 |
parents | 37a388fe4dab |
children | db8ea2c11ab7 |
files | src/login/ssl-proxy.c |
diffstat | 1 files changed, 53 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/src/login/ssl-proxy.c Wed Aug 28 00:51:00 2002 +0300 +++ b/src/login/ssl-proxy.c Wed Aug 28 02:16:19 2002 +0300 @@ -13,9 +13,12 @@ #include <gnutls/gnutls.h> typedef struct { + int refcount; + GNUTLS_STATE state; int fd_ssl, fd_plain; IO io_ssl, io_plain; + int io_ssl_dir; unsigned char outbuf_plain[1024]; unsigned int outbuf_pos_plain; @@ -41,7 +44,7 @@ static void ssl_input(void *context, int handle, IO io); static void plain_input(void *context, int handle, IO io); -static void ssl_proxy_destroy(SSLProxy *proxy); +static int ssl_proxy_destroy(SSLProxy *proxy); static int proxy_recv_ssl(SSLProxy *proxy, void *data, unsigned int size) { @@ -83,17 +86,22 @@ return -1; } -static void ssl_proxy_destroy(SSLProxy *proxy) +static int ssl_proxy_destroy(SSLProxy *proxy) { + if (--proxy->refcount > 0) + return TRUE; + gnutls_deinit(proxy->state); (void)net_disconnect(proxy->fd_ssl); (void)net_disconnect(proxy->fd_plain); - io_remove(proxy->io_ssl); + if (proxy->io_ssl != NULL) + io_remove(proxy->io_ssl); io_remove(proxy->io_plain); i_free(proxy); + return FALSE; } static void ssl_output(void *context, int fd __attr_unused__, @@ -222,25 +230,52 @@ return state; } +static void ssl_handshake(void *context, int fd __attr_unused__, + IO io __attr_unused__) +{ + SSLProxy *proxy = context; + int ret, dir; + + ret = gnutls_handshake(proxy->state); + if (ret >= 0) { + /* handshake done, now we can start reading */ + if (proxy->io_ssl != NULL) + io_remove(proxy->io_ssl); + + proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ, + ssl_input, proxy); + return; + } + + if (gnutls_error_is_fatal(ret)) { + ssl_proxy_destroy(proxy); + return; + } + + /* i/o interrupted */ + dir = gnutls_handshake_get_direction(proxy->state) == 0 ? + IO_READ : IO_WRITE; + if (proxy->io_ssl_dir != dir) { + if (proxy->io_ssl != NULL) + io_remove(proxy->io_ssl); + proxy->io_ssl = io_add(proxy->fd_ssl, dir, + ssl_handshake, proxy); + proxy->io_ssl_dir = dir; + } +} + int ssl_proxy_new(int fd) { SSLProxy *proxy; GNUTLS_STATE state; - int ret, sfd[2]; + int sfd[2]; - if (ssl_initialized) + if (!ssl_initialized) return -1; state = initialize_state(); gnutls_transport_set_ptr(state, fd); - net_set_nonblock(fd, FALSE); /* FIXME: blocks! */ - if ((ret = gnutls_handshake(state)) < 0) { - gnutls_deinit(state); - return -1; - } - net_set_nonblock(fd, TRUE); - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) == -1) { i_error("socketpair() failed: %m"); gnutls_deinit(state); @@ -248,13 +283,18 @@ } proxy = i_new(SSLProxy, 1); + proxy->refcount = 1; proxy->state = state; proxy->fd_ssl = fd; proxy->fd_plain = sfd[0]; - proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ, ssl_input, proxy); proxy->io_plain = io_add(proxy->fd_plain, IO_READ, plain_input, proxy); + proxy->refcount++; + ssl_handshake(proxy, -1, NULL); + if (!ssl_proxy_destroy(proxy)) + return -1; + return sfd[1]; }