int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t len,
                       size_t *written)
{
    int i;
    SSL3_BUFFER *wb = s->rlayer.wbuf;
    size_t currbuf = 0;
    size_t tmpwrit = 0;
    if ((s->rlayer.wpend_tot > len)
        || ((s->rlayer.wpend_buf != buf) &&
            !(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER))
        || (s->rlayer.wpend_type != type)) {
        SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BAD_WRITE_RETRY);
        return -1;
    }
    for (;;) {
        if (SSL3_BUFFER_get_left(&wb[currbuf]) == 0
            && currbuf < s->rlayer.numwpipes - 1) {
            currbuf++;
            continue;
        }
        clear_sys_error();
        if (s->wbio != NULL) {
            s->rwstate = SSL_WRITING;
            i = BIO_write(s->wbio, (char *)
                          &(SSL3_BUFFER_get_buf(&wb[currbuf])
                            [SSL3_BUFFER_get_offset(&wb[currbuf])]),
                          (unsigned int)SSL3_BUFFER_get_left(&wb[currbuf]));
            if (i >= 0)
                tmpwrit = i;
        } else {
            SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BIO_NOT_SET);
            i = -1;
        }
        if (i > 0 && tmpwrit == SSL3_BUFFER_get_left(&wb[currbuf])) {
            SSL3_BUFFER_set_left(&wb[currbuf], 0);
            SSL3_BUFFER_add_offset(&wb[currbuf], tmpwrit);
            if (currbuf + 1 < s->rlayer.numwpipes)
                continue;
            s->rwstate = SSL_NOTHING;
            *written = s->rlayer.wpend_ret;
            return 1;
        } else if (i <= 0) {
            if (SSL_IS_DTLS(s)) {
                SSL3_BUFFER_set_left(&wb[currbuf], 0);
            }
            return -1;
        }
        SSL3_BUFFER_add_offset(&wb[currbuf], tmpwrit);
        SSL3_BUFFER_sub_left(&wb[currbuf], tmpwrit);
    }
}
['static SUB_STATE_RETURN write_state_machine(SSL *s)\n{\n    OSSL_STATEM *st = &s->statem;\n    int ret;\n    WRITE_TRAN(*transition) (SSL *s);\n    WORK_STATE(*pre_work) (SSL *s, WORK_STATE wst);\n    WORK_STATE(*post_work) (SSL *s, WORK_STATE wst);\n    int (*get_construct_message_f) (SSL *s, WPACKET *pkt,\n                                    int (**confunc) (SSL *s, WPACKET *pkt),\n                                    int *mt);\n    void (*cb) (const SSL *ssl, int type, int val) = NULL;\n    int (*confunc) (SSL *s, WPACKET *pkt);\n    int mt;\n    WPACKET pkt;\n    cb = get_callback(s);\n    if (s->server) {\n        transition = ossl_statem_server_write_transition;\n        pre_work = ossl_statem_server_pre_work;\n        post_work = ossl_statem_server_post_work;\n        get_construct_message_f = ossl_statem_server_construct_message;\n    } else {\n        transition = ossl_statem_client_write_transition;\n        pre_work = ossl_statem_client_pre_work;\n        post_work = ossl_statem_client_post_work;\n        get_construct_message_f = ossl_statem_client_construct_message;\n    }\n    while (1) {\n        switch (st->write_state) {\n        case WRITE_STATE_TRANSITION:\n            if (cb != NULL) {\n                if (s->server)\n                    cb(s, SSL_CB_ACCEPT_LOOP, 1);\n                else\n                    cb(s, SSL_CB_CONNECT_LOOP, 1);\n            }\n            switch (transition(s)) {\n            case WRITE_TRAN_CONTINUE:\n                st->write_state = WRITE_STATE_PRE_WORK;\n                st->write_state_work = WORK_MORE_A;\n                break;\n            case WRITE_TRAN_FINISHED:\n                return SUB_STATE_FINISHED;\n                break;\n            case WRITE_TRAN_ERROR:\n                return SUB_STATE_ERROR;\n            }\n            break;\n        case WRITE_STATE_PRE_WORK:\n            switch (st->write_state_work = pre_work(s, st->write_state_work)) {\n            case WORK_ERROR:\n            case WORK_MORE_A:\n            case WORK_MORE_B:\n                return SUB_STATE_ERROR;\n            case WORK_FINISHED_CONTINUE:\n                st->write_state = WRITE_STATE_SEND;\n                break;\n            case WORK_FINISHED_STOP:\n                return SUB_STATE_END_HANDSHAKE;\n            }\n            if (!WPACKET_init(&pkt, s->init_buf)\n                    || !get_construct_message_f(s, &pkt, &confunc, &mt)\n                    || !ssl_set_handshake_header(s, &pkt, mt)\n                    || (confunc != NULL && !confunc(s, &pkt))\n                    || !ssl_close_construct_packet(s, &pkt, mt)\n                    || !WPACKET_finish(&pkt)) {\n                WPACKET_cleanup(&pkt);\n                ossl_statem_set_error(s);\n                return SUB_STATE_ERROR;\n            }\n        case WRITE_STATE_SEND:\n            if (SSL_IS_DTLS(s) && st->use_timer) {\n                dtls1_start_timer(s);\n            }\n            ret = statem_do_write(s);\n            if (ret <= 0) {\n                return SUB_STATE_ERROR;\n            }\n            st->write_state = WRITE_STATE_POST_WORK;\n            st->write_state_work = WORK_MORE_A;\n        case WRITE_STATE_POST_WORK:\n            switch (st->write_state_work = post_work(s, st->write_state_work)) {\n            case WORK_ERROR:\n            case WORK_MORE_A:\n            case WORK_MORE_B:\n                return SUB_STATE_ERROR;\n            case WORK_FINISHED_CONTINUE:\n                st->write_state = WRITE_STATE_TRANSITION;\n                break;\n            case WORK_FINISHED_STOP:\n                return SUB_STATE_END_HANDSHAKE;\n            }\n            break;\n        default:\n            return SUB_STATE_ERROR;\n        }\n    }\n}', 'static int statem_do_write(SSL *s)\n{\n    OSSL_STATEM *st = &s->statem;\n    if (st->hand_state == TLS_ST_CW_CHANGE\n        || st->hand_state == TLS_ST_SW_CHANGE) {\n        if (SSL_IS_DTLS(s))\n            return dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);\n        else\n            return ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);\n    } else {\n        return ssl_do_write(s);\n    }\n}', 'int ssl3_do_write(SSL *s, int type)\n{\n    int ret;\n    size_t written = 0;\n    ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off],\n                           s->init_num, &written);\n    if (ret < 0)\n        return (-1);\n    if (type == SSL3_RT_HANDSHAKE)\n        if (!ssl3_finish_mac(s,\n                             (unsigned char *)&s->init_buf->data[s->init_off],\n                             written))\n            return -1;\n    if (written == s->init_num) {\n        if (s->msg_callback)\n            s->msg_callback(1, s->version, type, s->init_buf->data,\n                            (size_t)(s->init_off + s->init_num), s,\n                            s->msg_callback_arg);\n        return (1);\n    }\n    s->init_off += written;\n    s->init_num -= written;\n    return (0);\n}', 'int ssl3_write_bytes(SSL *s, int type, const void *buf_, size_t len,\n                     size_t *written)\n{\n    const unsigned char *buf = buf_;\n    size_t tot;\n    size_t n, split_send_fragment, maxpipes;\n#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK\n    size_t max_send_fragment, nw;\n#endif\n    SSL3_BUFFER *wb = &s->rlayer.wbuf[0];\n    int i;\n    size_t tmpwrit;\n    s->rwstate = SSL_NOTHING;\n    tot = s->rlayer.wnum;\n    if (len < s->rlayer.wnum) {\n        SSLerr(SSL_F_SSL3_WRITE_BYTES, SSL_R_BAD_LENGTH);\n        return -1;\n    }\n    s->rlayer.wnum = 0;\n    if (SSL_in_init(s) && !ossl_statem_get_in_handshake(s)) {\n        i = s->handshake_func(s);\n        if (i < 0)\n            return i;\n        if (i == 0) {\n            SSLerr(SSL_F_SSL3_WRITE_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE);\n            return -1;\n        }\n    }\n    if (wb->left != 0) {\n        i = ssl3_write_pending(s, type, &buf[tot], s->rlayer.wpend_tot,\n                               &tmpwrit);\n        if (i <= 0) {\n            s->rlayer.wnum = tot;\n            return i;\n        }\n        tot += tmpwrit;\n    }\n#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK\n    if (type == SSL3_RT_APPLICATION_DATA &&\n        len >= 4 * (max_send_fragment = s->max_send_fragment) &&\n        s->compress == NULL && s->msg_callback == NULL &&\n        !SSL_USE_ETM(s) && SSL_USE_EXPLICIT_IV(s) &&\n        EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx)) &\n        EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK) {\n        unsigned char aad[13];\n        EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param;\n        size_t packlen;\n        int packleni;\n        if ((max_send_fragment & 0xfff) == 0)\n            max_send_fragment -= 512;\n        if (tot == 0 || wb->buf == NULL) {\n            ssl3_release_write_buffer(s);\n            packlen = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,\n                                          EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE,\n                                          (int)max_send_fragment, NULL);\n            if (len >= 8 * max_send_fragment)\n                packlen *= 8;\n            else\n                packlen *= 4;\n            if (!ssl3_setup_write_buffer(s, 1, packlen)) {\n                SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_MALLOC_FAILURE);\n                return -1;\n            }\n        } else if (tot == len) {\n            ssl3_release_write_buffer(s);\n            *written = tot;\n            return 1;\n        }\n        n = (len - tot);\n        for (;;) {\n            if (n < 4 * max_send_fragment) {\n                ssl3_release_write_buffer(s);\n                break;\n            }\n            if (s->s3->alert_dispatch) {\n                i = s->method->ssl_dispatch_alert(s);\n                if (i <= 0) {\n                    s->rlayer.wnum = tot;\n                    return i;\n                }\n            }\n            if (n >= 8 * max_send_fragment)\n                nw = max_send_fragment * (mb_param.interleave = 8);\n            else\n                nw = max_send_fragment * (mb_param.interleave = 4);\n            memcpy(aad, s->rlayer.write_sequence, 8);\n            aad[8] = type;\n            aad[9] = (unsigned char)(s->version >> 8);\n            aad[10] = (unsigned char)(s->version);\n            aad[11] = 0;\n            aad[12] = 0;\n            mb_param.out = NULL;\n            mb_param.inp = aad;\n            mb_param.len = nw;\n            packleni = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,\n                                          EVP_CTRL_TLS1_1_MULTIBLOCK_AAD,\n                                          sizeof(mb_param), &mb_param);\n            packlen = (size_t)packleni;\n            if (packleni <= 0 || packlen > wb->len) {\n                ssl3_release_write_buffer(s);\n                break;\n            }\n            mb_param.out = wb->buf;\n            mb_param.inp = &buf[tot];\n            mb_param.len = nw;\n            if (EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,\n                                    EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT,\n                                    sizeof(mb_param), &mb_param) <= 0)\n                return -1;\n            s->rlayer.write_sequence[7] += mb_param.interleave;\n            if (s->rlayer.write_sequence[7] < mb_param.interleave) {\n                int j = 6;\n                while (j >= 0 && (++s->rlayer.write_sequence[j--]) == 0) ;\n            }\n            wb->offset = 0;\n            wb->left = packlen;\n            s->rlayer.wpend_tot = nw;\n            s->rlayer.wpend_buf = &buf[tot];\n            s->rlayer.wpend_type = type;\n            s->rlayer.wpend_ret = nw;\n            i = ssl3_write_pending(s, type, &buf[tot], nw, &tmpwrit);\n            if (i <= 0) {\n                if (i < 0 && (!s->wbio || !BIO_should_retry(s->wbio))) {\n                    ssl3_release_write_buffer(s);\n                }\n                s->rlayer.wnum = tot;\n                return i;\n            }\n            if (tmpwrit == n) {\n                ssl3_release_write_buffer(s);\n                *written = tot + tmpwrit;\n                return 1;\n            }\n            n -= tmpwrit;\n            tot += tmpwrit;\n        }\n    } else\n#endif\n    if (tot == len) {\n        if (s->mode & SSL_MODE_RELEASE_BUFFERS && !SSL_IS_DTLS(s))\n            ssl3_release_write_buffer(s);\n        *written = tot;\n        return 1;\n    }\n    n = (len - tot);\n    split_send_fragment = s->split_send_fragment;\n    maxpipes = s->max_pipelines;\n    if (maxpipes > SSL_MAX_PIPELINES) {\n        SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_INTERNAL_ERROR);\n        return -1;\n    }\n    if (maxpipes == 0\n        || s->enc_write_ctx == NULL\n        || !(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx))\n             & EVP_CIPH_FLAG_PIPELINE)\n        || !SSL_USE_EXPLICIT_IV(s))\n        maxpipes = 1;\n    if (s->max_send_fragment == 0 || split_send_fragment > s->max_send_fragment\n        || split_send_fragment == 0) {\n        SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_INTERNAL_ERROR);\n        return -1;\n    }\n    for (;;) {\n        size_t pipelens[SSL_MAX_PIPELINES], tmppipelen, remain;\n        size_t numpipes, j;\n        if (n == 0)\n            numpipes = 1;\n        else\n            numpipes = ((n - 1) / split_send_fragment) + 1;\n        if (numpipes > maxpipes)\n            numpipes = maxpipes;\n        if (n / numpipes >= s->max_send_fragment) {\n            for (j = 0; j < numpipes; j++) {\n                pipelens[j] = s->max_send_fragment;\n            }\n        } else {\n            tmppipelen = n / numpipes;\n            remain = n % numpipes;\n            for (j = 0; j < numpipes; j++) {\n                pipelens[j] = tmppipelen;\n                if (j < remain)\n                    pipelens[j]++;\n            }\n        }\n        i = do_ssl3_write(s, type, &(buf[tot]), pipelens, numpipes, 0,\n                          &tmpwrit);\n        if (i <= 0) {\n            s->rlayer.wnum = tot;\n            return i;\n        }\n        if (tmpwrit == n ||\n            (type == SSL3_RT_APPLICATION_DATA &&\n             (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) {\n            s->s3->empty_fragment_done = 0;\n            if ((i == (int)n) && s->mode & SSL_MODE_RELEASE_BUFFERS &&\n                !SSL_IS_DTLS(s))\n                ssl3_release_write_buffer(s);\n            *written = tot + tmpwrit;\n            return 1;\n        }\n        n -= tmpwrit;\n        tot += tmpwrit;\n    }\n}', 'int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t len,\n                       size_t *written)\n{\n    int i;\n    SSL3_BUFFER *wb = s->rlayer.wbuf;\n    size_t currbuf = 0;\n    size_t tmpwrit = 0;\n    if ((s->rlayer.wpend_tot > len)\n        || ((s->rlayer.wpend_buf != buf) &&\n            !(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER))\n        || (s->rlayer.wpend_type != type)) {\n        SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BAD_WRITE_RETRY);\n        return -1;\n    }\n    for (;;) {\n        if (SSL3_BUFFER_get_left(&wb[currbuf]) == 0\n            && currbuf < s->rlayer.numwpipes - 1) {\n            currbuf++;\n            continue;\n        }\n        clear_sys_error();\n        if (s->wbio != NULL) {\n            s->rwstate = SSL_WRITING;\n            i = BIO_write(s->wbio, (char *)\n                          &(SSL3_BUFFER_get_buf(&wb[currbuf])\n                            [SSL3_BUFFER_get_offset(&wb[currbuf])]),\n                          (unsigned int)SSL3_BUFFER_get_left(&wb[currbuf]));\n            if (i >= 0)\n                tmpwrit = i;\n        } else {\n            SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BIO_NOT_SET);\n            i = -1;\n        }\n        if (i > 0 && tmpwrit == SSL3_BUFFER_get_left(&wb[currbuf])) {\n            SSL3_BUFFER_set_left(&wb[currbuf], 0);\n            SSL3_BUFFER_add_offset(&wb[currbuf], tmpwrit);\n            if (currbuf + 1 < s->rlayer.numwpipes)\n                continue;\n            s->rwstate = SSL_NOTHING;\n            *written = s->rlayer.wpend_ret;\n            return 1;\n        } else if (i <= 0) {\n            if (SSL_IS_DTLS(s)) {\n                SSL3_BUFFER_set_left(&wb[currbuf], 0);\n            }\n            return -1;\n        }\n        SSL3_BUFFER_add_offset(&wb[currbuf], tmpwrit);\n        SSL3_BUFFER_sub_left(&wb[currbuf], tmpwrit);\n    }\n}']