diff --git a/GNUmakefile b/GNUmakefile index 0496325..1864a44 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -9,7 +9,7 @@ MV := mv RANLIB := ranlib CFLAGS += -pipe -Wall USE_PCH ?= YES -USE_SSL ?= NO +USE_SSL ?= YES USE_BIGENDIAN ?= AUTO BITS ?= AUTO SILENT ?= YES diff --git a/src/core/hubio.c b/src/core/hubio.c index ef65d88..14ea99d 100644 --- a/src/core/hubio.c +++ b/src/core/hubio.c @@ -178,7 +178,7 @@ int hub_sendq_send(struct hub_sendq* q, hub_recvq_write w, void* data) if (ret > 0) { #ifdef SSL_SUPPORT - q->last_write_n = ret; + q->last_send = ret; #endif /* Remove messages sent */ diff --git a/src/core/netevent.c b/src/core/netevent.c index 44cd5ca..a85d6a4 100644 --- a/src/core/netevent.c +++ b/src/core/netevent.c @@ -75,7 +75,7 @@ int net_user_send(void* ptr, const void* buf, size_t len) return ret; } -#ifdef SSL_SUPPORT +#if 0 int net_user_send_ssl(void* ptr, const void* buf, size_t len) { struct hub_user* user = (struct hub_user*) ptr; @@ -114,8 +114,7 @@ int net_user_recv(void* ptr, void* buf, size_t len) return ret; } - -#ifdef SSL_SUPPORT +#if 0 int net_user_recv_ssl(void* ptr, void* buf, size_t len) { struct hub_user* user = (struct hub_user*) ptr; diff --git a/src/network/connection.c b/src/network/connection.c index 9ae8f75..858e2e8 100644 --- a/src/network/connection.c +++ b/src/network/connection.c @@ -21,12 +21,85 @@ extern struct hub_info* g_hub; +#ifdef SSL_SUPPORT +static ssize_t net_con_ssl_accept(struct net_connection* con); +static ssize_t net_con_ssl_connect(struct net_connection* con); +#endif + +static inline int net_con_flag_get(struct net_connection* con, unsigned int flag) +{ + return con->flags & flag; +} + +static inline void net_con_flag_set(struct net_connection* con, unsigned int flag) +{ + con->flags |= flag; +} + +static inline void net_con_flag_unset(struct net_connection* con, unsigned int flag) +{ + con->flags &= ~flag; +} + +static void net_con_event(int fd, short ev, void *arg) +{ + struct net_connection* con = (struct net_connection*) arg; +#ifdef SSL_SUPPORT + if (!con->ssl) + { +#endif + net_event(fd, ev, con->ptr); +#ifdef SSL_SUPPORT + } + else + { + if (ev & (EV_READ | EV_WRITE)) + { + if (net_con_flag_get(con, NET_WANT_SSL_ACCEPT)) + { + net_con_ssl_accept(con); + } + else if (net_con_flag_get(con, NET_WANT_SSL_CONNECT)) + { + net_con_ssl_connect(con); + } + else if (ev == EV_READ && net_con_flag_get(con, NET_WANT_SSL_READ)) + { + net_event(fd, EV_WRITE, con->ptr); + } + else if (ev == EV_WRITE && net_con_flag_get(con, NET_WANT_SSL_WRITE)) + { + net_event(fd, ev & EV_READ, con->ptr); + } + else + { + net_event(fd, ev, con->ptr); + } + } + else + { + net_event(fd, ev, con->ptr); + } + } +#endif +} + void net_con_initialize(struct net_connection* con, int sd, const void* ptr, int events) { con->sd = sd; con->ptr = (void*) ptr; + con->last_send = time(0); + con->last_recv = con->last_send; - event_set(&con->event, con->sd, events | EV_PERSIST, net_event, con->ptr); +#ifdef SSL_SUPPORT + con->ssl = NULL; + con->write_len = 0; +#endif + + if (events & EV_READ) net_con_flag_set(con, NET_WANT_READ); + if (events & EV_WRITE) net_con_flag_set(con, NET_WANT_WRITE); + + event_set(&con->event, con->sd, events | EV_PERSIST, net_con_event, con); event_base_set(g_hub->evbase, &con->event); event_add(&con->event, 0); } @@ -36,8 +109,11 @@ void net_con_update(struct net_connection* con, int events) if (event_pending(&con->event, EV_READ | EV_WRITE, 0) == events) return; + if (events & EV_READ) net_con_flag_set(con, NET_WANT_READ); + if (events & EV_WRITE) net_con_flag_set(con, NET_WANT_WRITE); + event_del(&con->event); - event_set(&con->event, con->sd, events | EV_PERSIST, net_event, con->ptr); + event_set(&con->event, con->sd, events | EV_PERSIST, net_con_event, con); event_add(&con->event, 0); } @@ -50,3 +126,159 @@ void net_con_close(struct net_connection* con) con->sd = -1; } +#ifdef SSL_SUPPORT +static int handle_openssl_error(struct net_connection* con, int ret) +{ + int error = SSL_get_error(con->ssl, ret); + switch (error) + { + case SSL_ERROR_ZERO_RETURN: + return ret; + + case SSL_ERROR_WANT_READ: + net_con_update(con, EV_READ); + net_con_flag_set(con, NET_WANT_SSL_READ); + return 0; + + case SSL_ERROR_WANT_WRITE: + net_con_update(con, EV_READ | EV_WRITE); + net_con_flag_set(con, NET_WANT_SSL_WRITE); + return 0; + + case SSL_ERROR_WANT_CONNECT: + net_con_update(con, EV_READ | EV_WRITE); + net_con_flag_set(con, NET_WANT_SSL_CONNECT); + return 0; + + case SSL_ERROR_WANT_ACCEPT: + net_con_update(con, EV_READ | EV_WRITE); + net_con_flag_set(con, NET_WANT_SSL_ACCEPT); + return 0; + + case SSL_ERROR_WANT_X509_LOOKUP: + return 0; + + case SSL_ERROR_SYSCALL: + /* if ret == 0, connection closed, if ret == -1, check with errno */ + return -1; + + case SSL_ERROR_SSL: + /* internal openssl error */ + return -1; + } + + return -1; +} +#endif + + +ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len) +{ +#ifdef SSL_SUPPORT + if (!con->ssl) + { +#endif + int ret = net_send(con->sd, buf, len, UHUB_SEND_SIGNAL); + if (ret > 0) + { + con->last_send = time(0); + } + else if (ret == -1 && (net_error() == EWOULDBLOCK || net_error() == EINTR)) + { + return 0; + } + else + { + return -1; + } + return ret; +#ifdef SSL_SUPPORT + } + else + { + int ret = SSL_write(con->ssl, buf, len); + if (ret > 0) + { + con->last_send = time(0); + net_con_flag_unset(con, NET_WANT_SSL_READ); + } + else + { + return handle_openssl_error(con, ret); + } + return ret; + } +#endif + + +} + +ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len) +{ +#ifdef SSL_SUPPORT + if (!con->ssl) + { +#endif + int ret = net_recv(con->sd, buf, len, 0); + if (ret > 0) + { + con->last_recv = time(0); + } + else if (ret == -1 && (net_error() == EWOULDBLOCK || net_error() == EINTR)) + { + return 0; + } + else + { + return -1; + } + return ret; +#ifdef SSL_SUPPORT + } + else + { + int ret = SSL_read(con->ssl, buf, len); + if (ret > 0) + { + con->last_recv = time(0); + net_con_flag_unset(con, NET_WANT_SSL_WRITE); + } + else + { + return handle_openssl_error(con, ret); + } + return ret; + } +#endif +} + +#ifdef SSL_SUPPORT +static ssize_t net_con_ssl_accept(struct net_connection* con) +{ + ssize_t ret = SSL_accept(con->ssl); + if (ret > 0) + { + net_con_flag_unset(con, NET_WANT_SSL_ACCEPT); + } + else + { + return handle_openssl_error(con, ret); + } + return ret; +} + +static ssize_t net_con_ssl_connect(struct net_connection* con) +{ + ssize_t ret = SSL_connect(con->ssl); + if (ret > 0) + { + net_con_flag_unset(con, NET_WANT_SSL_CONNECT); + } + else + { + return handle_openssl_error(con, ret); + } + return ret; +} +#endif + diff --git a/src/network/connection.h b/src/network/connection.h index 63cde55..8927e23 100644 --- a/src/network/connection.h +++ b/src/network/connection.h @@ -25,10 +25,14 @@ struct net_connection { int sd; /** socket descriptor */ + unsigned int flags; /** Connection flags */ void* ptr; /** data pointer */ struct event event; /** libevent struct for read/write events */ + time_t last_recv; /** Timestamp for last recv() */ + time_t last_send; /** Timestamp for last send() */ #ifdef SSL_SUPPORT SSL* ssl; /** SSL handle */ + size_t write_len; /** Length of last SSL_write(), only used if flags is NET_WANT_SSL_READ. */ #endif /* SSL_SUPPORT */ }; @@ -36,6 +40,23 @@ extern void net_con_initialize(struct net_connection* con, int sd, const void* p extern void net_con_update(struct net_connection* con, int events); extern void net_con_close(struct net_connection* con); +/** + * Send data + * + * @return returns the number of bytes sent. + * 0 if no data is sent, and this function should be called again + * -1 if an error occured, and the socket should be considered dead or closed. + */ +extern ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len); + +/** + * Receive data + * + * @return returns the number of bytes sent. + * 0 if no data is sent, and this function should be called again + * -1 if an error occured, and the socket should be considered dead or closed. + */ +extern ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len); #endif /* HAVE_UHUB_NETWORK_CONNECTION_H */