int dtls1_do_write(SSL *s, int type)
{
    int ret;
    size_t written;
    size_t curr_mtu;
    int retry = 1;
    size_t len, frag_off, mac_size, blocksize, used_len;
    if (!dtls1_query_mtu(s))
        return -1;
    if (s->d1->mtu < dtls1_min_mtu(s))
        return -1;
    if (s->init_off == 0 && type == SSL3_RT_HANDSHAKE)
        OPENSSL_assert(s->init_num ==
                       s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH);
    if (s->write_hash) {
        if (s->enc_write_ctx
            && (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx)) &
                EVP_CIPH_FLAG_AEAD_CIPHER) != 0)
            mac_size = 0;
        else
            mac_size = EVP_MD_CTX_size(s->write_hash);
    } else
        mac_size = 0;
    if (s->enc_write_ctx &&
        (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE))
        blocksize = 2 * EVP_CIPHER_CTX_block_size(s->enc_write_ctx);
    else
        blocksize = 0;
    frag_off = 0;
    s->rwstate = SSL_NOTHING;
    while (s->init_num > 0) {
        if (type == SSL3_RT_HANDSHAKE && s->init_off != 0) {
            if (frag_off > 0) {
                if (s->init_off <= DTLS1_HM_HEADER_LENGTH) {
                    return -1;
                }
                s->init_off -= DTLS1_HM_HEADER_LENGTH;
                s->init_num += DTLS1_HM_HEADER_LENGTH;
            } else {
                frag_off = s->d1->w_msg_hdr.frag_off;
            }
        }
        used_len = BIO_wpending(s->wbio) + DTLS1_RT_HEADER_LENGTH
            + mac_size + blocksize;
        if (s->d1->mtu > used_len)
            curr_mtu = s->d1->mtu - used_len;
        else
            curr_mtu = 0;
        if (curr_mtu <= DTLS1_HM_HEADER_LENGTH) {
            ret = BIO_flush(s->wbio);
            if (ret <= 0) {
                s->rwstate = SSL_WRITING;
                return ret;
            }
            used_len = DTLS1_RT_HEADER_LENGTH + mac_size + blocksize;
            if (s->d1->mtu > used_len + DTLS1_HM_HEADER_LENGTH) {
                curr_mtu = s->d1->mtu - used_len;
            } else {
                return -1;
            }
        }
        if (((unsigned int)s->init_num) > curr_mtu)
            len = curr_mtu;
        else
            len = s->init_num;
        if (type == SSL3_RT_HANDSHAKE) {
            if (len < DTLS1_HM_HEADER_LENGTH) {
                return -1;
            }
            dtls1_fix_message_header(s, frag_off, len - DTLS1_HM_HEADER_LENGTH);
            dtls1_write_message_header(s,
                                       (unsigned char *)&s->init_buf->
                                       data[s->init_off]);
        }
        ret = dtls1_write_bytes(s, type, &s->init_buf->data[s->init_off], len,
                                &written);
        if (ret < 0) {
            if (retry && BIO_ctrl(SSL_get_wbio(s),
                                  BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0) {
                if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
                    if (!dtls1_query_mtu(s))
                        return -1;
                    retry = 0;
                } else
                    return -1;
            } else {
                return (-1);
            }
        } else {
            OPENSSL_assert(len == written);
            if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting) {
                unsigned char *p =
                    (unsigned char *)&s->init_buf->data[s->init_off];
                const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
                size_t xlen;
                if (frag_off == 0 && s->version != DTLS1_BAD_VER) {
                    *p++ = msg_hdr->type;
                    l2n3(msg_hdr->msg_len, p);
                    s2n(msg_hdr->seq, p);
                    l2n3(0, p);
                    l2n3(msg_hdr->msg_len, p);
                    p -= DTLS1_HM_HEADER_LENGTH;
                    xlen = written;
                } else {
                    p += DTLS1_HM_HEADER_LENGTH;
                    xlen = written - DTLS1_HM_HEADER_LENGTH;
                }
                if (!ssl3_finish_mac(s, p, xlen))
                    return -1;
            }
            if (written == s->init_num) {
                if (s->msg_callback)
                    s->msg_callback(1, s->version, type, s->init_buf->data,
                                    (size_t)(s->init_off + s->init_num), s,
                                    s->msg_callback_arg);
                s->init_off = 0;
                s->init_num = 0;
                return 1;
            }
            s->init_off += written;
            s->init_num -= written;
            written -= DTLS1_HM_HEADER_LENGTH;
            frag_off += written;
            dtls1_fix_message_header(s, frag_off, 0);
        }
    }
    return 0;
}
['int dtls1_do_write(SSL *s, int type)\n{\n    int ret;\n    size_t written;\n    size_t curr_mtu;\n    int retry = 1;\n    size_t len, frag_off, mac_size, blocksize, used_len;\n    if (!dtls1_query_mtu(s))\n        return -1;\n    if (s->d1->mtu < dtls1_min_mtu(s))\n        return -1;\n    if (s->init_off == 0 && type == SSL3_RT_HANDSHAKE)\n        OPENSSL_assert(s->init_num ==\n                       s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH);\n    if (s->write_hash) {\n        if (s->enc_write_ctx\n            && (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx)) &\n                EVP_CIPH_FLAG_AEAD_CIPHER) != 0)\n            mac_size = 0;\n        else\n            mac_size = EVP_MD_CTX_size(s->write_hash);\n    } else\n        mac_size = 0;\n    if (s->enc_write_ctx &&\n        (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE))\n        blocksize = 2 * EVP_CIPHER_CTX_block_size(s->enc_write_ctx);\n    else\n        blocksize = 0;\n    frag_off = 0;\n    s->rwstate = SSL_NOTHING;\n    while (s->init_num > 0) {\n        if (type == SSL3_RT_HANDSHAKE && s->init_off != 0) {\n            if (frag_off > 0) {\n                if (s->init_off <= DTLS1_HM_HEADER_LENGTH) {\n                    return -1;\n                }\n                s->init_off -= DTLS1_HM_HEADER_LENGTH;\n                s->init_num += DTLS1_HM_HEADER_LENGTH;\n            } else {\n                frag_off = s->d1->w_msg_hdr.frag_off;\n            }\n        }\n        used_len = BIO_wpending(s->wbio) + DTLS1_RT_HEADER_LENGTH\n            + mac_size + blocksize;\n        if (s->d1->mtu > used_len)\n            curr_mtu = s->d1->mtu - used_len;\n        else\n            curr_mtu = 0;\n        if (curr_mtu <= DTLS1_HM_HEADER_LENGTH) {\n            ret = BIO_flush(s->wbio);\n            if (ret <= 0) {\n                s->rwstate = SSL_WRITING;\n                return ret;\n            }\n            used_len = DTLS1_RT_HEADER_LENGTH + mac_size + blocksize;\n            if (s->d1->mtu > used_len + DTLS1_HM_HEADER_LENGTH) {\n                curr_mtu = s->d1->mtu - used_len;\n            } else {\n                return -1;\n            }\n        }\n        if (((unsigned int)s->init_num) > curr_mtu)\n            len = curr_mtu;\n        else\n            len = s->init_num;\n        if (type == SSL3_RT_HANDSHAKE) {\n            if (len < DTLS1_HM_HEADER_LENGTH) {\n                return -1;\n            }\n            dtls1_fix_message_header(s, frag_off, len - DTLS1_HM_HEADER_LENGTH);\n            dtls1_write_message_header(s,\n                                       (unsigned char *)&s->init_buf->\n                                       data[s->init_off]);\n        }\n        ret = dtls1_write_bytes(s, type, &s->init_buf->data[s->init_off], len,\n                                &written);\n        if (ret < 0) {\n            if (retry && BIO_ctrl(SSL_get_wbio(s),\n                                  BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0) {\n                if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {\n                    if (!dtls1_query_mtu(s))\n                        return -1;\n                    retry = 0;\n                } else\n                    return -1;\n            } else {\n                return (-1);\n            }\n        } else {\n            OPENSSL_assert(len == written);\n            if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting) {\n                unsigned char *p =\n                    (unsigned char *)&s->init_buf->data[s->init_off];\n                const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;\n                size_t xlen;\n                if (frag_off == 0 && s->version != DTLS1_BAD_VER) {\n                    *p++ = msg_hdr->type;\n                    l2n3(msg_hdr->msg_len, p);\n                    s2n(msg_hdr->seq, p);\n                    l2n3(0, p);\n                    l2n3(msg_hdr->msg_len, p);\n                    p -= DTLS1_HM_HEADER_LENGTH;\n                    xlen = written;\n                } else {\n                    p += DTLS1_HM_HEADER_LENGTH;\n                    xlen = written - DTLS1_HM_HEADER_LENGTH;\n                }\n                if (!ssl3_finish_mac(s, p, xlen))\n                    return -1;\n            }\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                s->init_off = 0;\n                s->init_num = 0;\n                return 1;\n            }\n            s->init_off += written;\n            s->init_num -= written;\n            written -= DTLS1_HM_HEADER_LENGTH;\n            frag_off += written;\n            dtls1_fix_message_header(s, frag_off, 0);\n        }\n    }\n    return 0;\n}']