GNU libmicrohttpd  0.9.59
connection_https.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2007, 2008, 2010 Daniel Pittman and Christian Grothoff
4 
5  This library 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  This library 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 
29 #include "internal.h"
30 #include "connection.h"
31 #include "connection_https.h"
32 #include "memorypool.h"
33 #include "response.h"
34 #include "mhd_mono_clock.h"
35 #include <gnutls/gnutls.h>
36 
37 
47 static ssize_t
48 recv_tls_adapter (struct MHD_Connection *connection,
49  void *other,
50  size_t i)
51 {
52  ssize_t res;
53 
54  if (i > SSIZE_MAX)
55  i = SSIZE_MAX;
56 
57  res = gnutls_record_recv (connection->tls_session,
58  other,
59  i);
60  if ( (GNUTLS_E_AGAIN == res) ||
61  (GNUTLS_E_INTERRUPTED == res) )
62  {
63 #ifdef EPOLL_SUPPORT
64  if (GNUTLS_E_AGAIN == res)
65  connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
66 #endif
67  /* Any network errors means that buffer is empty. */
68  connection->tls_read_ready = false;
69  return MHD_ERR_AGAIN_;
70  }
71  if (res < 0)
72  {
73  /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
74  disrupted); interpret as a hard error */
75  connection->tls_read_ready = false;
76  return MHD_ERR_NOTCONN_;
77  }
78 
79 #ifdef EPOLL_SUPPORT
80  /* Unlike non-TLS connections, do not reset "read-ready" if
81  * received amount smaller than provided amount, as TLS
82  * connections may receive data by fixed-size chunks. */
83 #endif /* EPOLL_SUPPORT */
84 
85  /* Check whether TLS buffers still have some unread data. */
86  connection->tls_read_ready = ( ((size_t)res == i) &&
87  (0 != gnutls_record_check_pending (connection->tls_session)) );
88  return res;
89 }
90 
91 
101 static ssize_t
102 send_tls_adapter (struct MHD_Connection *connection,
103  const void *other,
104  size_t i)
105 {
106  ssize_t res;
107 
108  if (i > SSIZE_MAX)
109  i = SSIZE_MAX;
110 
111  res = gnutls_record_send (connection->tls_session,
112  other,
113  i);
114  if ( (GNUTLS_E_AGAIN == res) ||
115  (GNUTLS_E_INTERRUPTED == res) )
116  {
117 #ifdef EPOLL_SUPPORT
118  if (GNUTLS_E_AGAIN == res)
119  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
120 #endif
121  return MHD_ERR_AGAIN_;
122  }
123  if (res < 0)
124  {
125  /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
126  disrupted); interpret as a hard error */
127  return MHD_ERR_NOTCONN_;
128  }
129 #ifdef EPOLL_SUPPORT
130  /* Unlike non-TLS connections, do not reset "write-ready" if
131  * sent amount smaller than provided amount, as TLS
132  * connections may break data into smaller parts for sending. */
133 #endif /* EPOLL_SUPPORT */
134  return res;
135 }
136 
137 
147 bool
149 {
150  int ret;
151 
152  if ((MHD_TLS_CONN_INIT == connection->tls_state) ||
153  (MHD_TLS_CONN_HANDSHAKING == connection->tls_state))
154  {
155  ret = gnutls_handshake (connection->tls_session);
156  if (ret == GNUTLS_E_SUCCESS)
157  {
158  /* set connection TLS state to enable HTTP processing */
159  connection->tls_state = MHD_TLS_CONN_CONNECTED;
160  MHD_update_last_activity_ (connection);
161  return true;
162  }
163  if ( (GNUTLS_E_AGAIN == ret) ||
164  (GNUTLS_E_INTERRUPTED == ret) )
165  {
166  connection->tls_state = MHD_TLS_CONN_HANDSHAKING;
167  /* handshake not done */
168  return false;
169  }
170  /* handshake failed */
171  connection->tls_state = MHD_TLS_CONN_TLS_FAILED;
172 #ifdef HAVE_MESSAGES
173  MHD_DLOG (connection->daemon,
174  _("Error: received handshake message out of context\n"));
175 #endif
176  MHD_connection_close_ (connection,
178  return false;
179  }
180  return true;
181 }
182 
183 
190 void
192 {
193  connection->recv_cls = &recv_tls_adapter;
194  connection->send_cls = &send_tls_adapter;
195 }
196 
197 
204 bool
206 {
207  if (MHD_TLS_CONN_WR_CLOSED > connection->tls_state)
208  {
209  const int res =
210  gnutls_bye(connection->tls_session, GNUTLS_SHUT_WR);
211  if (GNUTLS_E_SUCCESS == res)
212  {
213  connection->tls_state = MHD_TLS_CONN_WR_CLOSED;
214  return true;
215  }
216  if ((GNUTLS_E_AGAIN == res) ||
217  (GNUTLS_E_INTERRUPTED == res))
218  {
219  connection->tls_state = MHD_TLS_CONN_WR_CLOSING;
220  return true;
221  }
222  else
223  connection->tls_state = MHD_TLS_CONN_TLS_FAILED;
224  }
225  return false;
226 }
227 
228 /* end of connection_https.c */
#define MHD_ERR_NOTCONN_
Definition: connection.h:47
Methods for managing connections.
static ssize_t recv_tls_adapter(struct MHD_Connection *connection, void *other, size_t i)
void MHD_connection_close_(struct MHD_Connection *connection, enum MHD_RequestTerminationCode termination_code)
Definition: connection.c:936
Methods for managing response objects.
void MHD_update_last_activity_(struct MHD_Connection *connection)
Definition: connection.c:2784
struct MHD_Daemon * daemon
Definition: internal.h:650
#define MHD_ERR_AGAIN_
Definition: connection.h:36
void MHD_set_https_callbacks(struct MHD_Connection *connection)
Methods for managing connections.
ReceiveCallback recv_cls
Definition: internal.h:938
internal shared structures
internal monotonic clock functions implementations
bool MHD_run_tls_handshake_(struct MHD_Connection *connection)
static ssize_t send_tls_adapter(struct MHD_Connection *connection, const void *other, size_t i)
TransmitCallback send_cls
Definition: internal.h:943
#define _(String)
Definition: mhd_options.h:42
bool MHD_tls_connection_shutdown(struct MHD_Connection *connection)
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...