summaryrefslogtreecommitdiffstatsabout
path: root/src/gnutls_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gnutls_io.c')
-rw-r--r--src/gnutls_io.c1367
1 files changed, 700 insertions, 667 deletions
diff --git a/src/gnutls_io.c b/src/gnutls_io.c
index 174a424..37b73e7 100644
--- a/src/gnutls_io.c
+++ b/src/gnutls_io.c
@@ -32,67 +32,64 @@
32 alloc) 32 alloc)
33 33
34static apr_status_t gnutls_io_filter_error(ap_filter_t * f, 34static apr_status_t gnutls_io_filter_error(ap_filter_t * f,
35 apr_bucket_brigade * bb, 35 apr_bucket_brigade * bb,
36 apr_status_t status) 36 apr_status_t status)
37{ 37{
38 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx; 38 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx;
39 apr_bucket *bucket; 39 apr_bucket *bucket;
40 40
41 switch (status) { 41 switch (status) {
42 case HTTP_BAD_REQUEST: 42 case HTTP_BAD_REQUEST:
43 /* log the situation */ 43 /* log the situation */
44 ap_log_error(APLOG_MARK, APLOG_INFO, 0, 44 ap_log_error(APLOG_MARK, APLOG_INFO, 0,
45 f->c->base_server, 45 f->c->base_server,
46 "GnuTLS handshake failed: HTTP spoken on HTTPS port; " 46 "GnuTLS handshake failed: HTTP spoken on HTTPS port; "
47 "trying to send HTML error page"); 47 "trying to send HTML error page");
48 48
49 ctxt->status = -1; 49 ctxt->status = -1;
50 50
51 /* fake the request line */ 51 /* fake the request line */
52 bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc); 52 bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc);
53 break; 53 break;
54 54
55 default: 55 default:
56 return status; 56 return status;
57 } 57 }
58 58
59 APR_BRIGADE_INSERT_TAIL(bb, bucket); 59 APR_BRIGADE_INSERT_TAIL(bb, bucket);
60 bucket = apr_bucket_eos_create(f->c->bucket_alloc); 60 bucket = apr_bucket_eos_create(f->c->bucket_alloc);
61 APR_BRIGADE_INSERT_TAIL(bb, bucket); 61 APR_BRIGADE_INSERT_TAIL(bb, bucket);
62 62
63 return APR_SUCCESS; 63 return APR_SUCCESS;
64} 64}
65 65
66static int char_buffer_read(mgs_char_buffer_t * buffer, char *in, 66static int char_buffer_read(mgs_char_buffer_t * buffer, char *in, int inl)
67 int inl)
68{ 67{
69 if (!buffer->length) { 68 if (!buffer->length) {
70 return 0; 69 return 0;
71 } 70 }
72 71
73 if (buffer->length > inl) { 72 if (buffer->length > inl) {
74 /* we have have enough to fill the caller's buffer */ 73 /* we have have enough to fill the caller's buffer */
75 memmove(in, buffer->value, inl); 74 memmove(in, buffer->value, inl);
76 buffer->value += inl; 75 buffer->value += inl;
77 buffer->length -= inl; 76 buffer->length -= inl;
78 } 77 } else {
79 else { 78 /* swallow remainder of the buffer */
80 /* swallow remainder of the buffer */ 79 memmove(in, buffer->value, buffer->length);
81 memmove(in, buffer->value, buffer->length); 80 inl = buffer->length;
82 inl = buffer->length; 81 buffer->value = NULL;
83 buffer->value = NULL; 82 buffer->length = 0;
84 buffer->length = 0; 83 }
85 } 84
86 85 return inl;
87 return inl;
88} 86}
89 87
90static int char_buffer_write(mgs_char_buffer_t * buffer, char *in, 88static int char_buffer_write(mgs_char_buffer_t * buffer, char *in, int inl)
91 int inl)
92{ 89{
93 buffer->value = in; 90 buffer->value = in;
94 buffer->length = inl; 91 buffer->length = inl;
95 return inl; 92 return inl;
96} 93}
97 94
98/** 95/**
@@ -101,679 +98,715 @@ static int char_buffer_write(mgs_char_buffer_t * buffer, char *in,
101 * proceeds. It will read at most *len bytes. 98 * proceeds. It will read at most *len bytes.
102 */ 99 */
103static apr_status_t brigade_consume(apr_bucket_brigade * bb, 100static apr_status_t brigade_consume(apr_bucket_brigade * bb,
104 apr_read_type_e block, 101 apr_read_type_e block,
105 char *c, apr_size_t * len) 102 char *c, apr_size_t * len)
106{ 103{
107 apr_size_t actual = 0; 104 apr_size_t actual = 0;
108 apr_status_t status = APR_SUCCESS; 105 apr_status_t status = APR_SUCCESS;
109 106
110 while (!APR_BRIGADE_EMPTY(bb)) { 107 while (!APR_BRIGADE_EMPTY(bb)) {
111 apr_bucket *b = APR_BRIGADE_FIRST(bb); 108 apr_bucket *b = APR_BRIGADE_FIRST(bb);
112 const char *str; 109 const char *str;
113 apr_size_t str_len; 110 apr_size_t str_len;
114 apr_size_t consume; 111 apr_size_t consume;
115 112
116 /* Justin points out this is an http-ism that might 113 /* Justin points out this is an http-ism that might
117 * not fit if brigade_consume is added to APR. Perhaps 114 * not fit if brigade_consume is added to APR. Perhaps
118 * apr_bucket_read(eos_bucket) should return APR_EOF? 115 * apr_bucket_read(eos_bucket) should return APR_EOF?
119 * Then this becomes mainline instead of a one-off. 116 * Then this becomes mainline instead of a one-off.
120 */ 117 */
121 if (APR_BUCKET_IS_EOS(b)) { 118 if (APR_BUCKET_IS_EOS(b)) {
122 status = APR_EOF; 119 status = APR_EOF;
123 break; 120 break;
124 } 121 }
125 122
126 /* The reason I'm not offering brigade_consume yet 123 /* The reason I'm not offering brigade_consume yet
127 * across to apr-util is that the following call 124 * across to apr-util is that the following call
128 * illustrates how borked that API really is. For 125 * illustrates how borked that API really is. For
129 * this sort of case (caller provided buffer) it 126 * this sort of case (caller provided buffer) it
130 * would be much more trivial for apr_bucket_consume 127 * would be much more trivial for apr_bucket_consume
131 * to do all the work that follows, based on the 128 * to do all the work that follows, based on the
132 * particular characteristics of the bucket we are 129 * particular characteristics of the bucket we are
133 * consuming here. 130 * consuming here.
134 */ 131 */
135 status = apr_bucket_read(b, &str, &str_len, block); 132 status = apr_bucket_read(b, &str, &str_len, block);
136 133
137 if (status != APR_SUCCESS) { 134 if (status != APR_SUCCESS) {
138 if (APR_STATUS_IS_EOF(status)) { 135 if (APR_STATUS_IS_EOF(status)) {
139 /* This stream bucket was consumed */ 136 /* This stream bucket was consumed */
140 apr_bucket_delete(b); 137 apr_bucket_delete(b);
141 continue; 138 continue;
142 } 139 }
143 break; 140 break;
144 } 141 }
145 142
146 if (str_len > 0) { 143 if (str_len > 0) {
147 /* Do not block once some data has been consumed */ 144 /* Do not block once some data has been consumed */
148 block = APR_NONBLOCK_READ; 145 block = APR_NONBLOCK_READ;
149 146
150 /* Assure we don't overflow. */ 147 /* Assure we don't overflow. */
151 consume = (str_len + actual > *len) ? *len - actual : str_len; 148 consume =
152 149 (str_len + actual >
153 memcpy(c, str, consume); 150 *len) ? *len - actual : str_len;
154 151
155 c += consume; 152 memcpy(c, str, consume);
156 actual += consume; 153
157 154 c += consume;
158 if (consume >= b->length) { 155 actual += consume;
159 /* This physical bucket was consumed */ 156
160 apr_bucket_delete(b); 157 if (consume >= b->length) {
161 } 158 /* This physical bucket was consumed */
162 else { 159 apr_bucket_delete(b);
163 /* Only part of this physical bucket was consumed */ 160 } else {
164 b->start += consume; 161 /* Only part of this physical bucket was consumed */
165 b->length -= consume; 162 b->start += consume;
166 } 163 b->length -= consume;
167 } 164 }
168 else if (b->length == 0) { 165 } else if (b->length == 0) {
169 apr_bucket_delete(b); 166 apr_bucket_delete(b);
170 } 167 }
171 168
172 /* This could probably be actual == *len, but be safe from stray 169 /* This could probably be actual == *len, but be safe from stray
173 * photons. */ 170 * photons. */
174 if (actual >= *len) { 171 if (actual >= *len) {
175 break; 172 break;
176 } 173 }
177 } 174 }
178 175
179 *len = actual; 176 *len = actual;
180 return status; 177 return status;
181} 178}
182 179
183 180
184static apr_status_t gnutls_io_input_read(mgs_handle_t * ctxt, 181static apr_status_t gnutls_io_input_read(mgs_handle_t * ctxt,
185 char *buf, apr_size_t * len) 182 char *buf, apr_size_t * len)
186{ 183{
187 apr_size_t wanted = *len; 184 apr_size_t wanted = *len;
188 apr_size_t bytes = 0; 185 apr_size_t bytes = 0;
189 int rc; 186 int rc;
190 187
191 *len = 0; 188 *len = 0;
192 189
193 /* If we have something leftover from last time, try that first. */ 190 /* If we have something leftover from last time, try that first. */
194 if ((bytes = char_buffer_read(&ctxt->input_cbuf, buf, wanted))) { 191 if ((bytes = char_buffer_read(&ctxt->input_cbuf, buf, wanted))) {
195 *len = bytes; 192 *len = bytes;
196 if (ctxt->input_mode == AP_MODE_SPECULATIVE) { 193 if (ctxt->input_mode == AP_MODE_SPECULATIVE) {
197 /* We want to rollback this read. */ 194 /* We want to rollback this read. */
198 if (ctxt->input_cbuf.length > 0) { 195 if (ctxt->input_cbuf.length > 0) {
199 ctxt->input_cbuf.value -= bytes; 196 ctxt->input_cbuf.value -= bytes;
200 ctxt->input_cbuf.length += bytes; 197 ctxt->input_cbuf.length += bytes;
201 } 198 } else {
202 else { 199 char_buffer_write(&ctxt->input_cbuf, buf,
203 char_buffer_write(&ctxt->input_cbuf, buf, (int) bytes); 200 (int) bytes);
204 } 201 }
205 return APR_SUCCESS; 202 return APR_SUCCESS;
206 } 203 }
207 /* This could probably be *len == wanted, but be safe from stray 204 /* This could probably be *len == wanted, but be safe from stray
208 * photons. 205 * photons.
209 */ 206 */
210 if (*len >= wanted) { 207 if (*len >= wanted) {
211 return APR_SUCCESS; 208 return APR_SUCCESS;
212 } 209 }
213 if (ctxt->input_mode == AP_MODE_GETLINE) { 210 if (ctxt->input_mode == AP_MODE_GETLINE) {
214 if (memchr(buf, APR_ASCII_LF, *len)) { 211 if (memchr(buf, APR_ASCII_LF, *len)) {
215 return APR_SUCCESS; 212 return APR_SUCCESS;
216 } 213 }
217 } 214 } else {
218 else { 215 /* Down to a nonblock pattern as we have some data already
219 /* Down to a nonblock pattern as we have some data already 216 */
220 */ 217 ctxt->input_block = APR_NONBLOCK_READ;
221 ctxt->input_block = APR_NONBLOCK_READ; 218 }
222 } 219 }
223 } 220
224 221 if (ctxt->session == NULL) {
225 if (ctxt->session == NULL) { 222 return APR_EGENERAL;
226 return APR_EGENERAL; 223 }
227 } 224
228 225 while (1) {
229 while (1) { 226
230 227 rc = gnutls_record_recv(ctxt->session, buf + bytes,
231 rc = gnutls_record_recv(ctxt->session, buf + bytes, wanted - bytes); 228 wanted - bytes);
232 229
233 if (rc > 0) { 230 if (rc > 0) {
234 *len += rc; 231 *len += rc;
235 if (ctxt->input_mode == AP_MODE_SPECULATIVE) { 232 if (ctxt->input_mode == AP_MODE_SPECULATIVE) {
236 /* We want to rollback this read. */ 233 /* We want to rollback this read. */
237 char_buffer_write(&ctxt->input_cbuf, buf, rc); 234 char_buffer_write(&ctxt->input_cbuf, buf,
238 } 235 rc);
239 return ctxt->input_rc; 236 }
240 } 237 return ctxt->input_rc;
241 else if (rc == 0) { 238 } else if (rc == 0) {
242 /* If EAGAIN, we will loop given a blocking read, 239 /* If EAGAIN, we will loop given a blocking read,
243 * otherwise consider ourselves at EOF. 240 * otherwise consider ourselves at EOF.
244 */ 241 */
245 if (APR_STATUS_IS_EAGAIN(ctxt->input_rc) 242 if (APR_STATUS_IS_EAGAIN(ctxt->input_rc)
246 || APR_STATUS_IS_EINTR(ctxt->input_rc)) { 243 || APR_STATUS_IS_EINTR(ctxt->input_rc)) {
247 /* Already read something, return APR_SUCCESS instead. 244 /* Already read something, return APR_SUCCESS instead.
248 * On win32 in particular, but perhaps on other kernels, 245 * On win32 in particular, but perhaps on other kernels,
249 * a blocking call isn't 'always' blocking. 246 * a blocking call isn't 'always' blocking.
250 */ 247 */
251 if (*len > 0) { 248 if (*len > 0) {
252 ctxt->input_rc = APR_SUCCESS; 249 ctxt->input_rc = APR_SUCCESS;
253 break; 250 break;
254 } 251 }
255 if (ctxt->input_block == APR_NONBLOCK_READ) { 252 if (ctxt->input_block == APR_NONBLOCK_READ) {
256 break; 253 break;
257 } 254 }
258 } 255 } else {
259 else { 256 if (*len > 0) {
260 if (*len > 0) { 257 ctxt->input_rc = APR_SUCCESS;
261 ctxt->input_rc = APR_SUCCESS; 258 } else {
262 } 259 ctxt->input_rc = APR_EOF;
263 else { 260 }
264 ctxt->input_rc = APR_EOF; 261 break;
265 } 262 }
266 break; 263 } else { /* (rc < 0) */
267 } 264
268 } 265 if (rc == GNUTLS_E_REHANDSHAKE) {
269 else { /* (rc < 0) */ 266 /* A client has asked for a new Hankshake. Currently, we don't do it */
270 267 ap_log_error(APLOG_MARK, APLOG_INFO,
271 if (rc == GNUTLS_E_REHANDSHAKE) { 268 ctxt->input_rc,
272 /* A client has asked for a new Hankshake. Currently, we don't do it */ 269 ctxt->c->base_server,
273 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc, 270 "GnuTLS: Error reading data. Client Requested a New Handshake."
274 ctxt->c->base_server, 271 " (%d) '%s'", rc,
275 "GnuTLS: Error reading data. Client Requested a New Handshake." 272 gnutls_strerror(rc));
276 " (%d) '%s'", rc, gnutls_strerror(rc)); 273 } else if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
277 } 274 rc = gnutls_alert_get(ctxt->session);
278 else if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { 275 ap_log_error(APLOG_MARK, APLOG_INFO,
279 rc = gnutls_alert_get(ctxt->session); 276 ctxt->input_rc,
280 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc, 277 ctxt->c->base_server,
281 ctxt->c->base_server, 278 "GnuTLS: Warning Alert From Client: "
282 "GnuTLS: Warning Alert From Client: " 279 " (%d) '%s'", rc,
283 " (%d) '%s'", rc, gnutls_alert_get_name(rc)); 280 gnutls_alert_get_name(rc));
284 } 281 } else if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
285 else if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { 282 rc = gnutls_alert_get(ctxt->session);
286 rc = gnutls_alert_get(ctxt->session); 283 ap_log_error(APLOG_MARK, APLOG_INFO,
287 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc, 284 ctxt->input_rc,
288 ctxt->c->base_server, 285 ctxt->c->base_server,
289 "GnuTLS: Fatal Alert From Client: " 286 "GnuTLS: Fatal Alert From Client: "
290 "(%d) '%s'", rc, gnutls_alert_get_name(rc)); 287 "(%d) '%s'", rc,
291 ctxt->input_rc = APR_EGENERAL; 288 gnutls_alert_get_name(rc));
292 break; 289 ctxt->input_rc = APR_EGENERAL;
293 } 290 break;
294 else { 291 } else {
295 /* Some Other Error. Report it. Die. */ 292 /* Some Other Error. Report it. Die. */
296 if(gnutls_error_is_fatal(rc)) { 293 if (gnutls_error_is_fatal(rc)) {
297 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc, 294 ap_log_error(APLOG_MARK,
298 ctxt->c->base_server, 295 APLOG_INFO,
299 "GnuTLS: Error reading data. (%d) '%s'", rc, 296 ctxt->input_rc,
300 gnutls_strerror(rc)); 297 ctxt->c->base_server,
301 } 298 "GnuTLS: Error reading data. (%d) '%s'",
302 else if(*len > 0) { 299 rc,
303 ctxt->input_rc = APR_SUCCESS; 300 gnutls_strerror(rc));
304 break; 301 } else if (*len > 0) {
305 } 302 ctxt->input_rc = APR_SUCCESS;
306 } 303 break;
307 304 }
308 if (ctxt->input_rc == APR_SUCCESS) { 305 }
309 ctxt->input_rc = APR_EGENERAL; 306
310 } 307 if (ctxt->input_rc == APR_SUCCESS) {
311 break; 308 ctxt->input_rc = APR_EGENERAL;
312 } 309 }
313 } 310 break;
314 return ctxt->input_rc; 311 }
312 }
313 return ctxt->input_rc;
315} 314}
316 315
317static apr_status_t gnutls_io_input_getline(mgs_handle_t * ctxt, 316static apr_status_t gnutls_io_input_getline(mgs_handle_t * ctxt,
318 char *buf, apr_size_t * len) 317 char *buf, apr_size_t * len)
319{ 318{
320 const char *pos = NULL; 319 const char *pos = NULL;
321 apr_status_t status; 320 apr_status_t status;
322 apr_size_t tmplen = *len, buflen = *len, offset = 0; 321 apr_size_t tmplen = *len, buflen = *len, offset = 0;
323 322
324 *len = 0; 323 *len = 0;
325 324
326 while (tmplen > 0) { 325 while (tmplen > 0) {
327 status = gnutls_io_input_read(ctxt, buf + offset, &tmplen); 326 status = gnutls_io_input_read(ctxt, buf + offset, &tmplen);
328 327
329 if (status != APR_SUCCESS) { 328 if (status != APR_SUCCESS) {
330 return status; 329 return status;
331 } 330 }
332 331
333 *len += tmplen; 332 *len += tmplen;
334 333
335 if ((pos = memchr(buf, APR_ASCII_LF, *len))) { 334 if ((pos = memchr(buf, APR_ASCII_LF, *len))) {
336 break; 335 break;
337 } 336 }
338 337
339 offset += tmplen; 338 offset += tmplen;
340 tmplen = buflen - offset; 339 tmplen = buflen - offset;
341 } 340 }
342 341
343 if (pos) { 342 if (pos) {
344 char *value; 343 char *value;
345 int length; 344 int length;
346 apr_size_t bytes = pos - buf; 345 apr_size_t bytes = pos - buf;
347 346
348 bytes += 1; 347 bytes += 1;
349 value = buf + bytes; 348 value = buf + bytes;
350 length = *len - bytes; 349 length = *len - bytes;
351 350
352 char_buffer_write(&ctxt->input_cbuf, value, length); 351 char_buffer_write(&ctxt->input_cbuf, value, length);
353 352
354 *len = bytes; 353 *len = bytes;
355 } 354 }
356 355
357 return APR_SUCCESS; 356 return APR_SUCCESS;
358} 357}
359 358
360#define HANDSHAKE_MAX_TRIES 1024 359#define HANDSHAKE_MAX_TRIES 1024
361static int gnutls_do_handshake(mgs_handle_t * ctxt) 360static int gnutls_do_handshake(mgs_handle_t * ctxt)
362{ 361{
363 int ret; 362 int ret;
364 int errcode; 363 int errcode;
365 int maxtries = HANDSHAKE_MAX_TRIES; 364 int maxtries = HANDSHAKE_MAX_TRIES;
366 365
367 if (ctxt->status != 0 || ctxt->session == NULL) { 366 if (ctxt->status != 0 || ctxt->session == NULL) {
368 return -1; 367 return -1;
369 } 368 }
370 369
371tryagain: 370 tryagain:
372 do { 371 do {
373 ret = gnutls_handshake(ctxt->session); 372 ret = gnutls_handshake(ctxt->session);
374 maxtries--; 373 maxtries--;
375 } while ((ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) && maxtries > 0); 374 } while ((ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
376 375 && maxtries > 0);
377 if (maxtries < 1) { 376
378 ctxt->status = -1; 377 if (maxtries < 1) {
378 ctxt->status = -1;
379#if USING_2_1_RECENT 379#if USING_2_1_RECENT
380 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctxt->c, 380 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctxt->c,
381 "GnuTLS: Handshake Failed. Hit Maximum Attempts"); 381 "GnuTLS: Handshake Failed. Hit Maximum Attempts");
382#else 382#else
383 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctxt->c->base_server, 383 ap_log_error(APLOG_MARK, APLOG_ERR, 0,
384 "GnuTLS: Handshake Failed. Hit Maximum Attempts"); 384 ctxt->c->base_server,
385 "GnuTLS: Handshake Failed. Hit Maximum Attempts");
385#endif 386#endif
386 if (ctxt->session) { 387 if (ctxt->session) {
387 gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL, 388 gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL,
388 gnutls_error_to_alert(GNUTLS_E_INTERNAL_ERROR, NULL)); 389 gnutls_error_to_alert
389 gnutls_deinit(ctxt->session); 390 (GNUTLS_E_INTERNAL_ERROR, NULL));
390 } 391 gnutls_deinit(ctxt->session);
391 ctxt->session = NULL; 392 }
392 return -1; 393 ctxt->session = NULL;
393 } 394 return -1;
394 395 }
395 if (ret < 0) { 396
396 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED 397 if (ret < 0) {
397 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { 398 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
398 errcode = gnutls_alert_get(ctxt->session); 399 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
399 ap_log_error(APLOG_MARK, APLOG_INFO, 0, ctxt->c->base_server, 400 errcode = gnutls_alert_get(ctxt->session);
400 "GnuTLS: Hanshake Alert (%d) '%s'.", errcode, 401 ap_log_error(APLOG_MARK, APLOG_INFO, 0,
401 gnutls_alert_get_name(errcode)); 402 ctxt->c->base_server,
402 } 403 "GnuTLS: Hanshake Alert (%d) '%s'.",
403 404 errcode,
404 if (!gnutls_error_is_fatal(ret)) { 405 gnutls_alert_get_name(errcode));
405 ap_log_error(APLOG_MARK, APLOG_INFO, 0, ctxt->c->base_server, 406 }
406 "GnuTLS: Non-Fatal Handshake Error: (%d) '%s'", ret, 407
407 gnutls_strerror(ret)); 408 if (!gnutls_error_is_fatal(ret)) {
408 goto tryagain; 409 ap_log_error(APLOG_MARK, APLOG_INFO, 0,
409 } 410 ctxt->c->base_server,
411 "GnuTLS: Non-Fatal Handshake Error: (%d) '%s'",
412 ret, gnutls_strerror(ret));
413 goto tryagain;
414 }
410#if USING_2_1_RECENT 415#if USING_2_1_RECENT
411 ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c, 416 ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c,
412 "GnuTLS: Handshake Failed (%d) '%s'", ret, 417 "GnuTLS: Handshake Failed (%d) '%s'", ret,
413 gnutls_strerror(ret)); 418 gnutls_strerror(ret));
414#else 419#else
415 ap_log_error(APLOG_MARK, APLOG_INFO, 0, ctxt->c->base_server, 420 ap_log_error(APLOG_MARK, APLOG_INFO, 0,
416 "GnuTLS: Handshake Failed (%d) '%s'", ret, 421 ctxt->c->base_server,
417 gnutls_strerror(ret)); 422 "GnuTLS: Handshake Failed (%d) '%s'", ret,
423 gnutls_strerror(ret));
418#endif 424#endif
419 ctxt->status = -1; 425 ctxt->status = -1;
420 if (ctxt->session) { 426 if (ctxt->session) {
421 gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL, 427 gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL,
422 gnutls_error_to_alert(ret, NULL)); 428 gnutls_error_to_alert(ret,
423 gnutls_deinit(ctxt->session); 429 NULL));
424 } 430 gnutls_deinit(ctxt->session);
425 ctxt->session = NULL; 431 }
426 return ret; 432 ctxt->session = NULL;
427 } 433 return ret;
428 else { 434 } else {
429 /* all done with the handshake */ 435 /* all done with the handshake */
430 ctxt->status = 1; 436 ctxt->status = 1;
431 /* If the session was resumed, we did not set the correct 437 /* If the session was resumed, we did not set the correct
432 * server_rec in ctxt->sc. Go Find it. (ick!) 438 * server_rec in ctxt->sc. Go Find it. (ick!)
433 */ 439 */
434 if (gnutls_session_is_resumed(ctxt->session)) { 440 if (gnutls_session_is_resumed(ctxt->session)) {
435 mgs_srvconf_rec* sc; 441 mgs_srvconf_rec *sc;
436 sc = mgs_find_sni_server(ctxt->session); 442 sc = mgs_find_sni_server(ctxt->session);
437 if (sc) { 443 if (sc) {
438 ctxt->sc = sc; 444 ctxt->sc = sc;
439 } 445 }
440 } 446 }
441 return 0; 447 return 0;
442 } 448 }
443} 449}
444 450
445int mgs_rehandshake(mgs_handle_t * ctxt) 451int mgs_rehandshake(mgs_handle_t * ctxt)
446{ 452{
447 int rv; 453 int rv;
448 454
449 if (ctxt->session == NULL) 455 if (ctxt->session == NULL)
450 return -1; 456 return -1;
451 457
452 rv = gnutls_rehandshake(ctxt->session); 458 rv = gnutls_rehandshake(ctxt->session);
453 459
454 if (rv != 0) { 460 if (rv != 0) {
455 /* the client did not want to rehandshake. goodbye */ 461 /* the client did not want to rehandshake. goodbye */
456 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ctxt->c->base_server, 462 ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
457 "GnuTLS: Client Refused Rehandshake request."); 463 ctxt->c->base_server,
458 return -1; 464 "GnuTLS: Client Refused Rehandshake request.");
459 } 465 return -1;
460 466 }
461 ctxt->status = 0; 467
462 468 ctxt->status = 0;
463 rv = gnutls_do_handshake(ctxt); 469
464 470 rv = gnutls_do_handshake(ctxt);
465 return rv; 471
472 return rv;
466} 473}
467 474
468 475
469apr_status_t mgs_filter_input(ap_filter_t* f, 476apr_status_t mgs_filter_input(ap_filter_t * f,
470 apr_bucket_brigade * bb, 477 apr_bucket_brigade * bb,
471 ap_input_mode_t mode, 478 ap_input_mode_t mode,
472 apr_read_type_e block, 479 apr_read_type_e block, apr_off_t readbytes)
473 apr_off_t readbytes)
474{ 480{
475 apr_status_t status = APR_SUCCESS; 481 apr_status_t status = APR_SUCCESS;
476 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx; 482 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx;
477 apr_size_t len = sizeof(ctxt->input_buffer); 483 apr_size_t len = sizeof(ctxt->input_buffer);
478 484
479 if (f->c->aborted) { 485 if (f->c->aborted) {
480 apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc); 486 apr_bucket *bucket =
481 APR_BRIGADE_INSERT_TAIL(bb, bucket); 487 apr_bucket_eos_create(f->c->bucket_alloc);
482 return APR_ECONNABORTED; 488 APR_BRIGADE_INSERT_TAIL(bb, bucket);
483 } 489 return APR_ECONNABORTED;
484 490 }
485 if (ctxt->status == 0) { 491
486 gnutls_do_handshake(ctxt); 492 if (ctxt->status == 0) {
487 } 493 gnutls_do_handshake(ctxt);
488 494 }
489 if (ctxt->status < 0) { 495
490 return ap_get_brigade(f->next, bb, mode, block, readbytes); 496 if (ctxt->status < 0) {
491 } 497 return ap_get_brigade(f->next, bb, mode, block, readbytes);
492 498 }
493 /* XXX: we don't currently support anything other than these modes. */ 499
494 if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE && 500 /* XXX: we don't currently support anything other than these modes. */
495 mode != AP_MODE_SPECULATIVE && mode != AP_MODE_INIT) { 501 if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE &&
496 return APR_ENOTIMPL; 502 mode != AP_MODE_SPECULATIVE && mode != AP_MODE_INIT) {
497 } 503 return APR_ENOTIMPL;
498 504 }
499 ctxt->input_mode = mode; 505
500 ctxt->input_block = block; 506 ctxt->input_mode = mode;
501 507 ctxt->input_block = block;
502 if (ctxt->input_mode == AP_MODE_READBYTES || 508
503 ctxt->input_mode == AP_MODE_SPECULATIVE) { 509 if (ctxt->input_mode == AP_MODE_READBYTES ||
504 /* Err. This is bad. readbytes *can* be a 64bit int! len.. is NOT */ 510 ctxt->input_mode == AP_MODE_SPECULATIVE) {
505 if (readbytes < len) { 511 /* Err. This is bad. readbytes *can* be a 64bit int! len.. is NOT */
506 len = (apr_size_t) readbytes; 512 if (readbytes < len) {
507 } 513 len = (apr_size_t) readbytes;
508 status = gnutls_io_input_read(ctxt, ctxt->input_buffer, &len); 514 }
509 } 515 status =
510 else if (ctxt->input_mode == AP_MODE_GETLINE) { 516 gnutls_io_input_read(ctxt, ctxt->input_buffer, &len);
511 status = gnutls_io_input_getline(ctxt, ctxt->input_buffer, &len); 517 } else if (ctxt->input_mode == AP_MODE_GETLINE) {
512 } 518 status =
513 else { 519 gnutls_io_input_getline(ctxt, ctxt->input_buffer,
514 /* We have no idea what you are talking about, so return an error. */ 520 &len);
515 return APR_ENOTIMPL; 521 } else {
516 } 522 /* We have no idea what you are talking about, so return an error. */
517 523 return APR_ENOTIMPL;
518 if (status != APR_SUCCESS) { 524 }
519 return gnutls_io_filter_error(f, bb, status); 525
520 } 526 if (status != APR_SUCCESS) {
521 527 return gnutls_io_filter_error(f, bb, status);
522 /* Create a transient bucket out of the decrypted data. */ 528 }
523 if (len > 0) { 529
524 apr_bucket *bucket = 530 /* Create a transient bucket out of the decrypted data. */
525 apr_bucket_transient_create(ctxt->input_buffer, len, 531 if (len > 0) {
526 f->c->bucket_alloc); 532 apr_bucket *bucket =
527 APR_BRIGADE_INSERT_TAIL(bb, bucket); 533 apr_bucket_transient_create(ctxt->input_buffer, len,
528 } 534 f->c->bucket_alloc);
529 535 APR_BRIGADE_INSERT_TAIL(bb, bucket);
530 return status; 536 }
537
538 return status;
531} 539}
532 540
533apr_status_t mgs_filter_output(ap_filter_t * f, 541apr_status_t mgs_filter_output(ap_filter_t * f, apr_bucket_brigade * bb)
534 apr_bucket_brigade * bb)
535{ 542{
536 apr_size_t ret; 543 apr_size_t ret;
537 apr_bucket* e; 544 apr_bucket *e;
538 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx; 545 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx;
539 apr_status_t status = APR_SUCCESS; 546 apr_status_t status = APR_SUCCESS;
540 apr_read_type_e rblock = APR_NONBLOCK_READ; 547 apr_read_type_e rblock = APR_NONBLOCK_READ;
541 548
542 if (f->c->aborted) { 549 if (f->c->aborted) {
543 apr_brigade_cleanup(bb); 550 apr_brigade_cleanup(bb);
544 return APR_ECONNABORTED; 551 return APR_ECONNABORTED;
545 } 552 }
546 553
547 if (ctxt->status == 0) { 554 if (ctxt->status == 0) {
548 gnutls_do_handshake(ctxt); 555 gnutls_do_handshake(ctxt);
549 } 556 }
550 557
551 if (ctxt->status < 0) { 558 if (ctxt->status < 0) {
552 return ap_pass_brigade(f->next, bb); 559 return ap_pass_brigade(f->next, bb);
553 } 560 }
554 561
555 while (!APR_BRIGADE_EMPTY(bb)) { 562 while (!APR_BRIGADE_EMPTY(bb)) {
556 apr_bucket *bucket = APR_BRIGADE_FIRST(bb); 563 apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
557 564
558 if (AP_BUCKET_IS_EOC(bucket)) { 565 if (AP_BUCKET_IS_EOC(bucket)) {
559 if (ctxt->session != NULL) { 566 if (ctxt->session != NULL) {
560 do { 567 do {
561 ret = gnutls_bye( ctxt->session, GNUTLS_SHUT_WR); 568 ret =
562 } while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); 569 gnutls_bye(ctxt->session,
563 } 570 GNUTLS_SHUT_WR);
564 571 } while (ret == GNUTLS_E_INTERRUPTED
565 apr_bucket_copy(bucket, &e); 572 || ret == GNUTLS_E_AGAIN);
566 APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e); 573 }
567 574
568 if ((status = ap_pass_brigade(f->next, ctxt->output_bb)) != APR_SUCCESS) { 575 apr_bucket_copy(bucket, &e);
569 apr_brigade_cleanup(ctxt->output_bb); 576 APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e);
570 return status; 577
571 } 578 if ((status =
572 579 ap_pass_brigade(f->next,
573 apr_brigade_cleanup(ctxt->output_bb); 580 ctxt->output_bb)) !=
574 if (ctxt->session) { 581 APR_SUCCESS) {
575 gnutls_deinit(ctxt->session); 582 apr_brigade_cleanup(ctxt->output_bb);
576 ctxt->session = NULL; 583 return status;
577 } 584 }
578 continue; 585
579 } else if (APR_BUCKET_IS_FLUSH(bucket) || APR_BUCKET_IS_EOS(bucket)) { 586 apr_brigade_cleanup(ctxt->output_bb);
580 587 if (ctxt->session) {
581 apr_bucket_copy(bucket, &e); 588 gnutls_deinit(ctxt->session);
582 APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e); 589 ctxt->session = NULL;
583 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { 590 }
584 apr_brigade_cleanup(ctxt->output_bb); 591 continue;
585 return status; 592 } else if (APR_BUCKET_IS_FLUSH(bucket)
586 } 593 || APR_BUCKET_IS_EOS(bucket)) {
587 594
588 apr_brigade_cleanup(ctxt->output_bb); 595 apr_bucket_copy(bucket, &e);
589 continue; 596 APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e);
590 } 597 if ((status =
591 else { 598 ap_pass_brigade(f->next,
592 /* filter output */ 599 bb)) != APR_SUCCESS) {
593 const char *data; 600 apr_brigade_cleanup(ctxt->output_bb);
594 apr_size_t len; 601 return status;
595 602 }
596 status = apr_bucket_read(bucket, &data, &len, rblock); 603
597 604 apr_brigade_cleanup(ctxt->output_bb);
598 if (APR_STATUS_IS_EAGAIN(status)) { 605 continue;
599 rblock = APR_BLOCK_READ; 606 } else {
600 continue; /* and try again with a blocking read. */ 607 /* filter output */
601 } 608 const char *data;
602 609 apr_size_t len;
603 rblock = APR_NONBLOCK_READ; 610
604 611 status =
605 if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) { 612 apr_bucket_read(bucket, &data, &len, rblock);
606 break; 613
607 } 614 if (APR_STATUS_IS_EAGAIN(status)) {
608 615 rblock = APR_BLOCK_READ;
609 if (len > 0) { 616 continue; /* and try again with a blocking read. */
610 617 }
611 if (ctxt->session == NULL) { 618
612 ret = GNUTLS_E_INVALID_REQUEST; 619 rblock = APR_NONBLOCK_READ;
613 } else { 620
614 do { 621 if (!APR_STATUS_IS_EOF(status)
615 ret = gnutls_record_send(ctxt->session, data, len); 622 && (status != APR_SUCCESS)) {
616 } 623 break;
617 while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); 624 }
618 } 625
619 626 if (len > 0) {
620 if (ret < 0) { 627
621 /* error sending output */ 628 if (ctxt->session == NULL) {
622 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->output_rc, 629 ret = GNUTLS_E_INVALID_REQUEST;
623 ctxt->c->base_server, 630 } else {
624 "GnuTLS: Error writing data." 631 do {
625 " (%d) '%s'", (int)ret, gnutls_strerror(ret)); 632 ret =
626 if (ctxt->output_rc == APR_SUCCESS) { 633 gnutls_record_send
627 ctxt->output_rc = APR_EGENERAL; 634 (ctxt->session, data,
628 } 635 len);
629 } 636 }
630 else if (ret != len) { 637 while (ret == GNUTLS_E_INTERRUPTED
631 /* Not able to send the entire bucket, 638 || ret == GNUTLS_E_AGAIN);
632 split it and send it again. */ 639 }
633 apr_bucket_split(bucket, ret); 640
634 } 641 if (ret < 0) {
635 } 642 /* error sending output */
636 643 ap_log_error(APLOG_MARK,
637 apr_bucket_delete(bucket); 644 APLOG_INFO,
638 645 ctxt->output_rc,
639 if (ctxt->output_rc != APR_SUCCESS) { 646 ctxt->c->base_server,
640 break; 647 "GnuTLS: Error writing data."
641 } 648 " (%d) '%s'",
642 } 649 (int) ret,
643 } 650 gnutls_strerror(ret));
644 651 if (ctxt->output_rc == APR_SUCCESS) {
645 return status; 652 ctxt->output_rc =
653 APR_EGENERAL;
654 }
655 } else if (ret != len) {
656 /* Not able to send the entire bucket,
657 split it and send it again. */
658 apr_bucket_split(bucket, ret);
659 }
660 }
661
662 apr_bucket_delete(bucket);
663
664 if (ctxt->output_rc != APR_SUCCESS) {
665 break;
666 }
667 }
668 }
669
670 return status;
646} 671}
647 672
648ssize_t mgs_transport_read(gnutls_transport_ptr_t ptr, 673ssize_t mgs_transport_read(gnutls_transport_ptr_t ptr,
649 void *buffer, size_t len) 674 void *buffer, size_t len)
650{ 675{
651 mgs_handle_t *ctxt = ptr; 676 mgs_handle_t *ctxt = ptr;
652 apr_status_t rc; 677 apr_status_t rc;
653 apr_size_t in = len; 678 apr_size_t in = len;
654 apr_read_type_e block = ctxt->input_block; 679 apr_read_type_e block = ctxt->input_block;
655 680
656 ctxt->input_rc = APR_SUCCESS; 681 ctxt->input_rc = APR_SUCCESS;
657 682
658 /* If Len = 0, we don't do anything. */ 683 /* If Len = 0, we don't do anything. */
659 if (!len) 684 if (!len)
660 return 0; 685 return 0;
661 686
662 if (!ctxt->input_bb) { 687 if (!ctxt->input_bb) {
663 ctxt->input_rc = APR_EOF; 688 ctxt->input_rc = APR_EOF;
664 return -1; 689 return -1;
665 } 690 }
666 691
667 if (APR_BRIGADE_EMPTY(ctxt->input_bb)) { 692 if (APR_BRIGADE_EMPTY(ctxt->input_bb)) {
668 693
669 rc = ap_get_brigade(ctxt->input_filter->next, ctxt->input_bb, 694 rc = ap_get_brigade(ctxt->input_filter->next,
670 AP_MODE_READBYTES, ctxt->input_block, in); 695 ctxt->input_bb, AP_MODE_READBYTES,
671 696 ctxt->input_block, in);
672 /* Not a problem, there was simply no data ready yet. 697
673 */ 698 /* Not a problem, there was simply no data ready yet.
674 if (APR_STATUS_IS_EAGAIN(rc) || APR_STATUS_IS_EINTR(rc) 699 */
675 || (rc == APR_SUCCESS && APR_BRIGADE_EMPTY(ctxt->input_bb))) { 700 if (APR_STATUS_IS_EAGAIN(rc) || APR_STATUS_IS_EINTR(rc)
676 701 || (rc == APR_SUCCESS
677 if (APR_STATUS_IS_EOF(ctxt->input_rc)) { 702 && APR_BRIGADE_EMPTY(ctxt->input_bb))) {
678 return 0; 703
679 } else { 704 if (APR_STATUS_IS_EOF(ctxt->input_rc)) {
680 if (ctxt->session) 705 return 0;
681 gnutls_transport_set_errno(ctxt->session, EINTR); 706 } else {
682 return -1; 707 if (ctxt->session)
683 } 708 gnutls_transport_set_errno(ctxt->
684 } 709 session,
685 710 EINTR);
686 711 return -1;
687 if (rc != APR_SUCCESS) { 712 }
688 /* Unexpected errors discard the brigade */ 713 }
689 apr_brigade_cleanup(ctxt->input_bb); 714
690 ctxt->input_bb = NULL; 715
691 return -1; 716 if (rc != APR_SUCCESS) {
692 } 717 /* Unexpected errors discard the brigade */
693 } 718 apr_brigade_cleanup(ctxt->input_bb);
694 719 ctxt->input_bb = NULL;
695 ctxt->input_rc = brigade_consume(ctxt->input_bb, block, buffer, &len); 720 return -1;
696 721 }
697 if (ctxt->input_rc == APR_SUCCESS) { 722 }
698 return (ssize_t) len; 723
699 } 724 ctxt->input_rc =
700 725 brigade_consume(ctxt->input_bb, block, buffer, &len);
701 if (APR_STATUS_IS_EAGAIN(ctxt->input_rc) 726
702 || APR_STATUS_IS_EINTR(ctxt->input_rc)) { 727 if (ctxt->input_rc == APR_SUCCESS) {
703 if (len == 0) { 728 return (ssize_t) len;
704 if (ctxt->session) 729 }
705 gnutls_transport_set_errno(ctxt->session, EINTR); 730
706 return -1; 731 if (APR_STATUS_IS_EAGAIN(ctxt->input_rc)
707 } 732 || APR_STATUS_IS_EINTR(ctxt->input_rc)) {
708 733 if (len == 0) {
709 return (ssize_t) len; 734 if (ctxt->session)
710 } 735 gnutls_transport_set_errno(ctxt->session,
711 736 EINTR);
712 /* Unexpected errors and APR_EOF clean out the brigade. 737 return -1;
713 * Subsequent calls will return APR_EOF. 738 }
714 */ 739
715 apr_brigade_cleanup(ctxt->input_bb); 740 return (ssize_t) len;
716 ctxt->input_bb = NULL; 741 }
717 742
718 if (APR_STATUS_IS_EOF(ctxt->input_rc) && len) { 743 /* Unexpected errors and APR_EOF clean out the brigade.
719 /* Provide the results of this read pass, 744 * Subsequent calls will return APR_EOF.
720 * without resetting the BIO retry_read flag 745 */
721 */ 746 apr_brigade_cleanup(ctxt->input_bb);
722 return (ssize_t) len; 747 ctxt->input_bb = NULL;
723 } 748
724 749 if (APR_STATUS_IS_EOF(ctxt->input_rc) && len) {
725 return -1; 750 /* Provide the results of this read pass,
751 * without resetting the BIO retry_read flag
752 */
753 return (ssize_t) len;
754 }
755
756 return -1;
726} 757}
727 758
728 759
729static ssize_t write_flush(mgs_handle_t * ctxt) 760static ssize_t write_flush(mgs_handle_t * ctxt)
730{ 761{
731 apr_bucket *e; 762 apr_bucket *e;
732 763
733 if (!(ctxt->output_blen || ctxt->output_length)) { 764 if (!(ctxt->output_blen || ctxt->output_length)) {
734 ctxt->output_rc = APR_SUCCESS; 765 ctxt->output_rc = APR_SUCCESS;
735 return 1; 766 return 1;
736 } 767 }
737 768
738 if (ctxt->output_blen) { 769 if (ctxt->output_blen) {
739 e = apr_bucket_transient_create(ctxt->output_buffer, 770 e = apr_bucket_transient_create(ctxt->output_buffer,
740 ctxt->output_blen, 771 ctxt->output_blen,
741 ctxt->output_bb->bucket_alloc); 772 ctxt->output_bb->
742 /* we filled this buffer first so add it to the 773 bucket_alloc);
743 * head of the brigade 774 /* we filled this buffer first so add it to the
744 */ 775 * head of the brigade
745 APR_BRIGADE_INSERT_HEAD(ctxt->output_bb, e); 776 */
746 ctxt->output_blen = 0; 777 APR_BRIGADE_INSERT_HEAD(ctxt->output_bb, e);
747 } 778 ctxt->output_blen = 0;
748 779 }
749 ctxt->output_length = 0; 780
750 e = apr_bucket_flush_create(ctxt->output_bb->bucket_alloc); 781 ctxt->output_length = 0;
751 APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e); 782 e = apr_bucket_flush_create(ctxt->output_bb->bucket_alloc);
752 783 APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e);
753 ctxt->output_rc = ap_pass_brigade(ctxt->output_filter->next, 784
754 ctxt->output_bb); 785 ctxt->output_rc = ap_pass_brigade(ctxt->output_filter->next,
755 /* clear the brigade to be ready for next time */ 786 ctxt->output_bb);
756 apr_brigade_cleanup(ctxt->output_bb); 787 /* clear the brigade to be ready for next time */
757 788 apr_brigade_cleanup(ctxt->output_bb);
758 return (ctxt->output_rc == APR_SUCCESS) ? 1 : -1; 789
790 return (ctxt->output_rc == APR_SUCCESS) ? 1 : -1;
759} 791}
760 792
761ssize_t mgs_transport_write(gnutls_transport_ptr_t ptr, 793ssize_t mgs_transport_write(gnutls_transport_ptr_t ptr,
762 const void *buffer, size_t len) 794 const void *buffer, size_t len)
763{ 795{
764 mgs_handle_t *ctxt = ptr; 796 mgs_handle_t *ctxt = ptr;
765 797
766 /* pass along the encrypted data 798 /* pass along the encrypted data
767 * need to flush since we're using SSL's malloc-ed buffer 799 * need to flush since we're using SSL's malloc-ed buffer
768 * which will be overwritten once we leave here 800 * which will be overwritten once we leave here
769 */ 801 */
770 apr_bucket *bucket = apr_bucket_transient_create(buffer, len, 802 apr_bucket *bucket = apr_bucket_transient_create(buffer, len,
771 ctxt->output_bb->bucket_alloc); 803 ctxt->output_bb->
772 ctxt->output_length += len; 804 bucket_alloc);
773 APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, bucket); 805 ctxt->output_length += len;
774 806 APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, bucket);
775 if (write_flush(ctxt) < 0) { 807
776 return -1; 808 if (write_flush(ctxt) < 0) {
777 } 809 return -1;
778 return len; 810 }
811 return len;
779} 812}