GnuTLS communication: the last part

This commit is contained in:
Evgeny Grin (Karlson2k)
2024-11-24 20:54:11 +03:00
parent 8162b4098f
commit cee65d14e2
21 changed files with 986 additions and 160 deletions
+5
View File
@@ -1291,6 +1291,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
*/
MHD_SC_TLS_CONNECTION_INIT_FAILED = 51201
,
/**
* Failed to perform TLS handshake
*/
MHD_SC_TLS_CONNECTION_HANDSHAKED_FAILED = 51220
,
/**
* Something wrong in the internal MHD logic.
* This error should be never returned if MHD works as expected.
+5
View File
@@ -1291,6 +1291,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
*/
MHD_SC_TLS_CONNECTION_INIT_FAILED = 51201
,
/**
* Failed to perform TLS handshake
*/
MHD_SC_TLS_CONNECTION_HANDSHAKED_FAILED = 51220
,
/**
* Something wrong in the internal MHD logic.
* This error should be never returned if MHD works as expected.
+3 -2
View File
@@ -108,8 +108,9 @@ upgrade_files = \
tls_common_files = \
mhd_tls_choice.h \
mhd_tls_funcs.c mhd_tls_funcs.h \
tls_dh_params.h
mhd_tls_funcs.c mhd_tls_funcs.h mhd_tls_enums.h \
tls_dh_params.h \
conn_tls_check.c conn_tls_check.h
tls_gnu_files = \
tls_gnu_tls_lib.h tls_gnu_daemon_data.h tls_gnu_conn_data.h \
+31 -82
View File
@@ -46,26 +46,51 @@
#include "conn_data_send.h"
#include "stream_process_states.h"
#ifdef MHD_ENABLE_HTTPS
# include "conn_tls_check.h"
#endif /* MHD_ENABLE_HTTPS */
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c)
{
bool send_ready_state_known;
bool has_sock_err;
bool data_processed;
#ifdef MHD_ENABLE_HTTPS
if (mhd_C_HAS_TLS (c))
{
switch (mhd_conn_tls_check (c))
{
case mhd_CONN_TLS_CHECK_OK:
break; /* Process HTTP data */
case mhd_CONN_TLS_CHECK_HANDSHAKING:
return true; /* TLS is not yet ready */
case mhd_CONN_TLS_CHECK_BROKEN:
return false; /* Connection is broken */
default:
mhd_assert (0 && "Impossible value");
MHD_UNREACHABLE_;
}
}
#endif /* MHD_ENABLE_HTTPS */
/* The "send-ready" state is known if system polling call is edge-triggered
(it always checks for both send- and recv-ready) or if connection needs
sending (therefore "send-ready" was explicitly checked by sockets polling
call). */
const bool send_ready_state_known =
send_ready_state_known =
((mhd_D_IS_USING_EDGE_TRIG (c->daemon)) ||
(0 != (MHD_EVENT_LOOP_INFO_SEND & c->event_loop_info)));
const bool has_sock_err =
has_sock_err =
(0 != (mhd_SOCKET_NET_STATE_ERROR_READY & c->sk.ready));
bool data_processed;
data_processed = false;
if (0 != (MHD_EVENT_LOOP_INFO_RECV & c->event_loop_info))
{
bool use_recv;
use_recv = (0 != (mhd_SOCKET_NET_STATE_RECV_READY & c->sk.ready));
use_recv = (0 != (mhd_SOCKET_NET_STATE_RECV_READY
& (c->sk.ready | mhd_C_HAS_TLS_DATA_IN (c))));
use_recv = use_recv ||
(has_sock_err && c->sk.props.is_nonblck);
@@ -85,7 +110,7 @@ mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c)
* + connection is ready for sending or
* + just formed send data, connection send ready status is not known and
* connection socket is non-blocking
* + detected network error on the connection, to check to the error */
* + detected network error on the connection, to check for the error */
/* Assuming that after finishing receiving phase, connection send system
buffers should have some space as sending was performed before receiving
or has not been performed yet. */
@@ -107,80 +132,4 @@ mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c)
if (! data_processed)
return mhd_conn_process_data (c);
return true;
#if 0 // TODO: re-implement fasttrack as a single unified buffer sending
if (! force_close)
{
/* No need to check value of 'ret' here as closed connection
* cannot be in MHD_EVENT_LOOP_INFO_SEND state. */
if ( (MHD_EVENT_LOOP_INFO_SEND == c->event_loop_info) &&
write_ready)
{
MHD_connection_handle_write (c);
ret = MHD_connection_handle_idle (c);
states_info_processed = true;
}
}
else
{
MHD_connection_close_ (c,
MHD_REQUEST_TERMINATED_WITH_ERROR);
return MHD_connection_handle_idle (c);
}
if (! states_info_processed)
{ /* Connection is not read or write ready, but external conditions
* may be changed and need to be processed. */
ret = MHD_connection_handle_idle (c);
}
/* Fast track for fast connections. */
/* If full request was read by single read_handler() invocation
and headers were completely prepared by single MHD_connection_handle_idle()
then try not to wait for next sockets polling and send response
immediately.
As writeability of socket was not checked and it may have
some data pending in system buffers, use this optimization
only for non-blocking sockets. */
/* No need to check 'ret' as connection is always in
* mhd_HTTP_STAGE_CLOSED state if 'ret' is equal 'MHD_NO'. */
else if (on_fasttrack && c->sk.props.is_nonblck)
{
if (mhd_HTTP_STAGE_HEADERS_SENDING == c->stage)
{
MHD_connection_handle_write (c);
/* Always call 'MHD_connection_handle_idle()' after each read/write. */
ret = MHD_connection_handle_idle (c);
}
/* If all headers were sent by single write_handler() and
* response body is prepared by single MHD_connection_handle_idle()
* call - continue. */
if ((mhd_HTTP_STAGE_UNCHUNKED_BODY_READY == c->stage) ||
(mhd_HTTP_STAGE_CHUNKED_BODY_READY == c->stage))
{
MHD_connection_handle_write (c);
ret = MHD_connection_handle_idle (c);
}
}
/* All connection's data and states are processed for this turn.
* If connection already has more data to be processed - use
* zero timeout for next select()/poll(). */
/* Thread-per-connection do not need global zero timeout as
* connections are processed individually. */
/* Note: no need to check for read buffer availability for
* TLS read-ready connection in 'read info' state as connection
* without space in read buffer will be marked as 'info block'. */
if ( (! c->daemon->data_already_pending) &&
(! mhd_D_HAS_THR_PER_CONN (c->daemon)) )
{
if (0 != (MHD_EVENT_LOOP_INFO_PROCESS & c->event_loop_info))
c->daemon->data_already_pending = true;
#ifdef HTTPS_SUPPORT
else if ( (c->tls_read_ready) &&
(0 != (MHD_EVENT_LOOP_INFO_RECV & c->event_loop_info)) )
c->daemon->data_already_pending = true;
#endif /* HTTPS_SUPPORT */
}
return ret;
#endif
}
-2
View File
@@ -57,8 +57,6 @@ mhd_conn_data_recv (struct MHD_Connection *restrict c,
mhd_assert ((0 == (c->sk.ready & mhd_SOCKET_NET_STATE_ERROR_READY)) || \
has_err);
// TODO: TLS support: handshake/transport layer
buf = c->read_buffer + c->read_buffer_offset;
buf_size = c->read_buffer_size - c->read_buffer_offset;
-4
View File
@@ -83,10 +83,6 @@ mhd_conn_data_send (struct MHD_Connection *restrict c)
// TODO: assert check suspended
#ifdef HTTPS_SUPPORT
// TODO: TLS support, handshake
#endif /* HTTPS_SUPPORT */
// TODO: MOVE out STATES PROCESSING
res = mhd_SOCKET_ERR_INTERNAL;
+2 -1
View File
@@ -108,7 +108,8 @@ mhd_conn_mark_ready_update3 (struct MHD_Connection *restrict c,
{
if (force_ready ||
(0 !=
(((unsigned int) c->sk.ready) & ((unsigned int) c->event_loop_info)
((((unsigned int) c->sk.ready) | mhd_C_HAS_TLS_DATA_IN (c))
& ((unsigned int) c->event_loop_info)
& (MHD_EVENT_LOOP_INFO_RECV | MHD_EVENT_LOOP_INFO_SEND))))
mhd_conn_mark_ready (c, d);
else
+130
View File
@@ -0,0 +1,130 @@
/*
This file is part of GNU libmicrohttpd
Copyright (C) 2024 Evgeny Grin (Karlson2k)
GNU libmicrohttpd is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
GNU libmicrohttpd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file src/mhd2/conn_tls_handshake.c
* @brief The implementation of connection TLS handling functions
* @author Karlson2k (Evgeny Grin)
*/
#include "mhd_sys_options.h"
#include "conn_tls_check.h"
#include "mhd_assert.h"
#include "mhd_daemon.h"
#include "mhd_connection.h"
#include "mhd_socket_error_funcs.h"
#include "daemon_logger.h"
#include "mhd_tls_funcs.h"
#include "conn_mark_ready.h"
#include "stream_funcs.h"
#include "stream_process_states.h"
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ enum mhd_ConnTlsCheckResult
mhd_conn_tls_check (struct MHD_Connection *restrict c)
{
mhd_assert (mhd_C_HAS_TLS (c));
mhd_assert (mhd_D_HAS_TLS (c->daemon));
mhd_assert ((mhd_CONN_STATE_TLS_HANDSHAKE_RECV == c->conn_state) || \
(mhd_CONN_STATE_TLS_HANDSHAKE_SEND == c->conn_state) || \
(mhd_CONN_STATE_TLS_CONNECTED == c->conn_state));
if (mhd_CONN_STATE_TLS_CONNECTED == c->conn_state)
return mhd_CONN_TLS_CHECK_OK; /* TLS is already connected */
if (0 != (mhd_SOCKET_NET_STATE_ERROR_READY & c->sk.ready))
{
/* Some socket error has been detected. Do not try to handshake. */
if (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err)
c->sk.state.discnt_err = mhd_socket_error_get_from_socket (c->sk.fd);
mhd_conn_start_closing_skt_err (c);
return mhd_CONN_TLS_CHECK_BROKEN;
}
/* Check whether the socket is ready for the required send/recv operation */
if (0 == (((mhd_CONN_FLAG_RECV | mhd_CONN_FLAG_SEND)
& ((unsigned int) c->conn_state)
& ((unsigned int) c->sk.ready))))
return mhd_CONN_TLS_CHECK_HANDSHAKING;
switch (mhd_tls_conn_handshake (c->tls))
{
case mhd_TLS_PROCED_SUCCESS:
c->conn_state = mhd_CONN_STATE_TLS_CONNECTED;
if (! c->sk.props.is_nonblck)
{
/* The socket is blocking,
probably all available data has been processed already. */
c->sk.ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' and 'send-ready' */
(((unsigned int) c->sk.ready)
& (~(enum mhd_SocketNetState)
mhd_SOCKET_NET_STATE_SEND_READY)
& (~(enum mhd_SocketNetState)
mhd_SOCKET_NET_STATE_RECV_READY));
}
/* TLS is connected now, set event loop state based on HTTP protocol.
Some early application-level data could be processing in this round. */
mhd_conn_event_loop_state_update (c);
return mhd_CONN_TLS_CHECK_OK;
break;
case mhd_TLS_PROCED_RECV_MORE_NEEDED:
c->sk.ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' */
(((unsigned int) c->sk.ready)
& (~(enum mhd_SocketNetState)
mhd_SOCKET_NET_STATE_RECV_READY));
/* Intentional fall-through */
case mhd_TLS_PROCED_RECV_INTERRUPTED:
c->conn_state = mhd_CONN_STATE_TLS_HANDSHAKE_RECV;
c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV;
break;
case mhd_TLS_PROCED_SEND_MORE_NEEDED:
c->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
(((unsigned int) c->sk.ready)
& (~(enum mhd_SocketNetState)
mhd_SOCKET_NET_STATE_SEND_READY));
/* Intentional fall-through */
case mhd_TLS_PROCED_SEND_INTERRUPTED:
c->conn_state = mhd_CONN_STATE_TLS_HANDSHAKE_SEND;
c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND;
break;
case mhd_TLS_PROCED_FAILED:
c->conn_state = mhd_CONN_STATE_TLS_FAILED;
mhd_LOG_MSG (c->daemon, \
MHD_SC_TLS_CONNECTION_HANDSHAKED_FAILED, \
"Failed to perform TLS handshake on the new connection");
c->sk.state.discnt_err = mhd_SOCKET_ERR_TLS;
mhd_conn_start_closing_skt_err (c);
return mhd_CONN_TLS_CHECK_BROKEN;
break;
default:
mhd_assert (0 && "Should be unreachable");
MHD_UNREACHABLE_;
return mhd_CONN_TLS_CHECK_BROKEN;
}
mhd_conn_mark_ready_update (c);
return mhd_CONN_TLS_CHECK_HANDSHAKING;
}
+71
View File
@@ -0,0 +1,71 @@
/*
This file is part of GNU libmicrohttpd
Copyright (C) 2024 Evgeny Grin (Karlson2k)
GNU libmicrohttpd is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
GNU libmicrohttpd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file src/mhd2/conn_tls_check.h
* @brief The declarations of connection TLS handling functions
* @author Karlson2k (Evgeny Grin)
*/
#ifndef MHD_CONN_TLS_CHECK_H
#define MHD_CONN_TLS_CHECK_H 1
#include "mhd_sys_options.h"
#include "sys_bool_type.h"
struct MHD_Connection; /* forward declaration */
/**
* The results of connection TLS checking
*/
enum mhd_ConnTlsCheckResult
{
/**
* The TLS layer is connected, the communication over TLS can be performed
*/
mhd_CONN_TLS_CHECK_OK = 0
,
/**
* The TLS layer connection is in progress.
* Communication over TLS is not possible yet.
*/
mhd_CONN_TLS_CHECK_HANDSHAKING
,
/**
* The connection is broken and must be closed
*/
mhd_CONN_TLS_CHECK_BROKEN
};
/**
* Check connection TLS status, perform TLS (re-)handshake if necessary,
* update connection's recv()/send() event loop state and connection active
* state if network operation has been performed.
* @param c the connection to process
* @return #mhd_CONN_TLS_CHECK_OK if the connection can be used,
* other enum mhd_ConnTlsCheckResult values otherwise
*/
MHD_INTERNAL enum mhd_ConnTlsCheckResult
mhd_conn_tls_check (struct MHD_Connection *restrict c)
MHD_FN_PAR_NONNULL_ALL_;
#endif /* ! MHD_CONN_TLS_CHECK_H */
+4 -1
View File
@@ -249,10 +249,13 @@ new_connection_prepare_ (struct MHD_Daemon *restrict daemon,
"the new connection");
ret = MHD_SC_TLS_CONNECTION_INIT_FAILED;
}
#ifndef NDEBUG
else
{
c->conn_state = mhd_CONN_STATE_TLS_HANDSHAKE_RECV;
#ifndef NDEBUG
c->dbg.tls_inited = true;
#endif
}
}
if (MHD_SC_OK == ret)
+129 -3
View File
@@ -79,6 +79,106 @@
struct MHD_Connection; /* forward declaration */
#define mhd_CONN_FLAG_RECV (1u << 0)
#define mhd_CONN_FLAG_SEND (1u << 1)
#define mhd_CONN_FLAG_TLS (1u << 2)
#define mhd_CONN_FLAG_HANDSHAKE (1u << 3)
#define mhd_CONN_FLAG_CLOSING (1u << 4)
#define mhd_CONN_FLAG_ERROR (1u << 6)
#define mhd_CONN_FLAG_CLOSED (1u << 7)
/**
* The states of connection TLS layer
* The bits (1 << 0) | (1 << 1) in enum values match the same bits in
* enum MHD_ConnectionEventLoopInfo and in enum mhd_SocketNetState values
*/
enum MHD_FIXED_ENUM_ mhd_ConnState
{
/**
* TLS not started / plain TCP communication
*/
mhd_CONN_STATE_TCP_CONNECTED = 0
,
/**
* TLS handshake in progress, need to receive the data
*/
mhd_CONN_STATE_TLS_HANDSHAKE_RECV =
mhd_CONN_FLAG_TLS | mhd_CONN_FLAG_HANDSHAKE | mhd_CONN_FLAG_RECV
,
/**
* TLS handshake in progress, need to send the data
*/
mhd_CONN_STATE_TLS_HANDSHAKE_SEND =
mhd_CONN_FLAG_TLS | mhd_CONN_FLAG_HANDSHAKE | mhd_CONN_FLAG_SEND
,
/**
* TLS connection established, HTTP communication is performing
*/
mhd_CONN_STATE_TLS_CONNECTED = mhd_CONN_FLAG_TLS
,
/**
* Sending TLS message for shutting down TLS communication on the MHD side
*/
mhd_CONN_STATE_TLS_SHUT_WR_SENDING =
mhd_CONN_FLAG_TLS | mhd_CONN_FLAG_CLOSING | mhd_CONN_FLAG_SEND
,
/**
* Waiting to receive message from remote for shutting down TLS communication
*/
mhd_CONN_STATE_TLS_LINGERING =
mhd_CONN_FLAG_TLS | mhd_CONN_FLAG_CLOSING | mhd_CONN_FLAG_RECV
,
/**
* TLS communication gracefully closed.
* This state should be avoided. Use #mhd_CONN_STATE_TCP_CONNECTED or
* #mhd_CONN_STATE_CLOSED.
*/
mhd_CONN_STATE_TLS_CLOSED = mhd_CONN_FLAG_TLS | mhd_CONN_FLAG_CLOSED
,
/**
* TLS communication broken
*/
mhd_CONN_STATE_TLS_FAILED = mhd_CONN_FLAG_TLS | mhd_CONN_FLAG_ERROR
#if 0 // TODO: Extend to TCP states
,
/**
* Setting TCP shutdown WR
*/
mhd_CONN_STATE_TCP_SHUT_WR_SENDING =
mhd_CONN_FLAG_CLOSING | mhd_CONN_FLAG_SEND
,
/**
* Waiting for EOF from the remote side
*/
mhd_CONN_STATE_TCP_LINGERING =
mhd_CONN_FLAG_CLOSING | mhd_CONN_FLAG_RECV
#endif
,
/**
* TCP communication closed
*/
mhd_CONN_STATE_CLOSED = mhd_CONN_FLAG_CLOSED
};
#ifdef MHD_ENABLE_HTTPS
/**
* The status of TLS buffer for incoming (receive) data
*/
enum mhd_TlsBufDataIn
{
/**
* No data in pending in the TLS buffer
*/
mhd_TLS_BUF_NO_DATA = 0
,
/**
* The incoming data in already pending in the TLS buffer
*/
mhd_TLS_BUF_HAS_DATA_IN = mhd_SOCKET_NET_STATE_RECV_READY
};
#endif /* MHD_ENABLE_HTTPS */
/**
* What is this connection waiting for?
*/
@@ -413,7 +513,17 @@ struct MHD_Connection
* deallocated separately.
*/
struct mhd_TlsConnData *tls;
#endif
/**
* The state of the communication layer
*/
enum mhd_ConnState conn_state;
/**
* Status of TLS buffer for the incoming data
*/
enum mhd_TlsBufDataIn tls_has_data_in;
#endif /* MHD_ENABLE_HTTPS */
/**
* 'true' if connection is in 'process ready' list,
@@ -616,11 +726,27 @@ struct MHD_Connection
* Returns non-zero if connection has TLS enabled or zero otherwise
*/
# define mhd_C_HAS_TLS(c) (((c)->tls) ? (! 0) : (0))
#else
#else /* ! MHD_ENABLE_HTTPS */
/**
* Returns non-zero if connection has TLS enabled or zero otherwise
*/
# define mhd_C_HAS_TLS(c) (0)
#endif
#endif /* ! MHD_ENABLE_HTTPS */
#ifdef MHD_ENABLE_HTTPS
/**
* Returns #mhd_SOCKET_NET_STATE_RECV_READY if connection has incoming data
* pending in TLS buffers
*/
# define mhd_C_HAS_TLS_DATA_IN(c) \
(((c)->tls) ? ((unsigned int) ((c)->tls_has_data_in)) : (0u))
#else /* ! MHD_ENABLE_HTTPS */
/**
* Returns #mhd_SOCKET_NET_STATE_RECV_READY if connection has incoming data
* pending in TLS buffers
*/
# define mhd_C_HAS_TLS_DATA_IN(c) (0)
#endif /* ! MHD_ENABLE_HTTPS */
#endif /* ! MHD_CONNECTION_H */
+52 -4
View File
@@ -33,14 +33,19 @@
#include "mhd_socket_type.h"
#include "sys_sockets_headers.h"
#include "mhd_sockets_macros.h"
#include "mhd_socket_error_funcs.h"
#include "mhd_limits.h"
#include "mhd_assert.h"
#include "mhd_socket_error_funcs.h"
#ifdef MHD_ENABLE_HTTPS
# include "mhd_tls_funcs.h"
#endif
static MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_OUT_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
mhd_plain_recv (struct MHD_Connection *restrict c,
mhd_recv_plain (struct MHD_Connection *restrict c,
size_t buf_size,
char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
size_t *restrict received)
@@ -76,6 +81,43 @@ mhd_plain_recv (struct MHD_Connection *restrict c,
}
#ifdef MHD_ENABLE_HTTPS
static MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_OUT_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
mhd_recv_tls (struct MHD_Connection *restrict c,
size_t buf_size,
char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
size_t *restrict received)
{
/* TLS connection */
enum mhd_SocketError res;
mhd_assert (mhd_C_HAS_TLS (c));
mhd_assert (0 != buf_size);
res = mhd_tls_conn_recv (c->tls,
buf_size,
buf,
received);
c->tls_has_data_in = mhd_TLS_BUF_NO_DATA; /* Updated with the actual value below */
if (mhd_SOCKET_ERR_AGAIN == res)
c->sk.ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' */
(((unsigned int) c->sk.ready)
& (~(enum mhd_SocketNetState)
mhd_SOCKET_NET_STATE_RECV_READY));
else if ((mhd_SOCKET_ERR_NO_ERROR == res) &&
(*received == buf_size) &&
mhd_tls_conn_has_data_in (c->tls))
c->tls_has_data_in = mhd_TLS_BUF_HAS_DATA_IN;
return res;
}
#endif /* MHD_ENABLE_HTTPS */
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_OUT_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
mhd_recv (struct MHD_Connection *restrict c,
@@ -86,7 +128,13 @@ mhd_recv (struct MHD_Connection *restrict c,
mhd_assert (MHD_INVALID_SOCKET != c->sk.fd);
mhd_assert (mhd_HTTP_STAGE_CLOSED != c->stage);
// TODO: implement TLS support
#ifdef MHD_ENABLE_HTTPS
if (mhd_C_HAS_TLS (c))
return mhd_recv_tls (c,
buf_size,
buf,
received);
#endif /* MHD_ENABLE_HTTPS */
return mhd_plain_recv (c, buf_size, buf, received);
return mhd_recv_plain (c, buf_size, buf, received);
}
+78 -36
View File
@@ -71,6 +71,10 @@
#include "mhd_limits.h"
#ifdef MHD_ENABLE_HTTPS
# include "mhd_tls_funcs.h"
#endif
#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) || \
defined(MHD_SOCKETS_KIND_WINSOCK)
# define mhd_USE_VECT_SEND 1
@@ -751,7 +755,7 @@ post_send_setopt (struct MHD_Connection *connection,
static MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_IN_SIZE_ (3,2)
MHD_FN_PAR_OUT_ (5) enum mhd_SocketError
mhd_plain_send (struct MHD_Connection *restrict c,
mhd_send_plain (struct MHD_Connection *restrict c,
size_t buf_size,
const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
bool push_data,
@@ -761,6 +765,9 @@ mhd_plain_send (struct MHD_Connection *restrict c,
ssize_t res;
bool full_buf_sent;
mhd_assert (! mhd_C_HAS_TLS (c));
mhd_assert (! mhd_D_HAS_TLS (c->daemon));
if (buf_size > MHD_SCKT_SEND_MAX_SIZE_)
{
buf_size = MHD_SCKT_SEND_MAX_SIZE_; /* send() return value limit */
@@ -816,6 +823,52 @@ mhd_plain_send (struct MHD_Connection *restrict c,
}
#ifdef MHD_ENABLE_HTTPS
static MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_IN_SIZE_ (3,2)
MHD_FN_PAR_OUT_ (5) enum mhd_SocketError
mhd_send_tls (struct MHD_Connection *restrict c,
size_t buf_size,
const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
bool push_data,
size_t *restrict sent)
{
/* TLS connection */
enum mhd_SocketError res;
mhd_assert (mhd_C_HAS_TLS (c));
mhd_assert (mhd_D_HAS_TLS (c->daemon));
mhd_assert (0 != buf_size);
pre_send_setopt (c, false, push_data);
res = mhd_tls_conn_send (c->tls,
buf_size,
buf,
sent);
if (mhd_SOCKET_ERR_NO_ERROR != res)
{
if (mhd_SOCKET_ERR_AGAIN == res)
c->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
(((unsigned int) c->sk.ready)
& (~(enum mhd_SocketNetState)
mhd_SOCKET_NET_STATE_SEND_READY));
return res;
}
/* If there is a need to push the data from network buffers
* call post_send_setopt(). */
if (push_data && (buf_size == *sent))
post_send_setopt (c, false, true);
return mhd_SOCKET_ERR_NO_ERROR;
}
#endif /* MHD_ENABLE_HTTPS */
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_IN_SIZE_ (3,2)
MHD_FN_PAR_OUT_ (5) enum mhd_SocketError
@@ -825,28 +878,19 @@ mhd_send_data (struct MHD_Connection *restrict connection,
bool push_data,
size_t *restrict sent)
{
const bool tls_conn = false; // TODO: TLS support
mhd_assert (MHD_INVALID_SOCKET != connection->sk.fd);
mhd_assert (mhd_HTTP_STAGE_CLOSED != connection->stage);
if (tls_conn)
{
enum mhd_SocketError ret;
#ifdef MHD_ENABLE_HTTPS
if (mhd_C_HAS_TLS (connection))
return mhd_send_tls (connection,
buf_size,
buf,
push_data,
sent);
#endif /* MHD_ENABLE_HTTPS */
#ifdef HTTPS_SUPPORT
pre_send_setopt (connection,
(! tls_conn),
push_data);
ret = mhd_SOCKET_ERR_OTHER;
mhd_assert (0 && "Not implemented yet");
#else /* ! HTTPS_SUPPORT */
ret = mhd_SOCKET_ERR_NOTCONN;
#endif /* ! HTTPS_SUPPORT */
return ret;
}
return mhd_plain_send (connection,
return mhd_send_plain (connection,
buf_size,
buf,
push_data,
@@ -885,9 +929,7 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict connection,
bool no_vec; /* Is vector-send() disallowed? */
no_vec = false;
#ifdef HTTPS_SUPPORT
no_vec = no_vec || (false); // TODO: TLS support
#endif /* HTTPS_SUPPORT */
no_vec = no_vec || (mhd_C_HAS_TLS (connection));
#if (! defined(HAVE_SENDMSG) || ! defined(MSG_NOSIGNAL) ) && \
defined(mhd_SEND_SPIPE_SUPPRESS_POSSIBLE) && \
defined(mhd_SEND_SPIPE_SUPPRESS_NEEDED)
@@ -947,7 +989,6 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict connection,
push_hdr,
sent);
// TODO: check 'send-ready'
if ((mhd_SOCKET_ERR_NO_ERROR == ret) &&
(header_size == *sent) &&
(0 != body_size) &&
@@ -976,6 +1017,8 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict connection,
}
#ifdef mhd_USE_VECT_SEND
mhd_assert (! mhd_C_HAS_TLS (connection));
if (header_size > (header_size + body_size))
{
/* Return value limit */
@@ -1133,7 +1176,7 @@ mhd_send_sendfile (struct MHD_Connection *restrict c,
mhd_assert (mhd_REPLY_CNTN_LOC_FILE == c->rp.cntn_loc);
mhd_assert (MHD_SIZE_UNKNOWN != c->rp.response->cntn_size);
mhd_assert (chunk_size <= (size_t) SSIZE_MAX);
// mhd_assert (0 == (connection->daemon->options & MHD_USE_TLS)); // TODO: TLS support
mhd_assert (! mhd_C_HAS_TLS (c));
send_size = 0;
push_data = true;
@@ -1373,7 +1416,8 @@ send_iov_nontls (struct MHD_Connection *restrict connection,
DWORD cnt_w;
#endif /* MHD_SOCKETS_KIND_WINSOCK */
// TODO: assert for non-TLS
mhd_assert (! mhd_C_HAS_TLS (connection));
mhd_assert (! mhd_D_HAS_TLS (connection->daemon));
mhd_assert (MHD_INVALID_SOCKET != connection->sk.fd);
mhd_assert (mhd_HTTP_STAGE_CLOSED != connection->stage);
@@ -1492,7 +1536,7 @@ send_iov_nontls (struct MHD_Connection *restrict connection,
#endif /* mhd_USE_VECT_SEND */
#if ! defined(mhd_USE_VECT_SEND) || defined(HTTPS_SUPPORT) || \
#if ! defined(mhd_USE_VECT_SEND) || defined(MHD_ENABLE_HTTPS) || \
defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
@@ -1574,7 +1618,7 @@ send_iov_emu (struct MHD_Connection *restrict connection,
}
#endif /* !mhd_USE_VECT_SEND || HTTPS_SUPPORT
#endif /* !mhd_USE_VECT_SEND || MHD_ENABLE_HTTPS
|| mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
@@ -1585,10 +1629,10 @@ mhd_send_iovec (struct MHD_Connection *restrict connection,
size_t *restrict sent)
{
#ifdef mhd_USE_VECT_SEND
#if defined(HTTPS_SUPPORT) || \
#if defined(MHD_ENABLE_HTTPS) || \
defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
bool use_iov_send = true;
#endif /* HTTPS_SUPPORT || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
#endif /* MHD_ENABLE_HTTPS || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
#endif /* mhd_USE_VECT_SEND */
mhd_assert (NULL != connection->rp.resp_iov.iov);
@@ -1596,24 +1640,22 @@ mhd_send_iovec (struct MHD_Connection *restrict connection,
connection->rp.response->cntn_dtype);
mhd_assert (connection->rp.resp_iov.cnt > connection->rp.resp_iov.sent);
#ifdef mhd_USE_VECT_SEND
#if defined(HTTPS_SUPPORT) || \
#if defined(MHD_ENABLE_HTTPS) || \
defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
#ifdef HTTPS_SUPPORT
use_iov_send = use_iov_send &&
(true); // TODO: TLS support
#endif /* HTTPS_SUPPORT */
(! mhd_C_HAS_TLS (connection));
#ifdef mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED
use_iov_send = use_iov_send && (connection->daemon->sigpipe_blocked ||
connection->sk.props.has_spipe_supp);
#endif /* mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
if (use_iov_send)
#endif /* HTTPS_SUPPORT || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
#endif /* MHD_ENABLE_HTTPS || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
return send_iov_nontls (connection, r_iov, push_data, sent);
#endif /* mhd_USE_VECT_SEND */
#if ! defined(mhd_USE_VECT_SEND) || defined(HTTPS_SUPPORT) || \
#if ! defined(mhd_USE_VECT_SEND) || defined(MHD_ENABLE_HTTPS) || \
defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
return send_iov_emu (connection, r_iov, push_data, sent);
#endif /* !mhd_USE_VECT_SEND || HTTPS_SUPPORT
#endif /* !mhd_USE_VECT_SEND || MHD_ENABLE_HTTPS
|| mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
}
+72
View File
@@ -0,0 +1,72 @@
/*
This file is part of GNU libmicrohttpd
Copyright (C) 2024 Evgeny Grin (Karlson2k)
GNU libmicrohttpd is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
GNU libmicrohttpd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file src/mhd2/mhd_tls_enums.h
* @brief The definition of internal enums used for TLS communication
* @author Karlson2k (Evgeny Grin)
*/
#ifndef MHD_TLS_ENUMS_H
#define MHD_TLS_ENUMS_H 1
#include "mhd_sys_options.h"
#ifndef MHD_ENABLE_HTTPS
#error This header should be used only if HTTPS is enabled
#endif
/**
* Result of performing TLS procedure
*/
enum MHD_FIXED_ENUM_ mhd_TlsProcedureResult
{
/**
* Completed successfully
*/
mhd_TLS_PROCED_SUCCESS = 0
,
/**
* In progress, receive operation interrupted
*/
mhd_TLS_PROCED_RECV_INTERRUPTED
,
/**
* In progress, send operation interrupted
*/
mhd_TLS_PROCED_SEND_INTERRUPTED
,
/**
* In progress, need to receive more data
*/
mhd_TLS_PROCED_RECV_MORE_NEEDED
,
/**
* In progress, need to send more data
*/
mhd_TLS_PROCED_SEND_MORE_NEEDED
,
/**
* Procedure failed
*/
mhd_TLS_PROCED_FAILED
};
#endif /* ! MHD_TLS_ENUMS_H */
+61
View File
@@ -116,6 +116,67 @@
mhd_TLS_FUNC (_conn_deinit)((c_tls))
/* ** TLS connection establishing ** */
/**
* Perform TLS handshake
* @param c_tls the connection TLS handle
* @return #mhd_TLS_PROCED_SUCCESS if completed successfully
* or other enum mhd_TlsProcedureResult values
*/
#define mhd_tls_conn_handshake(c_tls) \
mhd_TLS_FUNC (_conn_handshake)((c_tls))
/**
* Perform shutdown of TLS layer
* @param c_tls the connection TLS handle
* @return #mhd_TLS_PROCED_SUCCESS if completed successfully
* or other enum mhd_TlsProcedureResult values
*/
#define mhd_tls_conn_shutdown(c_tls) \
mhd_TLS_FUNC (_conn_shutdown)((c_tls))
/* ** Data sending and receiving over TLS connection ** */
/**
* Receive the data from the remote side over TLS connection
*
* @param c_tls the connection TLS handle
* @param buf_size the size of the @a buf buffer
* @param[out] buf the buffer to fill with the received data
* @param[out] received the pointer to variable to get the size of the data
* actually put to the @a buffer
* @return mhd_SOCKET_ERR_NO_ERROR if receive succeed (the @a received gets
* the received size) or socket error
*/
#define mhd_tls_conn_recv(c_tls,buf_size,buf,received) \
mhd_TLS_FUNC (_conn_recv)((c_tls),(buf_size),(buf),(received))
/**
* Check whether any incoming data is pending in the TLS buffers
*
* @param c_tls the connection TLS handle
* @return 'true' if any incoming remote data is already pending (the TLS recv()
* call can be performed),
* 'false' otherwise
*/
#define mhd_tls_conn_has_data_in(c_tls) \
mhd_TLS_FUNC (_conn_has_data_in)((c_tls))
/**
* Send data to the remote side over TLS connection
*
* @param c_tls the connection TLS handle
* @param buffer_size the size of the @a buffer (in bytes)
* @param buffer content of the buffer to send
* @param[out] sent the pointer to get amount of actually sent bytes
* @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets
* the sent size) or socket error
*/
#define mhd_tls_conn_send(c_tls,buf_size,buf,sent) \
mhd_TLS_FUNC (_conn_send)((c_tls),(buf_size),(buf),(sent))
/* ** General information function ** */
/**
+26 -1
View File
@@ -52,6 +52,10 @@
#include "conn_mark_ready.h"
#include "stream_process_reply.h"
#ifdef MHD_ENABLE_HTTPS
# include "mhd_tls_funcs.h"
#endif
#include "mhd_public_api.h"
@@ -822,7 +826,28 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c,
}
else
{
if (mhd_socket_shut_wr (c->sk.fd) && (! c->sk.state.rmt_shut_wr))
bool use_graceful_closing;
mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c->sk.state.discnt_err));
use_graceful_closing = true;
#ifdef MHD_ENABLE_HTTPS
if (mhd_C_HAS_TLS (c))
{
if ((0 != (((unsigned int) c->sk.ready)
& mhd_SOCKET_NET_STATE_SEND_READY))
|| c->sk.props.is_nonblck)
use_graceful_closing =
(mhd_TLS_PROCED_FAILED != mhd_tls_conn_shutdown (c->tls));
}
#endif /* MHD_ENABLE_HTTPS */
else if (1)
{
use_graceful_closing = mhd_socket_shut_wr (c->sk.fd);
if (use_graceful_closing)
use_graceful_closing = (! c->sk.state.rmt_shut_wr); /* Skip as already closed */
}
if (use_graceful_closing)
{
(void) 0; // TODO: start local lingering phase
c->stage = mhd_HTTP_STAGE_PRE_CLOSING; // TODO: start local lingering phase
+1 -3
View File
@@ -302,13 +302,11 @@ setup_reply_properties (struct MHD_Connection *restrict c)
c->rp.cntn_loc = mhd_REPLY_CNTN_LOC_IOV;
break;
case mhd_RESPONSE_CONTENT_DATA_FILE:
#if 0 // TODO: TLS support
if (use_tls)
if (mhd_C_HAS_TLS (c))
{
c->rp.cntn_loc = mhd_REPLY_CNTN_LOC_CONN_BUF;
break;
}
#endif
#ifdef MHD_USE_SENDFILE
if (r->cntn.file.use_sf)
{
+12 -20
View File
@@ -55,24 +55,13 @@
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
mhd_conn_event_loop_state_update (struct MHD_Connection *restrict c)
{
/* Do not update states of suspended connection */
mhd_assert (! c->suspended);
#ifdef MHD_ENABLE_HTTPS
mhd_assert (! mhd_C_HAS_TLS (c) || \
(mhd_CONN_STATE_TLS_CONNECTED == c->conn_state));
mhd_assert (mhd_C_HAS_TLS (c) || \
(mhd_CONN_STATE_TCP_CONNECTED == c->conn_state));
#endif /* MHD_ENABLE_HTTPS */
if (0 != (c->sk.ready & mhd_SOCKET_NET_STATE_ERROR_READY))
{
mhd_assert (0 && "Should be handled earlier");
mhd_conn_start_closing_skt_err (c);
return false;
}
#if 0 // def HTTPS_SUPPORT // TODO: implement TLS support
if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
{ /* HTTPS connection. */
switch (connection->tls_state)
{
}
}
#endif /* HTTPS_SUPPORT */
switch (c->stage)
{
case mhd_HTTP_STAGE_INIT:
@@ -288,9 +277,12 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
while (! c->suspended)
{
#ifdef HTTPS_SUPPORT
// TODO: support TLS, handshake
#endif /* HTTPS_SUPPORT */
#ifdef MHD_ENABLE_HTTPS
mhd_assert (! mhd_C_HAS_TLS (c) || \
(mhd_CONN_STATE_TLS_CONNECTED == c->conn_state));
mhd_assert (mhd_C_HAS_TLS (c) || \
(mhd_CONN_STATE_TCP_CONNECTED == c->conn_state));
#endif /* MHD_ENABLE_HTTPS */
switch (c->stage)
{
case mhd_HTTP_STAGE_INIT:
+21
View File
@@ -35,6 +35,16 @@
#include "tls_gnu_tls_lib.h"
#ifndef NDEBUG
struct mhd_TlsGnuConnDebug
{
unsigned int is_inited;
unsigned int is_tls_handshake_completed;
unsigned int is_finished;
unsigned int is_failed;
};
#endif /* ! NDEBUG */
/**
* The structure with connection-specific GnuTLS data
*/
@@ -44,6 +54,17 @@ struct mhd_TlsGnuConnData
* GnuTLS session data
*/
gnutls_session_t sess;
/**
* 'true' if received EOF (the remote side initiated shutting down)
*/
bool rmt_shut_tls_wr;
#ifndef NDEBUG
/**
* Debugging data
*/
struct mhd_TlsGnuConnDebug dbg;
#endif /* ! NDEBUG */
};
#endif /* ! MHD_TLS_GNU_CONN_DATA_H */
+207 -1
View File
@@ -312,7 +312,7 @@ static const struct MHD_StringNullable tlsgnulib_base_priorities[] = {
{0, NULL} /* Replaced with app-defined name */
,
#ifdef mhd_TLS_GNU_SUPPORTS_MULTI_KEYWORDS_PRIORITY
mhd_MSTR_INIT ("@LIBMICROHTTPD,@SYSTEM")
mhd_MSTR_INIT ("@LIBMICROHTTPD,SYSTEM")
#else
mhd_MSTR_INIT ("@LIBMICROHTTPD")
,
@@ -539,6 +539,9 @@ mhd_tls_gnu_conn_init (const struct mhd_TlsGnuDaemonData *restrict d_tls,
(void) alpn_res; /* Ignore any possible ALPN set errors */
}
#endif /* mhd_TLS_GNU_HAS_ALPN */
#ifndef NDEBUG
c_tls->dbg.is_inited = true;
#endif /* ! NDEBUG */
return true; /* Success exit point */
}
@@ -559,5 +562,208 @@ MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
mhd_tls_gnu_conn_deinit (struct mhd_TlsGnuConnData *restrict c_tls)
{
mhd_assert (NULL != c_tls->sess);
mhd_assert (c_tls->dbg.is_inited);
gnutls_deinit (c_tls->sess);
}
/* ** TLS connection establishing ** */
MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
enum mhd_TlsProcedureResult
mhd_tls_gnu_conn_handshake (struct mhd_TlsGnuConnData *restrict c_tls)
{
int res;
mhd_assert (c_tls->dbg.is_inited);
mhd_assert (! c_tls->dbg.is_tls_handshake_completed);
mhd_assert (! c_tls->dbg.is_failed);
res = gnutls_handshake (c_tls->sess);
switch (res)
{
case GNUTLS_E_SUCCESS:
#ifndef NDEBUG
c_tls->dbg.is_tls_handshake_completed = true;
#endif /* ! NDEBUG */
return mhd_TLS_PROCED_SUCCESS;
case GNUTLS_E_INTERRUPTED:
case GNUTLS_E_AGAIN:
case GNUTLS_E_WARNING_ALERT_RECEIVED: /* Ignore any warning for now */
if (1)
{
int is_sending;
is_sending = gnutls_record_get_direction (c_tls->sess);
if (GNUTLS_E_INTERRUPTED == res)
return is_sending ?
mhd_TLS_PROCED_SEND_INTERRUPTED :
mhd_TLS_PROCED_RECV_INTERRUPTED;
return is_sending ?
mhd_TLS_PROCED_SEND_MORE_NEEDED :
mhd_TLS_PROCED_RECV_MORE_NEEDED;
}
break;
default:
break;
}
#ifndef NDEBUG
c_tls->dbg.is_failed = true;
#endif /* ! NDEBUG */
return mhd_TLS_PROCED_FAILED;
}
MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
enum mhd_TlsProcedureResult
mhd_tls_gnu_conn_shutdown (struct mhd_TlsGnuConnData *restrict c_tls)
{
int res;
mhd_assert (c_tls->dbg.is_inited);
mhd_assert (c_tls->dbg.is_tls_handshake_completed);
mhd_assert (! c_tls->dbg.is_failed);
res = gnutls_bye (c_tls->sess,
c_tls->rmt_shut_tls_wr ? GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR);
switch (res)
{
case GNUTLS_E_SUCCESS:
#ifndef NDEBUG
c_tls->dbg.is_finished = true;
#endif /* ! NDEBUG */
return mhd_TLS_PROCED_SUCCESS;
case GNUTLS_E_INTERRUPTED:
case GNUTLS_E_AGAIN:
case GNUTLS_E_WARNING_ALERT_RECEIVED: /* Ignore any warning for now */
if (1)
{
int is_sending;
is_sending = gnutls_record_get_direction (c_tls->sess);
if (GNUTLS_E_INTERRUPTED == res)
return is_sending ?
mhd_TLS_PROCED_SEND_INTERRUPTED :
mhd_TLS_PROCED_RECV_INTERRUPTED;
return is_sending ?
mhd_TLS_PROCED_SEND_MORE_NEEDED :
mhd_TLS_PROCED_RECV_MORE_NEEDED;
}
break;
default:
break;
}
#ifndef NDEBUG
c_tls->dbg.is_failed = true;
#endif /* ! NDEBUG */
return mhd_TLS_PROCED_FAILED;
}
/* ** Data receiving and sending ** */
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_OUT_SIZE_ (3,2)
MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
mhd_tls_gnu_conn_recv (struct mhd_TlsGnuConnData *restrict c_tls,
size_t buf_size,
char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
size_t *restrict received)
{
ssize_t res;
mhd_assert (c_tls->dbg.is_inited);
mhd_assert (c_tls->dbg.is_tls_handshake_completed);
mhd_assert (! c_tls->dbg.is_failed);
/* Check for GnuTLS return value limitation */
if (0 > (ssize_t) buf_size)
buf_size = (ssize_t) ((~((size_t) 0u)) >> 1); /* SSIZE_MAX */
res = gnutls_record_recv (c_tls->sess,
buf,
buf_size);
if (0 >= res)
{
*received = 0;
switch (res)
{
case 0: /* Not an error */
c_tls->rmt_shut_tls_wr = true;
return mhd_SOCKET_ERR_NO_ERROR;
case GNUTLS_E_AGAIN:
return mhd_SOCKET_ERR_AGAIN;
case GNUTLS_E_INTERRUPTED:
return mhd_SOCKET_ERR_INTR;
case GNUTLS_E_PREMATURE_TERMINATION:
return mhd_SOCKET_ERR_CONNRESET;
default:
break;
}
/* Treat all other kinds of errors as hard errors */
#ifndef NDEBUG
c_tls->dbg.is_failed = true;
#endif /* ! NDEBUG */
return mhd_SOCKET_ERR_TLS;
}
*received = (size_t) res;
return mhd_SOCKET_ERR_NO_ERROR;
}
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
mhd_tls_gnu_conn_has_data_in (struct mhd_TlsGnuConnData *restrict c_tls)
{
return 0 != gnutls_record_check_pending (c_tls->sess);
}
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_IN_SIZE_ (3,2)
MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
mhd_tls_gnu_conn_send (struct mhd_TlsGnuConnData *restrict c_tls,
size_t buf_size,
const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
size_t *restrict sent)
{
ssize_t res;
mhd_assert (c_tls->dbg.is_inited);
mhd_assert (c_tls->dbg.is_tls_handshake_completed);
mhd_assert (! c_tls->dbg.is_failed);
/* Check for GnuTLS return value limitation */
if (0 > (ssize_t) buf_size)
buf_size = (ssize_t) ((~((size_t) 0u)) >> 1); /* SSIZE_MAX */
res = gnutls_record_send (c_tls->sess,
buf,
buf_size);
mhd_assert (0 != res);
if (0 > res)
{
*sent = 0;
switch (res)
{
case GNUTLS_E_AGAIN:
return mhd_SOCKET_ERR_AGAIN;
case GNUTLS_E_INTERRUPTED:
return mhd_SOCKET_ERR_INTR;
case GNUTLS_E_PREMATURE_TERMINATION:
return mhd_SOCKET_ERR_CONNRESET;
default:
break;
}
/* Treat all other kinds of errors as hard errors */
#ifndef NDEBUG
c_tls->dbg.is_failed = true;
#endif /* ! NDEBUG */
return mhd_SOCKET_ERR_TLS;
}
*sent = (size_t) res;
return mhd_SOCKET_ERR_NO_ERROR;
}
+76
View File
@@ -38,6 +38,9 @@
#include "mhd_status_code_int.h"
#include "mhd_tls_enums.h"
#include "mhd_socket_error.h"
/**
* The structure with daemon-specific GnuTLS data
*/
@@ -140,4 +143,77 @@ MHD_INTERNAL void
mhd_tls_gnu_conn_deinit (struct mhd_TlsGnuConnData *restrict c_tls)
MHD_FN_PAR_NONNULL_ALL_;
/* ** TLS connection establishing ** */
/**
* Perform TLS handshake
* @param c_tls the connection TLS handle
* @return #mhd_TLS_PROCED_SUCCESS if completed successfully
* or other enum mhd_TlsProcedureResult values
*/
MHD_INTERNAL enum mhd_TlsProcedureResult
mhd_tls_gnu_conn_handshake (struct mhd_TlsGnuConnData *restrict c_tls)
MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_;
/**
* Perform shutdown of TLS layer
* @param c_tls the connection TLS handle
* @return #mhd_TLS_PROCED_SUCCESS if completed successfully
* or other enum mhd_TlsProcedureResult values
*/
MHD_INTERNAL enum mhd_TlsProcedureResult
mhd_tls_gnu_conn_shutdown (struct mhd_TlsGnuConnData *restrict c_tls)
MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_;
/* ** Data sending and receiving over TLS connection ** */
/**
* Receive the data from the remote side over TLS connection
*
* @param c_tls the connection TLS handle
* @param buf_size the size of the @a buf buffer
* @param[out] buf the buffer to fill with the received data
* @param[out] received the pointer to variable to get the size of the data
* actually put to the @a buffer
* @return mhd_SOCKET_ERR_NO_ERROR if receive succeed (the @a received gets
* the received size) or socket error
*/
MHD_INTERNAL enum mhd_SocketError
mhd_tls_gnu_conn_recv (struct mhd_TlsGnuConnData *restrict c_tls,
size_t buf_size,
char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
size_t *restrict received)
MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4);
/**
* Check whether any incoming data is pending in the TLS buffers
*
* @param c_tls the connection TLS handle
* @return 'true' if any incoming remote data is already pending (the TLS recv()
* call can be performed),
* 'false' otherwise
*/
MHD_INTERNAL bool
mhd_tls_gnu_conn_has_data_in (struct mhd_TlsGnuConnData *restrict c_tls)
MHD_FN_PAR_NONNULL_ALL_;
/**
* Send data to the remote side over TLS connection
*
* @param c_tls the connection TLS handle
* @param buffer_size the size of the @a buffer (in bytes)
* @param buffer content of the buffer to send
* @param[out] sent the pointer to get amount of actually sent bytes
* @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets
* the sent size) or socket error
*/
MHD_INTERNAL enum mhd_SocketError
mhd_tls_gnu_conn_send (struct mhd_TlsGnuConnData *restrict c_tls,
size_t buf_size,
const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
size_t *restrict sent)
MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4);
#endif /* ! MHD_TLS_GNU_FUNCS_H */