diff --git a/CMakeLists.txt b/CMakeLists.txt index 8431d75..61ea77c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ set (network_SOURCES ${PROJECT_SOURCE_DIR}/network/timeout.c ${PROJECT_SOURCE_DIR}/network/timer.c ${PROJECT_SOURCE_DIR}/network/network.c + ${PROJECT_SOURCE_DIR}/network/openssl.c ${PROJECT_SOURCE_DIR}/network/ipcalc.c ) diff --git a/src/network/backend.c b/src/network/backend.c index 97b8426..62c892d 100644 --- a/src/network/backend.c +++ b/src/network/backend.c @@ -182,10 +182,7 @@ void net_con_close(struct net_connection* con) #ifdef SSL_SUPPORT #ifdef SSL_USE_OPENSSL if (con->ssl) - { - SSL_shutdown(con->ssl); - SSL_clear(con->ssl); - } + net_ssl_shutdown(con); #endif /* SSL_USE_OPENSSL */ #endif /* SSL_SUPPORT */ diff --git a/src/network/common.h b/src/network/common.h index 8f60477..48eeec4 100644 --- a/src/network/common.h +++ b/src/network/common.h @@ -1,6 +1,6 @@ /* * uhub - A tiny ADC p2p connection hub - * Copyright (C) 2007-2010, Jan Vidar Krey + * Copyright (C) 2007-2012, Jan Vidar Krey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,10 @@ #define NET_WANT_SSL_CONNECT 0x0080 #define NET_WANT_SSL_X509_LOOKUP 0x0100 +#define NET_SSL_ANY NET_WANT_SSL_READ | NET_WANT_SSL_WRITE | NET_WANT_SSL_ACCEPT | NET_WANT_SSL_CONNECT | NET_WANT_SSL_X509_LOOKUP + +struct ssl_handle; /* abstract type */ + #define NET_CLEANUP 0x8000 #define NET_CON_STRUCT_BASIC \ @@ -35,17 +39,8 @@ net_connection_cb callback; /** Callback function */ \ struct timeout_evt* timeout; /** timeout event handler */ -#ifdef SSL_USE_OPENSSL #define NET_CON_STRUCT_SSL \ - SSL* ssl; /** SSL handle */ \ - uint32_t ssl_state; /** SSL state */ \ - size_t write_len; /** Length of last SSL_write(), only used if flags is NET_WANT_SSL_READ. */ -#endif - -#ifdef SSL_USE_GNUTLS -#define NET_CON_STRUCT_SSL \ - uint32_t ssl_state; /** SSL state */ -#endif + struct ssl_handle* ssl; /** SSL handle */ #ifdef SSL_SUPPORT #define NET_CON_STRUCT_COMMON \ diff --git a/src/network/connection.c b/src/network/connection.c index ef3c6fe..56a27c3 100644 --- a/src/network/connection.c +++ b/src/network/connection.c @@ -1,6 +1,6 @@ /* * uhub - A tiny ADC p2p connection hub - * Copyright (C) 2007-2010, Jan Vidar Krey + * Copyright (C) 2007-2012, Jan Vidar Krey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,138 +20,6 @@ #include "uhub.h" #include "network/common.h" -#ifdef SSL_SUPPORT - -enum uhub_tls_state -{ - tls_st_none, - tls_st_error, - tls_st_accepting, - tls_st_connecting, - tls_st_connected, - tls_st_disconnecting, -}; - -#ifdef SSL_USE_OPENSSL -static int handle_openssl_error(struct net_connection* con, int ret) -{ - uhub_assert(con); - - int error = SSL_get_error(con->ssl, ret); - switch (error) - { - case SSL_ERROR_ZERO_RETURN: - LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_ZERO_RETURN", ret, error); - con->ssl_state = tls_st_error; - return -1; - - case SSL_ERROR_WANT_READ: - LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_READ", ret, error); - con->flags |= NET_WANT_SSL_READ; - net_con_update(con, NET_EVENT_READ); - return 0; - - case SSL_ERROR_WANT_WRITE: - LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_WRITE", ret, error); - con->flags |= NET_WANT_SSL_WRITE; - net_con_update(con, NET_EVENT_READ | NET_EVENT_WRITE); - return 0; - - case SSL_ERROR_SYSCALL: - LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SYSCALL", ret, error); - /* if ret == 0, connection closed, if ret == -1, check with errno */ - if (ret == 0) - return -1; - else - return -net_error(); - - case SSL_ERROR_SSL: - LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SSL", ret, error); - /* internal openssl error */ - con->ssl_state = tls_st_error; - return -1; - } - return -1; -} -#endif /* SSL_USE_OPENSSL */ - -ssize_t net_con_ssl_accept(struct net_connection* con) -{ - uhub_assert(con); - con->ssl_state = tls_st_accepting; - ssize_t ret; -#ifdef SSL_USE_OPENSSL - ret = SSL_accept(con->ssl); -#ifdef NETWORK_DUMP_DEBUG - LOG_PROTO("SSL_accept() ret=%d", ret); -#endif /* NETWORK_DUMP_DEBUG */ - if (ret > 0) - { - net_con_update(con, NET_EVENT_READ); - con->ssl_state = tls_st_connected; - } - else - { - return handle_openssl_error(con, ret); - } -#endif /* SSL_USE_OPENSSL */ - return ret; -} - -ssize_t net_con_ssl_connect(struct net_connection* con) -{ - uhub_assert(con); - ssize_t ret; - con->ssl_state = tls_st_connecting; -#ifdef SSL_USE_OPENSSL - ret = SSL_connect(con->ssl); -#ifdef NETWORK_DUMP_DEBUG - LOG_PROTO("SSL_connect() ret=%d", ret); -#endif /* NETWORK_DUMP_DEBUG */ - if (ret > 0) - { - con->ssl_state = tls_st_connected; - net_con_update(con, NET_EVENT_READ); - } - else - { - return handle_openssl_error(con, ret); - } -#endif /* SSL_USE_OPENSSL */ - return ret; -} - -#ifdef SSL_USE_OPENSSL -ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode ssl_mode, SSL_CTX* ssl_ctx) -{ - uhub_assert(con); - - SSL* ssl = 0; - - if (ssl_mode == net_con_ssl_mode_server) - { - ssl = SSL_new(ssl_ctx); - if (!ssl) - { - LOG_ERROR("Unable to create new SSL stream\n"); - return -1; - } - SSL_set_fd(ssl, con->sd); - net_con_set_ssl(con, ssl); - return net_con_ssl_accept(con); - } - else - { - ssl = SSL_new(SSL_CTX_new(TLSv1_method())); - SSL_set_fd(ssl, con->sd); - net_con_set_ssl(con, ssl); - return net_con_ssl_connect(con); - } - -} -#endif /* SSL_USE_OPENSSL */ -#endif /* SSL_SUPPORT */ - #ifdef SSL_SUPPORT void net_stats_add_tx(size_t bytes); void net_stats_add_rx(size_t bytes); @@ -161,9 +29,7 @@ ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len) { int ret; #ifdef SSL_SUPPORT -#ifdef SSL_USE_OPENSSL if (!con->ssl) -#endif /* SSL_USE_OPENSSL */ { #endif ret = net_send(con->sd, buf, len, UHUB_SEND_SIGNAL); @@ -181,22 +47,10 @@ ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len) } #ifdef SSL_SUPPORT } -#ifdef SSL_USE_OPENSSL else { - con->write_len = len; - ret = SSL_write(con->ssl, buf, len); - LOG_PROTO("SSL_write(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret); - if (ret <= 0) - { - return handle_openssl_error(con, ret); - } - else - { - net_stats_add_tx(ret); - } + ret = net_ssl_send(con, buf, len); } -#endif /* SSL_USE_OPENSSL */ #endif /* SSL_SUPPORT */ return ret; } @@ -205,7 +59,7 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len) { int ret; #ifdef SSL_SUPPORT - if (!net_con_is_ssl(con)) + if (!con->ssl) { #endif ret = net_recv(con->sd, buf, len, 0); @@ -229,22 +83,7 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len) } else { -#ifdef SSL_USE_OPENSSL - if (con->ssl_state == tls_st_error) - return -1; - - ret = SSL_read(con->ssl, buf, len); - LOG_PROTO("SSL_read(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret); - if (ret > 0) - { - net_con_update(con, NET_EVENT_READ); - net_stats_add_rx(ret); - } - else - { - return handle_openssl_error(con, ret); - } -#endif /* SSL_USE_OPENSSL */ + ret = net_ssl_recv(con, buf, len); } #endif /* SSL_SUPPORT */ return ret; @@ -274,22 +113,8 @@ ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len) int net_con_is_ssl(struct net_connection* con) { -#ifdef SSL_USE_OPENSSL - return con->ssl != 0; -#endif + return !!con->ssl; } - -#ifdef SSL_USE_OPENSSL -SSL* net_con_get_ssl(struct net_connection* con) -{ - return con->ssl; -} - -void net_con_set_ssl(struct net_connection* con, SSL* ssl) -{ - con->ssl = ssl; -} -#endif /* SSL_USE_OPENSSL */ #endif /* SSL_SUPPORT */ int net_con_get_sd(struct net_connection* con) @@ -305,9 +130,8 @@ void* net_con_get_ptr(struct net_connection* con) void net_con_destroy(struct net_connection* con) { #ifdef SSL_SUPPORT -#ifdef SSL_USE_OPENSSL - SSL_free(con->ssl); -#endif /* SSL_USE_OPENSSL */ + if (con->ssl) + net_ssl_destroy(con); #endif hub_free(con); } @@ -325,66 +149,12 @@ void net_con_callback(struct net_connection* con, int events) } #ifdef SSL_SUPPORT -#ifdef SSL_USE_OPENSSL if (!con->ssl) -#endif /* SSL_USE_OPENSSL */ - { #endif con->callback(con, events, con->ptr); #ifdef SSL_SUPPORT - } -#ifdef SSL_USE_OPENSSL else -#endif /* SSL_USE_OPENSSL */ - { -#ifdef NETWORK_DUMP_DEBUG - LOG_PROTO("net_con_event: events=%d, con=%p, state=%d", events, con, con->ssl_state); -#endif - switch (con->ssl_state) - { - case tls_st_none: - con->callback(con, events, con->ptr); - break; - - case tls_st_error: - con->callback(con, NET_EVENT_READ, con->ptr); - break; - - case tls_st_accepting: - if (net_con_ssl_accept(con) < 0) - { - con->callback(con, NET_EVENT_READ, con->ptr); - } - break; - - case tls_st_connecting: - if (net_con_ssl_connect(con) < 0) - { - con->callback(con, NET_EVENT_READ, con->ptr); - } - break; - - case tls_st_connected: - LOG_PROTO("tls_st_connected, events=%s%s, ssl_flags=%s%s", (events & NET_EVENT_READ ? "R" : ""), (events & NET_EVENT_WRITE ? "W" : ""), con->flags & NET_WANT_SSL_READ ? "R" : "", con->flags & NET_WANT_SSL_WRITE ? "W" : ""); - if (events & NET_EVENT_WRITE && con->flags & NET_WANT_SSL_READ) - { - con->callback(con, events & NET_EVENT_READ, con->ptr); - return; - } - - if (events & NET_EVENT_READ && con->flags & NET_WANT_SSL_WRITE) - { - con->callback(con, events & NET_EVENT_READ, con->ptr); - return; - } - - con->callback(con, events, con->ptr); - break; - - case tls_st_disconnecting: - return; - } - } + net_ssl_callback(con, events); #endif } diff --git a/src/network/connection.h b/src/network/connection.h index 53fd15e..84cc96a 100644 --- a/src/network/connection.h +++ b/src/network/connection.h @@ -1,6 +1,6 @@ /* * uhub - A tiny ADC p2p connection hub - * Copyright (C) 2007-2010, Jan Vidar Krey + * Copyright (C) 2007-2012, Jan Vidar Krey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include "uhub.h" #include "network/common.h" #include "network/backend.h" +#include "network/tls.h" #define NET_EVENT_TIMEOUT 0x0001 #define NET_EVENT_READ 0x0002 @@ -83,31 +84,5 @@ extern ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len); extern void net_con_set_timeout(struct net_connection* con, int seconds); extern void net_con_clear_timeout(struct net_connection* con); -#ifdef SSL_SUPPORT -/** - * Start SSL_accept() - */ -extern ssize_t net_con_ssl_accept(struct net_connection*); - -/** - * Start SSL_connect() - */ -extern ssize_t net_con_ssl_connect(struct net_connection*); - -enum net_con_ssl_mode -{ - net_con_ssl_mode_server, - net_con_ssl_mode_client, -}; - -#ifdef SSL_USE_OPENSSL -extern ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode, SSL_CTX* ssl_ctx); -extern SSL* net_con_get_ssl(struct net_connection* con); -extern void net_con_set_ssl(struct net_connection* con, SSL*); -#endif // SSL_USE_OPENSSL -extern int net_con_is_ssl(struct net_connection* con); - -#endif /* SSL_SUPPORT */ - #endif /* HAVE_UHUB_NETWORK_CONNECTION_H */ diff --git a/src/network/openssl.c b/src/network/openssl.c new file mode 100644 index 0000000..509555d --- /dev/null +++ b/src/network/openssl.c @@ -0,0 +1,252 @@ +/* + * uhub - A tiny ADC p2p connection hub + * Copyright (C) 2007-2012, Jan Vidar Krey + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "uhub.h" +#include "network/common.h" +#include "network/tls.h" + +#ifdef SSL_SUPPORT +#ifdef SSL_USE_OPENSSL + +struct net_ssl_openssl +{ + SSL* ssl; + enum ssl_state state; +}; + +static struct net_ssl_openssl* get_handle(struct net_connection* con) +{ + uhub_assert(con); + return (struct net_ssl_openssl*) con->ssl; +} + +static int handle_openssl_error(struct net_connection* con, int ret) +{ + struct net_ssl_openssl* handle = get_handle(con); + + int error = SSL_get_error(handle->ssl, ret); + switch (error) + { + case SSL_ERROR_ZERO_RETURN: + LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_ZERO_RETURN", ret, error); + handle->state = tls_st_error; + return -1; + + case SSL_ERROR_WANT_READ: + LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_READ", ret, error); + con->flags |= NET_WANT_SSL_READ; + net_con_update(con, NET_EVENT_READ); + return 0; + + case SSL_ERROR_WANT_WRITE: + LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_WRITE", ret, error); + con->flags |= NET_WANT_SSL_WRITE; + net_con_update(con, NET_EVENT_READ | NET_EVENT_WRITE); + return 0; + + case SSL_ERROR_SYSCALL: + LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SYSCALL", ret, error); + /* if ret == 0, connection closed, if ret == -1, check with errno */ + if (ret == 0) + return -1; + else + return -net_error(); + + case SSL_ERROR_SSL: + LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SSL", ret, error); + /* internal openssl error */ + handle->state = tls_st_error; + return -1; + } + return -1; +} + +ssize_t net_con_ssl_accept(struct net_connection* con) +{ + struct net_ssl_openssl* handle = get_handle(con); + handle->state = tls_st_accepting; + ssize_t ret; + + ret = SSL_accept(handle->ssl); + LOG_PROTO("SSL_accept() ret=%d", ret); + if (ret > 0) + { + net_con_update(con, NET_EVENT_READ); + handle->state = tls_st_connected; + } + else + { + return handle_openssl_error(con, ret); + } + return ret; +} + +ssize_t net_con_ssl_connect(struct net_connection* con) +{ + struct net_ssl_openssl* handle = get_handle(con); + ssize_t ret; + handle->state = tls_st_connecting; + + ret = SSL_connect(handle->ssl); +#ifdef NETWORK_DUMP_DEBUG + LOG_PROTO("SSL_connect() ret=%d", ret); +#endif /* NETWORK_DUMP_DEBUG */ + if (ret > 0) + { + handle->state = tls_st_connected; + net_con_update(con, NET_EVENT_READ); + } + else + { + return handle_openssl_error(con, ret); + } + return ret; +} + +ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode ssl_mode, SSL_CTX* ssl_ctx) +{ + uhub_assert(con); + + struct net_ssl_openssl* handle = (struct net_ssl_openssl*) hub_malloc_zero(sizeof(struct net_ssl_openssl)); + + if (ssl_mode == net_con_ssl_mode_server) + { + handle->ssl = SSL_new(ssl_ctx); + if (!handle->ssl) + { + LOG_ERROR("Unable to create new SSL stream\n"); + return -1; + } + SSL_set_fd(handle->ssl, con->sd); + con->ssl = (struct ssl_handle*) handle; + return net_con_ssl_accept(con); + } + else + { + handle->ssl = SSL_new(SSL_CTX_new(TLSv1_method())); + SSL_set_fd(handle->ssl, con->sd); + con->ssl = (struct ssl_handle*) handle; + return net_con_ssl_connect(con); + } + +} + +ssize_t net_ssl_send(struct net_connection* con, const void* buf, size_t len) +{ + struct net_ssl_openssl* handle = get_handle(con); +// con->write_len = len; + ssize_t ret = SSL_write(handle->ssl, buf, len); + LOG_PROTO("SSL_write(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret); + if (ret <= 0) + { + return handle_openssl_error(con, ret); + } + return ret; +} + +ssize_t net_ssl_recv(struct net_connection* con, void* buf, size_t len) +{ + struct net_ssl_openssl* handle = get_handle(con); + ssize_t ret; + + if (handle->state == tls_st_error) + return -1; + + ret = SSL_read(handle->ssl, buf, len); + LOG_PROTO("SSL_read(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret); + if (ret > 0) + { + net_con_update(con, NET_EVENT_READ); + } + else + { + return handle_openssl_error(con, ret); + } + return ret; +} + +void net_ssl_shutdown(struct net_connection* con) +{ + struct net_ssl_openssl* handle = get_handle(con); + SSL_shutdown(handle->ssl); + SSL_clear(handle->ssl); +} + +void net_ssl_destroy(struct net_connection* con) +{ + struct net_ssl_openssl* handle = get_handle(con); + SSL_free(handle->ssl); +} + +void net_ssl_callback(struct net_connection* con, int events) +{ + struct net_ssl_openssl* handle = get_handle(con); + + uint32_t flags = con->flags; + con->flags &= ~NET_SSL_ANY; /* reset the SSL related flags */ + + switch (handle->state) + { + case tls_st_none: + con->callback(con, events, con->ptr); + break; + + case tls_st_error: + con->callback(con, NET_EVENT_READ, con->ptr); + break; + + case tls_st_accepting: + if (net_con_ssl_accept(con) < 0) + { + con->callback(con, NET_EVENT_READ, con->ptr); + } + break; + + case tls_st_connecting: + if (net_con_ssl_connect(con) < 0) + { + con->callback(con, NET_EVENT_READ, con->ptr); + } + break; + + case tls_st_connected: + LOG_PROTO("tls_st_connected, events=%s%s, ssl_flags=%s%s", (events & NET_EVENT_READ ? "R" : ""), (events & NET_EVENT_WRITE ? "W" : ""), flags & NET_WANT_SSL_READ ? "R" : "", flags & NET_WANT_SSL_WRITE ? "W" : ""); + if (events & NET_EVENT_WRITE && flags & NET_WANT_SSL_READ) + { + con->callback(con, events & NET_EVENT_READ, con->ptr); + return; + } + + if (events & NET_EVENT_READ && flags & NET_WANT_SSL_WRITE) + { + con->callback(con, events & NET_EVENT_READ, con->ptr); + return; + } + + con->callback(con, events, con->ptr); + break; + + case tls_st_disconnecting: + return; + } +} + + +#endif /* SSL_USE_OPENSSL */ +#endif /* SSL_SUPPORT */ \ No newline at end of file diff --git a/src/network/tls.h b/src/network/tls.h new file mode 100644 index 0000000..eccccf7 --- /dev/null +++ b/src/network/tls.h @@ -0,0 +1,71 @@ +/* + * uhub - A tiny ADC p2p connection hub + * Copyright (C) 2007-2012, Jan Vidar Krey + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef HAVE_UHUB_NETWORK_TLS_H +#define HAVE_UHUB_NETWORK_TLS_H + +#include "uhub.h" + +#ifdef SSL_SUPPORT + + +enum ssl_state +{ + tls_st_none, + tls_st_error, + tls_st_accepting, + tls_st_connecting, + tls_st_connected, + tls_st_disconnecting, +}; + +enum net_con_ssl_mode +{ + net_con_ssl_mode_server, + net_con_ssl_mode_client, +}; + + +/** + * Start SSL_accept() + */ +extern ssize_t net_con_ssl_accept(struct net_connection*); + +/** + * Start SSL_connect() + */ +extern ssize_t net_con_ssl_connect(struct net_connection*); + +extern ssize_t net_ssl_send(struct net_connection* con, const void* buf, size_t len); +extern ssize_t net_ssl_recv(struct net_connection* con, void* buf, size_t len); + +extern void net_ssl_shutdown(struct net_connection* con); +extern void net_ssl_destroy(struct net_connection* con); +extern void net_ssl_callback(struct net_connection* con, int events); + + +#ifdef SSL_USE_OPENSSL +extern ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode, SSL_CTX* ssl_ctx); +extern SSL* net_con_get_ssl(struct net_connection* con); +extern void net_con_set_ssl(struct net_connection* con, SSL*); +#endif // SSL_USE_OPENSSL +extern int net_con_is_ssl(struct net_connection* con); + +#endif /* SSL_SUPPORT */ +#endif /* HAVE_UHUB_NETWORK_TLS_H */ \ No newline at end of file