in source/websocket.c [454:532]
static int s_send_frame(
struct aws_websocket *websocket,
const struct aws_websocket_send_frame_options *options,
bool from_public_api) {
AWS_ASSERT(websocket);
AWS_ASSERT(options);
/* Check for bad input. Log about non-obvious errors. */
if (options->high_priority && aws_websocket_is_data_frame(options->opcode)) {
AWS_LOGF_ERROR(AWS_LS_HTTP_WEBSOCKET, "id=%p: Data frames cannot be sent as high-priority.", (void *)websocket);
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
if (options->payload_length > 0 && !options->stream_outgoing_payload) {
AWS_LOGF_ERROR(
AWS_LS_HTTP_WEBSOCKET,
"id=%p: Invalid frame options, payload streaming function required when payload length is non-zero.",
(void *)websocket);
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
struct outgoing_frame *frame = aws_mem_calloc(websocket->alloc, 1, sizeof(struct outgoing_frame));
if (!frame) {
return AWS_OP_ERR;
}
frame->def = *options;
/* Enqueue frame, unless no further sending is allowed. */
int send_error = 0;
bool should_schedule_task = false;
/* BEGIN CRITICAL SECTION */
s_lock_synced_data(websocket);
if (websocket->synced_data.is_midchannel_handler && from_public_api) {
send_error = AWS_ERROR_HTTP_WEBSOCKET_IS_MIDCHANNEL_HANDLER;
} else if (websocket->synced_data.send_frame_error_code) {
send_error = websocket->synced_data.send_frame_error_code;
} else {
aws_linked_list_push_back(&websocket->synced_data.outgoing_frame_list, &frame->node);
if (!websocket->synced_data.is_move_synced_data_to_thread_task_scheduled) {
websocket->synced_data.is_move_synced_data_to_thread_task_scheduled = true;
should_schedule_task = true;
}
}
s_unlock_synced_data(websocket);
/* END CRITICAL SECTION */
if (send_error) {
AWS_LOGF_ERROR(
AWS_LS_HTTP_WEBSOCKET,
"id=%p: Cannot send frame, error %d (%s).",
(void *)websocket,
send_error,
aws_error_name(send_error));
aws_mem_release(websocket->alloc, frame);
return aws_raise_error(send_error);
}
AWS_LOGF_DEBUG(
AWS_LS_HTTP_WEBSOCKET,
"id=%p: Enqueuing outgoing frame with opcode=%" PRIu8 "(%s) length=%" PRIu64 " fin=%s priority=%s",
(void *)websocket,
options->opcode,
aws_websocket_opcode_str(options->opcode),
options->payload_length,
options->fin ? "T" : "F",
options->high_priority ? "high" : "normal");
if (should_schedule_task) {
AWS_LOGF_TRACE(AWS_LS_HTTP_WEBSOCKET, "id=%p: Scheduling synced data task.", (void *)websocket);
aws_channel_schedule_task_now(websocket->channel_slot->channel, &websocket->move_synced_data_to_thread_task);
}
return AWS_OP_SUCCESS;
}