diff -r f4472119de3b -r c59d3eaff0fb src/sock_gnutls.c --- a/src/sock_gnutls.c Tue Apr 28 17:52:48 2009 +0300 +++ b/src/sock_gnutls.c Tue Apr 28 20:27:45 2009 +0300 @@ -13,23 +13,24 @@ #include /** - * Register for events based on the session's gnutls_record_get_direction(). + * Enable the TCP events based on the session's gnutls_record_get_direction(). */ -static err_t sock_gnutls_ev_enable (struct sock_gnutls *sock, struct error_info *err) +static err_t sock_gnutls_ev_enable (struct sock_gnutls *sock, error_t *err) { int ret; + short mask; // gnutls_record_get_direction tells us what I/O operation gnutls would have required for the last // operation, so we can use that to determine what events to register switch ((ret = gnutls_record_get_direction(sock->session))) { case 0: // read more data - sock_fd_enable_events(SOCK_GNUTLS_FD(sock), EV_READ); + mask = EV_READ; break; case 1: // write buffer full - sock_fd_enable_events(SOCK_GNUTLS_FD(sock), EV_WRITE); + mask = EV_WRITE; break; default: @@ -37,7 +38,11 @@ RETURN_SET_ERROR_EXTRA(err, ERR_GNUTLS_RECORD_GET_DIRECTION, ret); } - // ok... wait + // do the enabling + if ((ERROR_CODE(err) = transport_fd_enable(SOCK_GNUTLS_FD(sock), EV_READ))) + return ERROR_CODE(err); + + return SUCCESS; } @@ -72,7 +77,7 @@ * * Based on the GnuTLS examples/ex-rfc2818.c */ -static err_t sock_gnutls_verify (struct sock_gnutls *sock, struct error_info *err) +static err_t sock_gnutls_verify (struct sock_gnutls *sock, error_t *err) { unsigned int status; const gnutls_datum_t *cert_list; @@ -138,7 +143,7 @@ * * @return >0 for finished handshake, 0 for handshake-in-progress, -err_t for errors. */ -static int sock_gnutls_handshake (struct sock_gnutls *sock, struct error_info *err) +static int sock_gnutls_handshake (struct sock_gnutls *sock, error_t *err) { int ret; @@ -177,60 +182,61 @@ } /** - * Our SOCK_STREAM event handler. Drive the handshake if that's current, otherwise, invoke user callbacks. - * - * XXX: this is ugly. This sock_stream-level separation doesn't really work that well. + * Our transport_fd event handler. Drive the handshake if that's current, otherwise, invoke user callbacks. */ -static void sock_gnutls_event_handler (int fd, short what, void *arg) +static void sock_gnutls_on_event (struct transport_fd *fd, short what, void *arg) { struct sock_gnutls *sock = arg; - struct error_info err; + error_t err; (void) fd; + + // XXX: timeouts (void) what; // are we in the handshake cycle? if (sock->handshake) { RESET_ERROR(&err); + // perform the next handshake step if (sock_gnutls_handshake(sock, &err) == 0) { - // wait for the next handshake step + // handshake continues - } else if (SOCK_GNUTLS_BASE(sock)->conn_cb_func) { + } else if (SOCK_GNUTLS_TRANSPORT(sock)->connected) { // the async connect process has now completed, either succesfully or with an error // invoke the user connect callback directly with appropriate error - sock_stream_invoke_conn_cb(SOCK_GNUTLS_BASE(sock), ERROR_CODE(&err) ? &err : NULL, true); + transport_connected(SOCK_GNUTLS_TRANSPORT(sock), ERROR_CODE(&err) ? &err : NULL, true); } else { - // re-handshake completed, so continue with the sock_stream_callbacks, so the user can call sock_gnutls_read/write - if (ERROR_CODE(&err)) - // XXX: bad, since we can't report this directly... we need to let the user call _read/write, and get - // the error from there - log_warn_err(&err, "sock_gnutls_handshake failed"); - - // continue where we left off - sock_stream_invoke_callbacks(SOCK_GNUTLS_BASE(sock), sock->ev_mask); + // the re-handshake failed, so this transport is dead + transport_error(SOCK_GNUTLS_TRANSPORT(sock), &err); + + else + // re-handshake completed, so continue with the transport_callbacks + transport_fd_invoke(SOCK_GNUTLS_FD(sock), what); } } else { // normal sock_stream operation - // gnutls might be able to proceed now, so ask user to try what didn't work before now, using the mask given to - // event_enable(). - sock_stream_invoke_callbacks(SOCK_GNUTLS_BASE(sock), sock->ev_mask); + // gnutls might be able to proceed now, so invoke user callbacks + transport_fd_invoke(SOCK_GNUTLS_FD(sock), what); } } -static err_t sock_gnutls_read (struct sock_stream *base_sock, void *buf, size_t *len, struct error_info *err) +static err_t sock_gnutls_read (transport_t *transport, void *buf, size_t *len, error_t *err) { - struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); + struct sock_gnutls *sock = transport_check(transport, &sock_gnutls_type); int ret; // read gnutls record - ret = gnutls_record_recv(sock->session, buf, *len); + do { + ret = gnutls_record_recv(sock->session, buf, *len); + + } while (ret == GNUTLS_E_INTERRUPTED); // errors - // XXX: E_INTERRUPTED, E_REHANDSHAKE? + // XXX: E_REHANDSHAKE? if (ret < 0 && ret != GNUTLS_E_AGAIN) RETURN_SET_ERROR_EXTRA(err, ERR_GNUTLS_RECORD_RECV, ret); @@ -238,7 +244,7 @@ return SET_ERROR(err, ERR_READ_EOF); - // eagain? + // EAGAIN? if (ret < 0) { *len = 0; @@ -251,14 +257,17 @@ return SUCCESS; } -static err_t sock_gnutls_write (struct sock_stream *base_sock, const void *buf, size_t *len, struct error_info *err) +static err_t sock_gnutls_write (transport_t *transport, const void *buf, size_t *len, error_t *err) { - struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); + struct sock_gnutls *sock = transport_check(transport, &sock_gnutls_type); int ret; // read gnutls record - ret = gnutls_record_send(sock->session, buf, *len); - + do { + ret = gnutls_record_send(sock->session, buf, *len); + + } while (ret == GNUTLS_E_INTERRUPTED); + // errors if (ret < 0 && ret != GNUTLS_E_AGAIN) RETURN_SET_ERROR_EXTRA(err, ERR_GNUTLS_RECORD_RECV, ret); @@ -279,43 +288,21 @@ return SUCCESS; } -static err_t sock_gnutls_event_init (struct sock_stream *base_sock) -{ - struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); - - (void) sock; - - // already setup, ok - return SUCCESS; -} - -static err_t sock_gnutls_event_enable (struct sock_stream *base_sock, short mask) +static void _sock_gnutls_destroy (transport_t *transport) { - struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); - - // store the ev_mask. We don't care about it here, because we assume that event_enable is only called once read or - // write, respectively, return zero. This is really the only case we can handle with gnutls. - sock->ev_mask = mask; + struct sock_gnutls *sock = transport_check(transport, &sock_gnutls_type); - // then wait for the event - return sock_gnutls_ev_enable(sock, SOCK_GNUTLS_ERR(sock)); -} - -static void sock_gnutls_release (struct sock_stream *base_sock) -{ - struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); - - // DIEEEE + // die sock_gnutls_destroy(sock); } /** * Our sock_tcp-invoked connect handler */ -static void sock_gnutls_on_connect (struct sock_stream *base_sock, struct error_info *tcp_err) +static void sock_gnutls__connected (transport_t *transport, const error_t *tcp_err) { - struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); - struct error_info err; + struct sock_gnutls *sock = transport_check(transport, &sock_gnutls_type); + error_t err; // trap errors to let the user handle them directly if (tcp_err) @@ -325,7 +312,7 @@ gnutls_transport_set_ptr(sock->session, (gnutls_transport_ptr_t) (long int) SOCK_GNUTLS_FD(sock)->fd); // add ourselves as the event handler - if ((ERROR_CODE(&err) = sock_fd_init_ev(SOCK_GNUTLS_FD(sock), &sock_gnutls_event_handler, sock))) + if ((ERROR_CODE(&err) = transport_fd_setup(SOCK_GNUTLS_FD(sock), sock_gnutls_on_event, sock))) goto error; // start handshake @@ -338,20 +325,15 @@ error: // tell the user - SOCK_GNUTLS_BASE(sock)->conn_cb_func(SOCK_GNUTLS_BASE(sock), &err, SOCK_GNUTLS_BASE(sock)->conn_cb_arg); + transport_connected(transport, &err, true); } -/* - * Our sock_stream_Type - */ -struct sock_stream_type sock_gnutls_type = { +struct transport_type sock_gnutls_type = { .methods = { - .read = &sock_gnutls_read, - .write = &sock_gnutls_write, - .event_init = &sock_gnutls_event_init, - .event_enable = &sock_gnutls_event_enable, - .release = &sock_gnutls_release, - ._conn_cb = &sock_gnutls_on_connect, + .read = sock_gnutls_read, + .write = sock_gnutls_write, + .destroy = _sock_gnutls_destroy, + ._connected = sock_gnutls__connected, }, }; @@ -366,7 +348,7 @@ printf("gnutls: %d: %s", level, msg); } -err_t sock_gnutls_global_init (struct error_info *err) +err_t sock_gnutls_global_init (error_t *err) { // global init if ((ERROR_EXTRA(err) = gnutls_global_init()) < 0) @@ -395,7 +377,7 @@ err_t sock_ssl_client_cred_create (struct sock_ssl_client_cred **ctx_cred, const char *cafile_path, bool verify, const char *cert_path, const char *pkey_path, - struct error_info *err + error_t *err ) { struct sock_ssl_client_cred *cred; @@ -453,11 +435,10 @@ sock_ssl_client_cred_destroy(cred); } -err_t sock_ssl_connect_async (struct sock_stream **sock_ptr, +err_t sock_ssl_connect (const struct transport_info *info, transport_t **transport_ptr, const char *hostname, const char *service, struct sock_ssl_client_cred *cred, - sock_stream_connect_cb cb_func, void *cb_arg, - struct error_info *err + error_t *err ) { struct sock_gnutls *sock = NULL; @@ -467,7 +448,7 @@ return SET_ERROR(err, ERR_CALLOC); // initialize base - sock_stream_init(SOCK_GNUTLS_BASE(sock), &sock_gnutls_type, cb_func, cb_arg); + transport_init(SOCK_GNUTLS_TRANSPORT(sock), &sock_gnutls_type, info); if (!cred) { // default credentials @@ -487,6 +468,9 @@ if ((sock->hostname = strdup(hostname)) == NULL) JUMP_SET_ERROR(err, ERR_STRDUP); + // initialize TCP + sock_tcp_init(SOCK_GNUTLS_TCP(sock)); + // initialize client session if ((ERROR_EXTRA(err) = gnutls_init(&sock->session, GNUTLS_CLIENT)) < 0) JUMP_SET_ERROR(err, ERR_GNUTLS_INIT); @@ -503,11 +487,11 @@ JUMP_SET_ERROR(err, ERR_GNUTLS_CRED_SET); // TCP connect - if (sock_tcp_connect_async_begin(SOCK_GNUTLS_TCP(sock), hostname, service, err)) + if (sock_tcp_connect_async(SOCK_GNUTLS_TCP(sock), hostname, service, err)) goto error; // done, wait for the connect to complete - *sock_ptr = SOCK_GNUTLS_BASE(sock); + *transport_ptr = SOCK_GNUTLS_TRANSPORT(sock); return SUCCESS; @@ -520,18 +504,17 @@ void sock_gnutls_destroy (struct sock_gnutls *sock) { - // terminate the TCP transport - sock_fd_close(SOCK_GNUTLS_FD(sock)); - // close the session rudely gnutls_deinit(sock->session); - + + // terminate the TCP transport + sock_tcp_destroy(SOCK_GNUTLS_TCP(sock)); + if (sock->cred) // drop the cred ref sock_ssl_client_cred_put(sock->cred); // free free(sock->hostname); - free(sock); }