Changeset e02dd8c in mod_gnutls for src/gnutls_io.c


Ignore:
Timestamp:
Oct 25, 2010, 3:21:04 PM (9 years ago)
Author:
Nikos Mavrogiannopoulos <nmav@…>
Branches:
debian/master, debian/stretch-backports, jessie-backports, master, msva, upstream
Children:
b59327c
Parents:
62def2f
Message:

indented code

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_io.c

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