mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
GnuTLS communication: the last part
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user