Changeset e183628 in mod_gnutls for src/gnutls_io.c


Ignore:
Timestamp:
Sep 19, 2011, 11:58:43 PM (8 years ago)
Author:
Dash Shendy <neuromancer@…>
Branches:
debian/master, debian/stretch-backports, jessie-backports, master, msva, upstream
Children:
c7c2ad2
Parents:
6223319
Message:

Updated Copyright Headers & Formatting

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_io.c

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