GNU libmicrohttpd  0.9.70
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 (
88  connection->tls_session)) );
89  return res;
90 }
91 
92 
102 ssize_t
103 send_tls_adapter (struct MHD_Connection *connection,
104  const void *other,
105  size_t i)
106 {
107  ssize_t res;
108 
109  if (i > SSIZE_MAX)
110  i = SSIZE_MAX;
111 
112  res = gnutls_record_send (connection->tls_session,
113  other,
114  i);
115  if ( (GNUTLS_E_AGAIN == res) ||
116  (GNUTLS_E_INTERRUPTED == res) )
117  {
118 #ifdef EPOLL_SUPPORT
119  if (GNUTLS_E_AGAIN == res)
120  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
121 #endif
122  return MHD_ERR_AGAIN_;
123  }
124  if (res < 0)
125  {
126  /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
127  disrupted); interpret as a hard error */
128  return MHD_ERR_NOTCONN_;
129  }
130 #ifdef EPOLL_SUPPORT
131  /* Unlike non-TLS connections, do not reset "write-ready" if
132  * sent amount smaller than provided amount, as TLS
133  * connections may break data into smaller parts for sending. */
134 #endif /* EPOLL_SUPPORT */
135  return res;
136 }
137 
138 
148 bool
150 {
151  int ret;
152 
153  if ((MHD_TLS_CONN_INIT == connection->tls_state) ||
154  (MHD_TLS_CONN_HANDSHAKING == connection->tls_state))
155  {
156  ret = gnutls_handshake (connection->tls_session);
157  if (ret == GNUTLS_E_SUCCESS)
158  {
159  /* set connection TLS state to enable HTTP processing */
160  connection->tls_state = MHD_TLS_CONN_CONNECTED;
161  MHD_update_last_activity_ (connection);
162  return true;
163  }
164  if ( (GNUTLS_E_AGAIN == ret) ||
165  (GNUTLS_E_INTERRUPTED == ret) )
166  {
167  connection->tls_state = MHD_TLS_CONN_HANDSHAKING;
168  /* handshake not done */
169  return false;
170  }
171  /* handshake failed */
172  connection->tls_state = MHD_TLS_CONN_TLS_FAILED;
173 #ifdef HAVE_MESSAGES
174  MHD_DLOG (connection->daemon,
175  _ ("Error: received handshake message out of context\n"));
176 #endif
177  MHD_connection_close_ (connection,
179  return false;
180  }
181  return true;
182 }
183 
184 
191 void
193 {
194  connection->recv_cls = &recv_tls_adapter;
195  connection->send_cls = &send_tls_adapter;
196 }
197 
198 
205 bool
207 {
208  if (MHD_TLS_CONN_WR_CLOSED > connection->tls_state)
209  {
210  const int res =
211  gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR);
212  if (GNUTLS_E_SUCCESS == res)
213  {
214  connection->tls_state = MHD_TLS_CONN_WR_CLOSED;
215  return true;
216  }
217  if ((GNUTLS_E_AGAIN == res) ||
218  (GNUTLS_E_INTERRUPTED == res))
219  {
220  connection->tls_state = MHD_TLS_CONN_WR_CLOSING;
221  return true;
222  }
223  else
224  connection->tls_state = MHD_TLS_CONN_TLS_FAILED;
225  }
226  return false;
227 }
228 
229 
230 /* end of connection_https.c */
MHD_Connection::recv_cls
ReceiveCallback recv_cls
Definition: internal.h:706
_
#define _(String)
Definition: mhd_options.h:42
MHD_TLS_CONN_WR_CLOSING
@ MHD_TLS_CONN_WR_CLOSING
Definition: internal.h:548
MHD_Connection::tls_read_ready
bool tls_read_ready
Definition: internal.h:769
MHD_EPOLL_STATE_WRITE_READY
@ MHD_EPOLL_STATE_WRITE_READY
Definition: internal.h:606
MHD_ERR_AGAIN_
#define MHD_ERR_AGAIN_
Definition: internal.h:1863
memorypool.h
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...
MHD_run_tls_handshake_
bool MHD_run_tls_handshake_(struct MHD_Connection *connection)
Definition: connection_https.c:149
connection_https.h
Methods for managing connections.
response.h
Methods for managing response objects.
recv_tls_adapter
static ssize_t recv_tls_adapter(struct MHD_Connection *connection, void *other, size_t i)
Definition: connection_https.c:48
internal.h
internal shared structures
MHD_connection_close_
void MHD_connection_close_(struct MHD_Connection *connection, enum MHD_RequestTerminationCode rtc)
Definition: connection_close.c:83
MHD_TLS_CONN_CONNECTED
@ MHD_TLS_CONN_CONNECTED
Definition: internal.h:547
MHD_Connection::send_cls
TransmitCallback send_cls
Definition: internal.h:711
MHD_TLS_CONN_TLS_FAILED
@ MHD_TLS_CONN_TLS_FAILED
Definition: internal.h:552
mhd_mono_clock.h
internal monotonic clock functions implementations
MHD_TLS_CONN_WR_CLOSED
@ MHD_TLS_CONN_WR_CLOSED
Definition: internal.h:549
send_tls_adapter
ssize_t send_tls_adapter(struct MHD_Connection *connection, const void *other, size_t i)
Definition: connection_https.c:103
MHD_TLS_CONN_HANDSHAKING
@ MHD_TLS_CONN_HANDSHAKING
Definition: internal.h:546
SSIZE_MAX
#define SSIZE_MAX
Definition: mhd_limits.h:111
MHD_update_last_activity_
void MHD_update_last_activity_(struct MHD_Connection *connection)
Definition: connection_options.c:88
connection.h
Methods for managing connections.
MHD_EPOLL_STATE_READ_READY
@ MHD_EPOLL_STATE_READ_READY
Definition: internal.h:600
MHD_Connection::daemon
struct MHD_Daemon * daemon
Definition: internal.h:675
MHD_REQUEST_TERMINATED_WITH_ERROR
@ MHD_REQUEST_TERMINATED_WITH_ERROR
Definition: microhttpd.h:1823
MHD_Connection
Definition: internal.h:633
MHD_ERR_NOTCONN_
#define MHD_ERR_NOTCONN_
Definition: internal.h:1874
MHD_tls_connection_shutdown
bool MHD_tls_connection_shutdown(struct MHD_Connection *connection)
Definition: connection_https.c:206
MHD_TLS_CONN_INIT
@ MHD_TLS_CONN_INIT
Definition: internal.h:545
MHD_set_https_callbacks
void MHD_set_https_callbacks(struct MHD_Connection *connection)
Definition: connection_https.c:192