--- 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 <assert.h>
/**
- * 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);
}