Coverage Report

Created: 2025-08-24 06:26

/src/mhd2/src/mhd2/conn_tls_check.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
  This file is part of GNU libmicrohttpd
3
  Copyright (C) 2024 Evgeny Grin (Karlson2k)
4
5
  GNU libmicrohttpd is free software; you can redistribute it and/or
6
  modify it under the terms of the GNU Lesser General Public
7
  License as published by the Free Software Foundation; either
8
  version 2.1 of the License, or (at your option) any later version.
9
10
  GNU libmicrohttpd is distributed in the hope that it will be useful,
11
  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
  Lesser General Public License for more details.
14
15
  You should have received a copy of the GNU Lesser General Public
16
  License along with this library; if not, write to the Free Software
17
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18
19
*/
20
21
/**
22
 * @file src/mhd2/conn_tls_handshake.c
23
 * @brief  The implementation of connection TLS handling functions
24
 * @author Karlson2k (Evgeny Grin)
25
 */
26
27
#include "mhd_sys_options.h"
28
29
#include "conn_tls_check.h"
30
31
#include "mhd_assert.h"
32
#include "mhd_unreachable.h"
33
34
#include "mhd_daemon.h"
35
#include "mhd_connection.h"
36
37
#include "mhd_socket_error_funcs.h"
38
#include "daemon_logger.h"
39
40
#include "mhd_tls_funcs.h"
41
42
#include "conn_mark_ready.h"
43
#include "stream_funcs.h"
44
#include "stream_process_states.h"
45
46
47
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ enum mhd_ConnTlsCheckResult
48
mhd_conn_tls_check (struct MHD_Connection *restrict c)
49
0
{
50
0
  mhd_assert (mhd_C_HAS_TLS (c));
51
0
  mhd_assert (mhd_D_HAS_TLS (c->daemon));
52
0
  mhd_assert ((mhd_CONN_STATE_TLS_HANDSHAKE_RECV == c->conn_state) || \
53
0
              (mhd_CONN_STATE_TLS_HANDSHAKE_SEND == c->conn_state) || \
54
0
              (mhd_CONN_STATE_TLS_CONNECTED == c->conn_state));
55
56
0
  if (mhd_CONN_STATE_TLS_CONNECTED == c->conn_state)
57
0
    return mhd_CONN_TLS_CHECK_OK; /* TLS is already connected */
58
59
0
  if (0 != (mhd_SOCKET_NET_STATE_ERROR_READY & c->sk.ready))
60
0
  {
61
    /* Some socket error has been detected. Do not try to handshake. */
62
0
    if (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err)
63
0
      c->sk.state.discnt_err = mhd_socket_error_get_from_socket (c->sk.fd);
64
0
    mhd_conn_start_closing_skt_err (c);
65
0
    return mhd_CONN_TLS_CHECK_BROKEN;
66
0
  }
67
  /* Check whether the socket is ready for the required send/recv operation */
68
0
  if (0 == (((mhd_CONN_FLAG_RECV | mhd_CONN_FLAG_SEND)
69
0
             & ((unsigned int) c->conn_state)
70
0
             & ((unsigned int) c->sk.ready))))
71
0
    return mhd_CONN_TLS_CHECK_HANDSHAKING;
72
73
0
  switch (mhd_tls_conn_handshake (c->tls))
74
0
  {
75
0
  case mhd_TLS_PROCED_SUCCESS:
76
0
    c->conn_state = mhd_CONN_STATE_TLS_CONNECTED;
77
0
    if (! c->sk.props.is_nonblck)
78
0
    {
79
      /* The socket is blocking,
80
         probably all available data has been processed already. */
81
0
      c->sk.ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' and 'send-ready' */
82
0
                    (((unsigned int) c->sk.ready)
83
0
                     & (~(enum mhd_SocketNetState)
84
0
                        mhd_SOCKET_NET_STATE_SEND_READY)
85
0
                     & (~(enum mhd_SocketNetState)
86
0
                        mhd_SOCKET_NET_STATE_RECV_READY));
87
0
    }
88
    /* TLS is connected now, set event loop state based on HTTP protocol.
89
       Some early application-level data could be processing in this round. */
90
0
    mhd_conn_event_loop_state_update (c);
91
92
0
    return mhd_CONN_TLS_CHECK_OK;
93
0
    break;
94
0
  case mhd_TLS_PROCED_RECV_MORE_NEEDED:
95
0
    c->sk.ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' */
96
0
                  (((unsigned int) c->sk.ready)
97
0
                   & (~(enum mhd_SocketNetState)
98
0
                      mhd_SOCKET_NET_STATE_RECV_READY));
99
0
    mhd_FALLTHROUGH;
100
  /* Intentional fallthrough */
101
0
  case mhd_TLS_PROCED_RECV_INTERRUPTED:
102
0
    c->conn_state = mhd_CONN_STATE_TLS_HANDSHAKE_RECV;
103
0
    c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV;
104
0
    break;
105
0
  case mhd_TLS_PROCED_SEND_MORE_NEEDED:
106
0
    c->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
107
0
                  (((unsigned int) c->sk.ready)
108
0
                   & (~(enum mhd_SocketNetState)
109
0
                      mhd_SOCKET_NET_STATE_SEND_READY));
110
0
    mhd_FALLTHROUGH;
111
  /* Intentional fallthrough */
112
0
  case mhd_TLS_PROCED_SEND_INTERRUPTED:
113
0
    c->conn_state = mhd_CONN_STATE_TLS_HANDSHAKE_SEND;
114
0
    c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND;
115
0
    break;
116
0
  case mhd_TLS_PROCED_FAILED:
117
0
    c->conn_state = mhd_CONN_STATE_TLS_FAILED;
118
0
    mhd_LOG_MSG (c->daemon, \
119
0
                 MHD_SC_TLS_CONNECTION_HANDSHAKED_FAILED, \
120
0
                 "Failed to perform TLS handshake on the new connection");
121
0
    c->sk.state.discnt_err = mhd_SOCKET_ERR_TLS;
122
0
    mhd_conn_start_closing_skt_err (c);
123
0
    return mhd_CONN_TLS_CHECK_BROKEN;
124
0
    break;
125
0
  default:
126
0
    mhd_assert (0 && "Should be unreachable");
127
0
    mhd_UNREACHABLE ();
128
0
    return mhd_CONN_TLS_CHECK_BROKEN;
129
0
  }
130
131
0
  mhd_conn_mark_ready_update (c);
132
0
  return mhd_CONN_TLS_CHECK_HANDSHAKING;
133
0
}