feat: 对接Python,暴露接口
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user