xqc_int_t xqc_datagram_send()

in src/transport/xqc_datagram.c [149:261]


xqc_int_t xqc_datagram_send(xqc_connection_t *conn, void *data, 
	size_t data_len, uint64_t *dgram_id, xqc_data_qos_level_t qos_level)
{
    if (conn == NULL) {
        return -XQC_EPARAM;
    }

    if (data == NULL && data_len != 0) {
        return -XQC_EPARAM;
    }

    if (conn->conn_state >= XQC_CONN_STATE_CLOSING) {
        xqc_conn_log(conn, XQC_LOG_INFO, "|conn closing, cannot send datagram|size:%ud|", data_len);
        return -XQC_CLOSING;
    }

    if (conn->remote_settings.max_datagram_frame_size == 0) {
        if (conn->conn_flag & XQC_CONN_FLAG_CAN_SEND_1RTT) {
            xqc_conn_log(conn, XQC_LOG_INFO, "|does not support datagram|size:%ud|", data_len);
            return -XQC_EDGRAM_NOT_SUPPORTED;
        } else {
            /*may receive max_datagram_frame_size later */
            xqc_log(conn->log, XQC_LOG_DEBUG, "|waiting_for_max_datagram_frame_size_from_peer|");
            conn->conn_flag |= XQC_CONN_FLAG_DGRAM_WAIT_FOR_1RTT;
            return -XQC_EAGAIN;
        }
    }

    if (conn->dgram_mss < data_len) {
        xqc_log(conn->log, XQC_LOG_INFO, "|datagram_is_too_large|data_len:%ud|",
                data_len);
        return -XQC_EDGRAM_TOO_LARGE;
    }

    /* max_datagram_frame_size > 0 */

    int ret;
    xqc_pkt_type_t pkt_type = XQC_PTYPE_SHORT_HEADER;
    int support_0rtt = xqc_conn_is_ready_to_send_early_data(conn);
    uint64_t dg_id;

    if (!(conn->conn_flag & XQC_CONN_FLAG_CAN_SEND_1RTT)) {
        if ((conn->conn_type == XQC_CONN_TYPE_CLIENT) 
            && (conn->conn_state == XQC_CONN_STATE_CLIENT_INITIAL_SENT) 
            && support_0rtt)
        {
            pkt_type = XQC_PTYPE_0RTT;
            conn->conn_flag |= XQC_CONN_FLAG_HAS_0RTT;

        } else {
            xqc_log(conn->log, XQC_LOG_DEBUG, "|does_not_support_0rtt_when_sending_datagram|");
            conn->conn_flag |= XQC_CONN_FLAG_DGRAM_WAIT_FOR_1RTT;
            return -XQC_EAGAIN;
        }
    }

    if (!xqc_send_queue_can_write(conn->conn_send_queue)) {
        conn->conn_send_queue->sndq_full = XQC_TRUE;
        xqc_log(conn->log, XQC_LOG_DEBUG, "|too many packets used|ctl_packets_used:%ud|", conn->conn_send_queue->sndq_packets_used);
        return -XQC_EAGAIN;
    }

    if (pkt_type == XQC_PTYPE_0RTT && conn->zero_rtt_count >= XQC_PACKET_0RTT_MAX_COUNT) {
        conn->conn_flag |= XQC_CONN_FLAG_DGRAM_WAIT_FOR_1RTT;
        xqc_log(conn->log, XQC_LOG_DEBUG, "|too many 0rtt packets|zero_rtt_count:%ud|", conn->zero_rtt_count);
        return -XQC_EAGAIN;
    }

    xqc_conn_check_app_limit(conn);

    ret = xqc_write_datagram_frame_to_packet(conn, pkt_type, data, data_len, &dg_id, XQC_FALSE, qos_level);

    if (ret < 0) {
        xqc_log(conn->log, XQC_LOG_ERROR, "|write_datagram_frame_to_packet_error|");
        XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR);
        return ret;
    }

    /* 0RTT failure requires fallback to 1RTT, save the original send data */
    if (pkt_type == XQC_PTYPE_0RTT) {
        /* buffer 0RTT packet */
        ret = xqc_conn_buff_0rtt_datagram(conn, data, data_len, dg_id, qos_level);
        if (ret < 0) {
            xqc_log(conn->log, XQC_LOG_ERROR, "|unable_to_buffer_0rtt_datagram_data_error|");
            XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR);
            return ret;
        }
    }

    if (dgram_id) {
        *dgram_id = dg_id;
    }

    xqc_engine_remove_wakeup_queue(conn->engine, conn);
    xqc_engine_add_active_queue(conn->engine, conn);

    if (conn->conn_settings.datagram_redundant_probe
        && conn->dgram_probe_timer >= 0
        && qos_level <= XQC_DATA_QOS_NORMAL
        && conn->last_dgram
        && data_len <= conn->last_dgram->buf_len)
    {
        xqc_var_buf_clear(conn->last_dgram);
        xqc_var_buf_save_data(conn->last_dgram, data, data_len);
        xqc_conn_gp_timer_set(conn, conn->dgram_probe_timer, xqc_monotonic_timestamp() + conn->conn_settings.datagram_redundant_probe);
        xqc_log(conn->log, XQC_LOG_DEBUG, "|start_dgram_probe_timer|data_len:%z|", data_len);
    }

    /* call main logic to send packets out */
    xqc_engine_conn_logic(conn->engine, conn);

    return XQC_OK;
}