feat: 对接Python,暴露接口

This commit is contained in:
2026-03-30 22:48:36 +08:00
parent 24467c04c0
commit d678bfc326
22 changed files with 1311 additions and 51 deletions

View File

@@ -113,7 +113,7 @@ int latencylog_is_business_message(const message_t *msg) {
if (msg == NULL) {
return 0;
}
return msg->type == MSG_TYPE_TEXT || msg->type == MSG_TYPE_FILE;
return msg->type == MSG_TYPE_TEXT || msg->type == MSG_TYPE_FILE || msg->type == MSG_TYPE_BINARY;
}
void latencylog_log_message_event(latency_logger_t *logger, const char *node_role, const char *node_id, const char *event_name, const message_t *msg) {

View File

@@ -66,6 +66,11 @@ static int kcp_client_persist_message_to_disk(const message_t *msg, const char *
if (omni_write_file(path, msg->body, msg->body_len) != 0) {
return -1;
}
} else if (msg->type == MSG_TYPE_BINARY) {
snprintf(path, sizeof(path), "%s/%s-%" PRIu64 ".bin", inbox_dir, msg->from, msg->id);
if (omni_write_file(path, msg->body, msg->body_len) != 0) {
return -1;
}
} else {
errno = EINVAL;
return -1;
@@ -77,7 +82,20 @@ static int kcp_client_persist_message_to_disk(const message_t *msg, const char *
return 0;
}
kcp_client_t *kcp_client_dial(const char *server_addr, const char *dial_addr, const char *peer_id, const char *bind_ip, const char *bind_device, latency_logger_t *logger, kcp_packet_debug_logger_t *packet_logger, kcp_session_stats_logger_t *stats_logger, int stats_interval_ms) {
static void kcp_client_fill_recv_meta(kcp_client_recv_meta_t *meta, const message_t *msg) {
if (meta == NULL || msg == NULL) {
return;
}
memset(meta, 0, sizeof(*meta));
meta->type = msg->type;
meta->id = msg->id;
meta->body_len = msg->body_len;
snprintf(meta->from, sizeof(meta->from), "%s", msg->from);
snprintf(meta->to, sizeof(meta->to), "%s", msg->to);
snprintf(meta->file_name, sizeof(meta->file_name), "%s", msg->file_name);
}
kcp_client_t *kcp_client_dial_with_options(const char *server_addr, const char *dial_addr, const char *peer_id, const char *bind_ip, const char *bind_device, const kcp_conn_options_t *options, latency_logger_t *logger, kcp_packet_debug_logger_t *packet_logger, kcp_session_stats_logger_t *stats_logger, int stats_interval_ms) {
kcp_client_t *client;
const char *actual_dial_addr = (dial_addr != NULL && dial_addr[0] != '\0') ? dial_addr : server_addr;
message_t register_msg;
@@ -91,7 +109,7 @@ kcp_client_t *kcp_client_dial(const char *server_addr, const char *dial_addr, co
snprintf(client->server_addr, sizeof(client->server_addr), "%s", server_addr == NULL ? "" : server_addr);
pthread_mutex_init(&client->id_mu, NULL);
client->logger = logger;
client->conn = kcp_conn_dial(actual_dial_addr, bind_ip, bind_device, packet_logger, logger, OMNI_NODE_ROLE_PEER, peer_id, stats_logger, stats_interval_ms);
client->conn = kcp_conn_dial_with_options(actual_dial_addr, bind_ip, bind_device, options, packet_logger, logger, OMNI_NODE_ROLE_PEER, peer_id, stats_logger, stats_interval_ms);
if (client->conn == NULL) {
saved_errno = errno;
kcp_client_free(client);
@@ -113,6 +131,10 @@ kcp_client_t *kcp_client_dial(const char *server_addr, const char *dial_addr, co
return client;
}
kcp_client_t *kcp_client_dial(const char *server_addr, const char *dial_addr, const char *peer_id, const char *bind_ip, const char *bind_device, latency_logger_t *logger, kcp_packet_debug_logger_t *packet_logger, kcp_session_stats_logger_t *stats_logger, int stats_interval_ms) {
return kcp_client_dial_with_options(server_addr, dial_addr, peer_id, bind_ip, bind_device, NULL, logger, packet_logger, stats_logger, stats_interval_ms);
}
const char *kcp_client_id(const kcp_client_t *client) {
return client == NULL ? "" : client->id;
}
@@ -121,6 +143,10 @@ int kcp_client_send_text(kcp_client_t *client, const char *to, const char *text)
message_t msg;
uint64_t id;
if (client == NULL || to == NULL || text == NULL) {
errno = EINVAL;
return -1;
}
protocol_message_init(&msg);
kcp_client_next_message_id(client, &id);
msg.type = MSG_TYPE_TEXT;
@@ -141,6 +167,37 @@ int kcp_client_send_text(kcp_client_t *client, const char *to, const char *text)
return 0;
}
int kcp_client_send_binary(kcp_client_t *client, const char *to, const void *data, size_t data_len) {
message_t msg;
uint64_t id;
if (client == NULL || to == NULL || (data == NULL && data_len > 0)) {
errno = EINVAL;
return -1;
}
protocol_message_init(&msg);
kcp_client_next_message_id(client, &id);
msg.type = MSG_TYPE_BINARY;
msg.id = id;
snprintf(msg.from, sizeof(msg.from), "%s", client->id);
snprintf(msg.to, sizeof(msg.to), "%s", to);
if (data_len > 0) {
msg.body = (uint8_t *) malloc(data_len);
if (msg.body == NULL) {
return -1;
}
memcpy(msg.body, data, data_len);
}
msg.body_len = data_len;
latencylog_log_message_event(client->logger, OMNI_NODE_ROLE_PEER, client->id, EVENT_A_APP_PREP_BEGIN, &msg);
if (kcp_conn_send(client->conn, &msg) != 0) {
protocol_message_clear(&msg);
return -1;
}
protocol_message_clear(&msg);
return 0;
}
int kcp_client_send_file_path(kcp_client_t *client, const char *to, const char *path) {
message_t msg;
uint64_t id;
@@ -148,6 +205,10 @@ int kcp_client_send_file_path(kcp_client_t *client, const char *to, const char *
size_t body_len = 0;
const char *base_name = strrchr(path, '/');
if (client == NULL || to == NULL || path == NULL) {
errno = EINVAL;
return -1;
}
if (omni_read_file(path, &body, &body_len) != 0) {
return -1;
}
@@ -169,14 +230,57 @@ int kcp_client_send_file_path(kcp_client_t *client, const char *to, const char *
return 0;
}
int kcp_client_receive(kcp_client_t *client, message_t *out_msg) {
if (kcp_conn_receive(client->conn, out_msg) != 0) {
int kcp_client_receive_timed(kcp_client_t *client, message_t *out_msg, int timeout_ms) {
int rc;
if (client == NULL || out_msg == NULL) {
errno = EINVAL;
return -1;
}
rc = kcp_conn_receive_timed(client->conn, out_msg, timeout_ms);
if (rc != 0) {
return rc;
}
latencylog_log_message_event(client->logger, OMNI_NODE_ROLE_PEER, client->id, EVENT_B_APP_RECV, out_msg);
return 0;
}
int kcp_client_receive(kcp_client_t *client, message_t *out_msg) {
if (kcp_client_receive_timed(client, out_msg, -1) != 0) {
return -1;
}
return 0;
}
int kcp_client_receive_binary_into(kcp_client_t *client, void *buffer, size_t buffer_len, kcp_client_recv_meta_t *out_meta, int timeout_ms) {
message_t msg;
int rc;
if (client == NULL || (buffer == NULL && buffer_len > 0) || out_meta == NULL) {
errno = EINVAL;
return -1;
}
protocol_message_init(&msg);
rc = kcp_client_receive_timed(client, &msg, timeout_ms);
if (rc != 0) {
return rc;
}
kcp_client_fill_recv_meta(out_meta, &msg);
if (msg.body_len > buffer_len) {
protocol_message_clear(&msg);
errno = EMSGSIZE;
return 2;
}
if (msg.body_len > 0) {
memcpy(buffer, msg.body, msg.body_len);
}
protocol_message_clear(&msg);
return 0;
}
int kcp_client_persist_message(kcp_client_t *client, const message_t *msg, const char *inbox_dir, char *out_path, size_t out_path_len) {
if (!latencylog_is_business_message(msg)) {
errno = EINVAL;

View File

@@ -55,6 +55,11 @@ static int client_persist_message_to_disk(const message_t *msg, const char *inbo
if (omni_write_file(path, msg->body, msg->body_len) != 0) {
return -1;
}
} else if (msg->type == MSG_TYPE_BINARY) {
snprintf(path, sizeof(path), "%s/%s-%" PRIu64 ".bin", inbox_dir, msg->from, msg->id);
if (omni_write_file(path, msg->body, msg->body_len) != 0) {
return -1;
}
} else {
errno = EINVAL;
return -1;

View File

@@ -8,11 +8,12 @@ static const char *protocol_message_type_table[] = {
"text",
"file",
"register",
"error"
"error",
"binary"
};
const char *protocol_message_type_name(message_type_t type) {
if ((int) type < 0 || type >= MSG_TYPE_INVALID) {
if ((int) type < 0 || (size_t) type >= OMNI_ARRAY_LEN(protocol_message_type_table)) {
return "invalid";
}
return protocol_message_type_table[type];
@@ -102,6 +103,11 @@ int protocol_validate_message(const message_t *msg, char *err, size_t err_len) {
return protocol_set_err(err, err_len, "protocol: missing file name");
}
break;
case MSG_TYPE_BINARY:
if (msg->file_name[0] != '\0') {
return protocol_set_err(err, err_len, "protocol: unexpected file name");
}
break;
case MSG_TYPE_REGISTER:
if (strcmp(msg->to, SERVER_PEER_ID) != 0) {
return protocol_set_err(err, err_len, "protocol: invalid register target");

View File

@@ -63,6 +63,36 @@ static kcp_peer_entry_t *kcp_hub_find_peer(kcp_hub_t *hub, const char *peer_id)
return NULL;
}
static int kcp_hub_peer_id_has_suffix(const char *peer_id, const char *suffix) {
size_t peer_len;
size_t suffix_len;
if (peer_id == NULL || suffix == NULL) {
return 0;
}
peer_len = strlen(peer_id);
suffix_len = strlen(suffix);
return peer_len >= suffix_len && strcmp(peer_id + peer_len - suffix_len, suffix) == 0;
}
static int kcp_hub_configure_peer_transport(kcp_conn_t *conn, const char *peer_id) {
kcp_conn_options_t options;
if (conn == NULL || peer_id == NULL) {
errno = EINVAL;
return -1;
}
if (kcp_hub_peer_id_has_suffix(peer_id, "-ctrl")) {
kcp_conn_options_set_control_defaults(&options);
return kcp_conn_apply_options(conn, &options);
}
if (kcp_hub_peer_id_has_suffix(peer_id, "-video")) {
kcp_conn_options_set_video_defaults(&options);
return kcp_conn_apply_options(conn, &options);
}
return 0;
}
static int kcp_hub_send_server_error(kcp_conn_t *conn, const char *to, const char *message) {
message_t msg;
protocol_message_init(&msg);
@@ -255,6 +285,7 @@ static int kcp_hub_handle_peer_message(kcp_hub_t *hub, const char *peer_id, kcp_
switch (msg->type) {
case MSG_TYPE_TEXT:
case MSG_TYPE_FILE:
case MSG_TYPE_BINARY:
snprintf(msg->from, sizeof(msg->from), "%s", peer_id);
if (kcp_hub_deliver_to_local_peer(hub, msg) == 0) {
return 0;
@@ -294,7 +325,7 @@ static int kcp_hub_handle_peer_message(kcp_hub_t *hub, const char *peer_id, kcp_
return 0;
case MSG_TYPE_REGISTER:
case MSG_TYPE_ERROR:
if (kcp_hub_send_server_error(conn, peer_id, "registered peers can only send text or file messages") != 0) {
if (kcp_hub_send_server_error(conn, peer_id, "registered peers can only send text, file, or binary messages") != 0) {
return -1;
}
errno = EPROTO;
@@ -358,6 +389,11 @@ static int kcp_hub_register_conn(kcp_hub_t *hub, kcp_conn_t *conn, char *peer_id
pthread_rwlock_unlock(&hub->lock);
snprintf(peer_id, peer_id_len, "%s", msg.from);
if (kcp_hub_configure_peer_transport(conn, peer_id) != 0) {
kcp_hub_unregister(hub, peer_id, conn);
protocol_message_clear(&msg);
return -1;
}
protocol_message_clear(&msg);
return 0;
}
@@ -518,7 +554,7 @@ int kcp_hub_serve_relay(kcp_hub_t *hub) {
protocol_message_clear(&msg);
continue;
}
if (msg.type != MSG_TYPE_TEXT && msg.type != MSG_TYPE_FILE && msg.type != MSG_TYPE_ERROR) {
if (msg.type != MSG_TYPE_TEXT && msg.type != MSG_TYPE_FILE && msg.type != MSG_TYPE_BINARY && msg.type != MSG_TYPE_ERROR) {
protocol_message_clear(&msg);
continue;
}

View File

@@ -112,7 +112,7 @@ int udp_hub_serve(udp_hub_t *hub) {
pthread_rwlock_unlock(&hub->lock);
continue;
}
if (msg.type != MSG_TYPE_TEXT && msg.type != MSG_TYPE_FILE) {
if (msg.type != MSG_TYPE_TEXT && msg.type != MSG_TYPE_FILE && msg.type != MSG_TYPE_BINARY) {
if (msg.type == MSG_TYPE_ERROR) {
udp_hub_send_error(hub, &addr, addr_len, msg.from, "peers cannot send error messages");
} else {

View File

@@ -60,6 +60,8 @@ struct kcp_conn {
int update_thread_started;
pthread_t stats_thread;
int stats_thread_started;
kcp_conn_options_t options;
int update_interval_ms;
uint64_t pending_bytes_sent;
uint64_t pending_bytes_received;
uint64_t pending_in_pkts;
@@ -141,6 +143,82 @@ struct kcp_process_sampler {
static pthread_mutex_t g_kcp_process_sampler_mu = PTHREAD_MUTEX_INITIALIZER;
static kcp_process_sampler_t *g_kcp_process_samplers = NULL;
void kcp_conn_options_init(kcp_conn_options_t *options) {
if (options == NULL) {
return;
}
memset(options, 0, sizeof(*options));
options->nodelay = KCP_DEFAULT_NODELAY;
options->interval_ms = KCP_DEFAULT_INTERVAL_MS;
options->resend = KCP_DEFAULT_RESEND;
options->nc = KCP_DEFAULT_NC;
options->sndwnd = KCP_DEFAULT_SND_WND;
options->rcvwnd = KCP_DEFAULT_RCV_WND;
options->mtu = KCP_DEFAULT_MTU;
}
void kcp_conn_options_set_control_defaults(kcp_conn_options_t *options) {
if (options == NULL) {
return;
}
memset(options, 0, sizeof(*options));
options->nodelay = KCP_CONTROL_NODELAY;
options->interval_ms = KCP_CONTROL_INTERVAL_MS;
options->resend = KCP_CONTROL_RESEND;
options->nc = KCP_CONTROL_NC;
options->sndwnd = KCP_CONTROL_SND_WND;
options->rcvwnd = KCP_CONTROL_RCV_WND;
options->mtu = KCP_CONTROL_MTU;
}
void kcp_conn_options_set_video_defaults(kcp_conn_options_t *options) {
if (options == NULL) {
return;
}
memset(options, 0, sizeof(*options));
options->nodelay = KCP_VIDEO_NODELAY;
options->interval_ms = KCP_VIDEO_INTERVAL_MS;
options->resend = KCP_VIDEO_RESEND;
options->nc = KCP_VIDEO_NC;
options->sndwnd = KCP_VIDEO_SND_WND;
options->rcvwnd = KCP_VIDEO_RCV_WND;
options->mtu = KCP_VIDEO_MTU;
}
static int kcp_conn_validate_options(const kcp_conn_options_t *options) {
if (options == NULL) {
errno = EINVAL;
return -1;
}
if (options->interval_ms <= 0 || options->sndwnd <= 0 || options->rcvwnd <= 0 || options->mtu <= 0) {
errno = EINVAL;
return -1;
}
return 0;
}
static int kcp_conn_apply_options_locked(kcp_conn_t *conn, const kcp_conn_options_t *options) {
if (conn == NULL || conn->kcp == NULL || kcp_conn_validate_options(options) != 0) {
return -1;
}
if (ikcp_wndsize(conn->kcp, options->sndwnd, options->rcvwnd) != 0) {
errno = EINVAL;
return -1;
}
if (ikcp_setmtu(conn->kcp, options->mtu) != 0) {
errno = EINVAL;
return -1;
}
if (ikcp_nodelay(conn->kcp, options->nodelay, options->interval_ms, options->resend, options->nc) != 0) {
errno = EINVAL;
return -1;
}
conn->kcp->stream = 1;
conn->options = *options;
conn->update_interval_ms = options->interval_ms;
return 0;
}
static void kcp_parse_packet_segments(const uint8_t *packet, size_t len, uint32_t *conv, kcp_packet_debug_segment_t **segments, size_t *segment_count) {
size_t offset = 0;
size_t count = 0;
@@ -1107,10 +1185,12 @@ static void *kcp_client_recv_thread_main(void *arg) {
static void *kcp_update_thread_main(void *arg) {
kcp_conn_t *conn = (kcp_conn_t *) arg;
while (!atomic_load(&conn->closed)) {
int interval_ms;
pthread_mutex_lock(&conn->kcp_mu);
ikcp_update(conn->kcp, omni_now_millis32());
interval_ms = conn->update_interval_ms > 0 ? conn->update_interval_ms : KCP_DEFAULT_INTERVAL_MS;
pthread_mutex_unlock(&conn->kcp_mu);
usleep(10000);
usleep((useconds_t) interval_ms * 1000U);
}
return NULL;
}
@@ -1129,10 +1209,11 @@ static int kcp_conn_start_stats_thread(kcp_conn_t *conn) {
return 0;
}
static kcp_conn_t *kcp_conn_alloc_common(int fd, const struct sockaddr_storage *remote_addr, socklen_t remote_addr_len, kcp_socket_debug_state_t *sock_state, latency_logger_t *logger, const char *node_role, const char *node_id, kcp_session_stats_logger_t *stats_logger, int stats_interval_ms) {
static kcp_conn_t *kcp_conn_alloc_common(int fd, const struct sockaddr_storage *remote_addr, socklen_t remote_addr_len, const kcp_conn_options_t *options, kcp_socket_debug_state_t *sock_state, latency_logger_t *logger, const char *node_role, const char *node_id, kcp_session_stats_logger_t *stats_logger, int stats_interval_ms) {
kcp_conn_t *conn = (kcp_conn_t *) calloc(1, sizeof(*conn));
uint32_t conv;
int thread_rc;
kcp_conn_options_t effective_options;
if (conn == NULL) {
errno = ENOMEM;
@@ -1150,6 +1231,12 @@ static kcp_conn_t *kcp_conn_alloc_common(int fd, const struct sockaddr_storage *
snprintf(conn->node_id, sizeof(conn->node_id), "%s", node_id == NULL ? "" : node_id);
conn->stats_logger = stats_logger;
conn->stats_interval_ms = stats_interval_ms > 0 ? stats_interval_ms : KCP_DEFAULT_STATS_INTERVAL_MS;
kcp_conn_options_init(&effective_options);
if (options != NULL) {
effective_options = *options;
}
conn->options = effective_options;
conn->update_interval_ms = effective_options.interval_ms;
conn->sock_state = sock_state;
if (omni_random_u32(&conv) != 0) {
protocol_frame_decoder_destroy(&conn->decoder);
@@ -1170,10 +1257,15 @@ static kcp_conn_t *kcp_conn_alloc_common(int fd, const struct sockaddr_storage *
return NULL;
}
ikcp_setoutput(conn->kcp, kcp_output_callback_impl);
ikcp_wndsize(conn->kcp, KCP_WND_SIZE, KCP_WND_SIZE);
ikcp_setmtu(conn->kcp, KCP_MTU);
ikcp_nodelay(conn->kcp, KCP_NODELAY, KCP_INTERVAL, KCP_RESEND, KCP_NC);
conn->kcp->stream = 1;
if (kcp_conn_apply_options_locked(conn, &effective_options) != 0) {
ikcp_release(conn->kcp);
protocol_frame_decoder_destroy(&conn->decoder);
pthread_cond_destroy(&conn->rx_cond);
pthread_mutex_destroy(&conn->kcp_mu);
pthread_mutex_destroy(&conn->close_mu);
free(conn);
return NULL;
}
if (kcp_conn_attach_process_sampler(conn) != 0) {
ikcp_release(conn->kcp);
protocol_frame_decoder_destroy(&conn->decoder);
@@ -1213,7 +1305,7 @@ static kcp_conn_t *kcp_conn_alloc_common(int fd, const struct sockaddr_storage *
return conn;
}
kcp_conn_t *kcp_conn_dial(const char *server_addr, const char *bind_ip, const char *bind_device, kcp_packet_debug_logger_t *packet_logger, latency_logger_t *logger, const char *node_role, const char *node_id, kcp_session_stats_logger_t *stats_logger, int stats_interval_ms) {
kcp_conn_t *kcp_conn_dial_with_options(const char *server_addr, const char *bind_ip, const char *bind_device, const kcp_conn_options_t *options, kcp_packet_debug_logger_t *packet_logger, latency_logger_t *logger, const char *node_role, const char *node_id, kcp_session_stats_logger_t *stats_logger, int stats_interval_ms) {
struct sockaddr_storage remote_addr;
socklen_t remote_len;
int family;
@@ -1236,7 +1328,7 @@ kcp_conn_t *kcp_conn_dial(const char *server_addr, const char *bind_ip, const ch
close(fd);
return NULL;
}
conn = kcp_conn_alloc_common(fd, &remote_addr, remote_len, sock_state, logger, node_role, node_id, stats_logger, stats_interval_ms);
conn = kcp_conn_alloc_common(fd, &remote_addr, remote_len, options, sock_state, logger, node_role, node_id, stats_logger, stats_interval_ms);
if (conn == NULL) {
kcp_socket_debug_destroy(sock_state);
free(sock_state);
@@ -1255,6 +1347,10 @@ kcp_conn_t *kcp_conn_dial(const char *server_addr, const char *bind_ip, const ch
return conn;
}
kcp_conn_t *kcp_conn_dial(const char *server_addr, const char *bind_ip, const char *bind_device, kcp_packet_debug_logger_t *packet_logger, latency_logger_t *logger, const char *node_role, const char *node_id, kcp_session_stats_logger_t *stats_logger, int stats_interval_ms) {
return kcp_conn_dial_with_options(server_addr, bind_ip, bind_device, NULL, packet_logger, logger, node_role, node_id, stats_logger, stats_interval_ms);
}
static void kcp_listener_enqueue_accept(kcp_listener_t *listener, kcp_conn_t *conn) {
pthread_mutex_lock(&listener->accept_mu);
if (listener->accept_tail == NULL) {
@@ -1381,6 +1477,7 @@ static void *kcp_listener_recv_thread_main(void *arg) {
if (conn == NULL) {
conn = (kcp_conn_t *) calloc(1, sizeof(*conn));
if (conn != NULL) {
kcp_conn_options_t accepted_options;
conn->fd = listener->fd;
memcpy(&conn->remote_addr, &source, sizeof(source));
conn->remote_addr_len = msg.msg_namelen;
@@ -1393,15 +1490,15 @@ static void *kcp_listener_recv_thread_main(void *arg) {
conn->stats_interval_ms = KCP_DEFAULT_STATS_INTERVAL_MS;
conn->sock_state = &listener->sock_state;
conn->listener = listener;
kcp_conn_options_init(&accepted_options);
conn->options = accepted_options;
conn->update_interval_ms = accepted_options.interval_ms;
conn->kcp = ikcp_create(conv, conn);
if (conn->kcp != NULL) {
int update_started = 0;
ikcp_setoutput(conn->kcp, kcp_output_callback_impl);
ikcp_wndsize(conn->kcp, KCP_WND_SIZE, KCP_WND_SIZE);
ikcp_setmtu(conn->kcp, KCP_MTU);
ikcp_nodelay(conn->kcp, KCP_NODELAY, KCP_INTERVAL, KCP_RESEND, KCP_NC);
conn->kcp->stream = 1;
if (pthread_create(&conn->update_thread, NULL, kcp_update_thread_main, conn) == 0) {
if (kcp_conn_apply_options_locked(conn, &accepted_options) == 0 &&
pthread_create(&conn->update_thread, NULL, kcp_update_thread_main, conn) == 0) {
update_started = 1;
}
if (update_started && kcp_listener_add_session(listener, conv, conn) == 0) {
@@ -1537,6 +1634,19 @@ int kcp_conn_configure_runtime(kcp_conn_t *conn, latency_logger_t *logger, const
return 0;
}
int kcp_conn_apply_options(kcp_conn_t *conn, const kcp_conn_options_t *options) {
int rc;
if (conn == NULL || options == NULL) {
errno = EINVAL;
return -1;
}
pthread_mutex_lock(&conn->kcp_mu);
rc = kcp_conn_apply_options_locked(conn, options);
pthread_mutex_unlock(&conn->kcp_mu);
return rc;
}
int kcp_conn_send(kcp_conn_t *conn, const message_t *msg) {
uint8_t *frame = NULL;
size_t frame_len = 0;
@@ -1577,15 +1687,31 @@ int kcp_conn_send(kcp_conn_t *conn, const message_t *msg) {
return 0;
}
int kcp_conn_receive(kcp_conn_t *conn, message_t *out_msg) {
static void kcp_timespec_deadline_after_ms(struct timespec *deadline, int timeout_ms) {
clock_gettime(CLOCK_REALTIME, deadline);
deadline->tv_sec += timeout_ms / 1000;
deadline->tv_nsec += (long) (timeout_ms % 1000) * 1000000L;
if (deadline->tv_nsec >= 1000000000L) {
deadline->tv_sec += 1;
deadline->tv_nsec -= 1000000000L;
}
}
int kcp_conn_receive_timed(kcp_conn_t *conn, message_t *out_msg, int timeout_ms) {
uint8_t *frame = NULL;
size_t frame_len = 0;
char err[128];
int next_rc;
struct timespec deadline;
int use_deadline = timeout_ms > 0;
if (conn == NULL || out_msg == NULL) {
errno = EINVAL;
return -1;
}
if (use_deadline) {
kcp_timespec_deadline_after_ms(&deadline, timeout_ms);
}
for (;;) {
next_rc = protocol_frame_decoder_next(&conn->decoder, &frame, &frame_len);
if (next_rc < 0) {
@@ -1618,12 +1744,33 @@ int kcp_conn_receive(kcp_conn_t *conn, message_t *out_msg) {
errno = ECANCELED;
return -1;
}
pthread_cond_wait(&conn->rx_cond, &conn->kcp_mu);
if (timeout_ms == 0) {
pthread_mutex_unlock(&conn->kcp_mu);
return 1;
}
if (timeout_ms < 0) {
pthread_cond_wait(&conn->rx_cond, &conn->kcp_mu);
} else {
int wait_rc = pthread_cond_timedwait(&conn->rx_cond, &conn->kcp_mu, &deadline);
if (wait_rc == ETIMEDOUT) {
pthread_mutex_unlock(&conn->kcp_mu);
return 1;
}
if (wait_rc != 0) {
pthread_mutex_unlock(&conn->kcp_mu);
errno = wait_rc;
return -1;
}
}
}
pthread_mutex_unlock(&conn->kcp_mu);
}
}
int kcp_conn_receive(kcp_conn_t *conn, message_t *out_msg) {
return kcp_conn_receive_timed(conn, out_msg, -1);
}
uint32_t kcp_conn_conv(const kcp_conn_t *conn) {
return conn == NULL || conn->kcp == NULL ? 0 : conn->kcp->conv;
}