diff --git a/CMakeLists.txt b/CMakeLists.txt index 502588d..836383e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,11 +6,14 @@ option(ENABLE_TESTS "Enable tests" OFF) include(third_party/coreHTTP/httpFilePaths.cmake) include(third_party/coreMQTT/mqttFilePaths.cmake) -include_directories(dist/include) +include_directories(dist/include dist/include/cjson) link_directories(dist/lib) set(DEP_LIBS "srtp2" "usrsctp" "mbedtls" "mbedcrypto" "mbedx509" "cjson") +# Extended debug information (symbols, source code, and macro definitions) +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g3") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g3") add_definitions("-Wunused-variable -Werror=sequence-point -Werror=pointer-sign -Werror=return-type -Werror=sizeof-pointer-memaccess -Wincompatible-pointer-types -DHTTP_DO_NOT_USE_CUSTOM_CONFIG -DMQTT_DO_NOT_USE_CUSTOM_CONFIG") diff --git a/examples/sample/main.c b/examples/sample/main.c index 443b3e3..4d420e6 100644 --- a/examples/sample/main.c +++ b/examples/sample/main.c @@ -26,9 +26,9 @@ static void onclose(void *user_data) { } -static void onmessasge(char *msg, size_t len, void *user_data) { +static void onmessage(char *msg, size_t len, void *user_data, uint16_t sid) { - printf("on message: %s", msg); + printf("on message: %d %s", sid, msg); if (strncmp(msg, "ping", 4) == 0) { printf(", send pong\n"); @@ -96,7 +96,7 @@ int main(int argc, char *argv[]) { peer_init(); g_pc = peer_connection_create(&config); peer_connection_oniceconnectionstatechange(g_pc, onconnectionstatechange); - peer_connection_ondatachannel(g_pc, onmessasge, onopen, onclose); + peer_connection_ondatachannel(g_pc, onmessage, onopen, onclose); peer_signaling_join_channel((const char*)buf, g_pc); diff --git a/src/config.h b/src/config.h index c9d6ceb..e0d7096 100644 --- a/src/config.h +++ b/src/config.h @@ -35,7 +35,7 @@ #define WHIP_PORT 443 #define KEEPALIVE_CONNCHECK 0 -#define CONFIG_IPV6 0 +#define CONFIG_IPV6 1 // default use wifi interface #define IFR_NAME "w" diff --git a/src/peer_connection.c b/src/peer_connection.c index a9e05ef..91b7066 100644 --- a/src/peer_connection.c +++ b/src/peer_connection.c @@ -164,6 +164,11 @@ PeerConnectionState peer_connection_get_state(PeerConnection *pc) { return pc->state; } +Sctp *peer_connection_get_sctp(PeerConnection *pc) { + + return &pc->sctp; +} + PeerConnection* peer_connection_create(PeerConfiguration *config) { PeerConnection *pc = calloc(1, sizeof(PeerConnection)); @@ -250,17 +255,20 @@ int peer_connection_send_video(PeerConnection *pc, const uint8_t *buf, size_t le } int peer_connection_datachannel_send(PeerConnection *pc, char *message, size_t len) { + return peer_connection_datachannel_send_sid(pc, message, len, 0); +} + +int peer_connection_datachannel_send_sid(PeerConnection *pc, char *message, size_t len, uint16_t sid) { if(!sctp_is_connected(&pc->sctp)) { LOGE("sctp not connected"); return -1; } - if (buffer_push_tail(pc->data_rb, (const uint8_t*)message, len) < 0) { - buffer_clear(pc->data_rb); - } - - return 0; + if (pc->config.datachannel == DATA_CHANNEL_STRING) + return sctp_outgoing_data(&pc->sctp, message, len, PPID_STRING, sid); + else + return sctp_outgoing_data(&pc->sctp, message, len, PPID_BINARY, sid); } static void peer_connection_state_new(PeerConnection *pc) { @@ -402,9 +410,9 @@ int peer_connection_loop(PeerConnection *pc) { if (data) { if (pc->config.datachannel == DATA_CHANNEL_STRING) - sctp_outgoing_data(&pc->sctp, (char*)data, bytes, PPID_STRING); + sctp_outgoing_data(&pc->sctp, (char*)data, bytes, PPID_STRING, 0); else - sctp_outgoing_data(&pc->sctp, (char*)data, bytes, PPID_BINARY); + sctp_outgoing_data(&pc->sctp, (char*)data, bytes, PPID_BINARY, 0); buffer_pop_head(pc->data_rb); } @@ -539,7 +547,7 @@ void peer_connection_oniceconnectionstatechange(PeerConnection *pc, } void peer_connection_ondatachannel(PeerConnection *pc, - void (*onmessasge)(char *msg, size_t len, void *userdata), + void (*onmessage)(char *msg, size_t len, void *userdata, uint16_t sid), void (*onopen)(void *userdata), void (*onclose)(void *userdata)) { @@ -547,7 +555,26 @@ void peer_connection_ondatachannel(PeerConnection *pc, sctp_onopen(&pc->sctp, onopen); sctp_onclose(&pc->sctp, onclose); - sctp_onmessage(&pc->sctp, onmessasge); + sctp_onmessage(&pc->sctp, onmessage); } } +int peer_connection_lookup_sid(PeerConnection *pc, const char *label, uint16_t *sid) { + for (int i = 0; i < pc->sctp.stream_count; i++) { + if (strncmp(pc->sctp.stream_table[i].label, label, sizeof(pc->sctp.stream_table[i].label)) == 0) { + *sid = pc->sctp.stream_table[i].sid; + return 0; + } + } + return -1; // Not found +} + +char *peer_connection_lookup_sid_label(PeerConnection *pc, uint16_t sid) { + for (int i = 0; i < pc->sctp.stream_count; i++) { + if (pc->sctp.stream_table[i].sid == sid) { + return pc->sctp.stream_table[i].label; + } + } + return NULL; // Not found +} + diff --git a/src/peer_connection.h b/src/peer_connection.h index 5454999..1b620e1 100644 --- a/src/peer_connection.h +++ b/src/peer_connection.h @@ -7,6 +7,7 @@ #include #include +#include "sctp.h" #ifdef __cplusplus extern "C" { @@ -77,6 +78,8 @@ const char* peer_connection_state_to_string(PeerConnectionState state); PeerConnectionState peer_connection_get_state(PeerConnection *pc); +Sctp *peer_connection_get_sctp(PeerConnection *pc); + PeerConnection* peer_connection_create(PeerConfiguration *config); void peer_connection_destroy(PeerConnection *pc); @@ -92,6 +95,8 @@ int peer_connection_loop(PeerConnection *pc); */ int peer_connection_datachannel_send(PeerConnection *pc, char *message, size_t len); +int peer_connection_datachannel_send_sid(PeerConnection *pc, char *message, size_t len, uint16_t sid); + int peer_connection_send_audio(PeerConnection *pc, const uint8_t *packet, size_t bytes); int peer_connection_send_video(PeerConnection *pc, const uint8_t *packet, size_t bytes); @@ -134,10 +139,14 @@ void peer_connection_oniceconnectionstatechange(PeerConnection *pc, * @param[in] callback function when connection is closed */ void peer_connection_ondatachannel(PeerConnection *pc, - void (*onmessasge)(char *msg, size_t len, void *userdata), + void (*onmessage)(char *msg, size_t len, void *userdata, uint16_t sid), void (*onopen)(void *userdata), void (*onclose)(void *userdata)); +int peer_connection_lookup_sid(PeerConnection *pc, const char *label, uint16_t *sid); + +char *peer_connection_lookup_sid_label(PeerConnection *pc, uint16_t sid); + #ifdef __cplusplus } #endif diff --git a/src/sctp.c b/src/sctp.c index 8b6b5ec..1a8a472 100644 --- a/src/sctp.c +++ b/src/sctp.c @@ -15,6 +15,7 @@ #define DATA_CHANNEL_PPID_BINARY_PARTIAL 52 #define DATA_CHANNEL_PPID_BINARY 53 #define DATA_CHANNEL_PPID_DOMSTRING_PARTIAL 54 +#define DATA_CHANNEL_OPEN 0x03 static const uint32_t crc32c_table[256] = { 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, @@ -108,21 +109,22 @@ static int sctp_outgoing_data_cb(void *userdata, void *buf, size_t len, uint8_t return 0; } -int sctp_outgoing_data(Sctp *sctp, char *buf, size_t len, SctpDataPpid ppid) { +int sctp_outgoing_data(Sctp *sctp, char *buf, size_t len, SctpDataPpid ppid, uint16_t sid) { #ifdef HAVE_USRSCTP + int res; struct sctp_sendv_spa spa = {0}; spa.sendv_flags = SCTP_SEND_SNDINFO_VALID; - spa.sendv_sndinfo.snd_sid = 0; + spa.sendv_sndinfo.snd_sid = sid; spa.sendv_sndinfo.snd_flags = SCTP_EOR; spa.sendv_sndinfo.snd_ppid = htonl(ppid); - if(usrsctp_sendv(sctp->sock, buf, len, NULL, 0, &spa, sizeof(spa), SCTP_SENDV_SPA, 0) < 0) { - LOGE("sctp sendv error"); - return -1; - } + res = usrsctp_sendv(sctp->sock, buf, len, NULL, 0, &spa, sizeof(spa), SCTP_SENDV_SPA, 0); + if(res < 0) + LOGE("sctp sendv error %d %s", errno, strerror(errno)); + return res; #else size_t padding_len = 0; size_t payload_max = SCTP_MTU - sizeof(SctpPacket) - sizeof(SctpDataChunk); @@ -176,15 +178,65 @@ int sctp_outgoing_data(Sctp *sctp, char *buf, size_t len, SctpDataPpid ppid) { return len; } +void sctp_add_stream_mapping(Sctp *sctp, const char *label, uint16_t sid) { + if (sctp->stream_countstream_table[sctp->stream_count].label, label, sizeof(sctp->stream_table[sctp->stream_count].label)); + sctp->stream_table[sctp->stream_count].sid = sid; + sctp->stream_count++; + } else + LOGE("Stream table full. Cannot add more streams."); +} + +void sctp_parse_data_channel_open(Sctp *sctp, uint16_t sid, char *data, size_t length) { + if (length < 12) + return; // Not enough data for a DATA_CHANNEL_OPEN message + + if (data[0]==DATA_CHANNEL_OPEN) { + uint16_t label_length = ntohs(*(uint16_t *)(data + 8)); + uint16_t protocol_length = ntohs(*(uint16_t *)(data + 10)); + + // Ensure we have enough data for the label and protocol + if (length < 12 + label_length + protocol_length) + return; + + char *label = (char *)(data + 12); + + // copy and null-terminate + char label_str[label_length + 1]; + memcpy(label_str, label, label_length); + label_str[label_length] = '\0'; + + // Log or process the DATA_CHANNEL_OPEN message + printf("DATA_CHANNEL_OPEN: Label=%s, sid=%d\n", label_str, sid); + + // Add stream mapping + sctp_add_stream_mapping(sctp, label_str, sid); + } +} + +void sctp_handle_sctp_packet(Sctp *sctp, char *buf, size_t len) { + if (len<=29) + return; + + if (buf[12]!=0) // if chunk_type is no zero, it's not data + return; + + uint16_t sid = ntohs(*(uint16_t *)(buf + 20)); + uint32_t ppid = ntohl(*(uint32_t *)(buf + 24)); + + if (ppid==DATA_CHANNEL_PPID_CONTROL) + sctp_parse_data_channel_open(sctp, sid, buf + 28, len - 28); +} + void sctp_incoming_data(Sctp *sctp, char *buf, size_t len) { if(!sctp) return; #ifdef HAVE_USRSCTP + sctp_handle_sctp_packet(sctp, buf, len); usrsctp_conninput(sctp, buf, len, 0); #else - size_t length = 0; size_t pos = sizeof(SctpHeader); SctpChunkCommon *chunk_common; @@ -220,6 +272,7 @@ void sctp_incoming_data(Sctp *sctp, char *buf, size_t len) { switch (chunk_common->type) { case SCTP_DATA: + data_chunk = (SctpDataChunk*)(buf + pos); LOGD("SCTP_DATA. ppid = %ld", ntohl(data_chunk->ppid)); @@ -231,8 +284,8 @@ void sctp_incoming_data(Sctp *sctp, char *buf, size_t len) { #endif if (ntohl(data_chunk->ppid) == DATA_CHANNEL_PPID_DOMSTRING) { - if (sctp->onmessasge) { - sctp->onmessasge((char*)data_chunk->data, ntohs(data_chunk->length) - sizeof(SctpDataChunk), sctp->userdata); + if (sctp->onmessage) { + sctp->onmessage((char*)data_chunk->data, ntohs(data_chunk->length) - sizeof(SctpDataChunk), sctp->userdata, ntohs(data_chunk->sid)); } } @@ -343,30 +396,23 @@ void sctp_incoming_data(Sctp *sctp, char *buf, size_t len) { } -static int sctp_handle_incoming_data(Sctp *sctp, char *data, size_t len, uint32_t ppid, uint16_t stream, int flags) { - +static int sctp_handle_incoming_data(Sctp *sctp, char *data, size_t len, uint32_t ppid, uint16_t sid, int flags) { #ifdef HAVE_USRSCTP - char *msg = NULL; - switch(ppid) { case DATA_CHANNEL_PPID_CONTROL: - break; - case DATA_CHANNEL_PPID_DOMSTRING: - msg = strndup(data, len); - LOGD("Got message %s (size = %ld)", msg, len); - if(msg && sctp->onmessasge) { - sctp->onmessasge(msg, len, sctp->userdata); - free(msg); - } - break; + case DATA_CHANNEL_PPID_DOMSTRING: case DATA_CHANNEL_PPID_BINARY: - break; case DATA_CHANNEL_PPID_DOMSTRING_PARTIAL: - break; case DATA_CHANNEL_PPID_BINARY_PARTIAL: + + LOGD("Got message (size = %ld)", len); + if(sctp->onmessage) { + sctp->onmessage(data, len, sctp->userdata, sid); + } break; + default: break; } @@ -400,7 +446,8 @@ static void sctp_process_notification(Sctp *sctp, union sctp_notification *notif break; case SCTP_COMM_LOST: - sctp->connected = 1; + case SCTP_SHUTDOWN_COMP: + sctp->connected = 0; if(sctp->onclose) { sctp->onclose(sctp->userdata); } @@ -411,7 +458,7 @@ static void sctp_process_notification(Sctp *sctp, union sctp_notification *notif default: break; } - + free(notification); // we need to free the memory that usrsctp allocates } static int sctp_incoming_data_cb(struct socket *sock, union sctp_sockstore addr, @@ -425,8 +472,7 @@ static int sctp_incoming_data_cb(struct socket *sock, union sctp_sockstore addr, ntohl(recv_info.rcv_ppid)); if(flags & MSG_NOTIFICATION) { sctp_process_notification(sctp, (union sctp_notification *)data, len); - } - else { + } else { sctp_handle_incoming_data(sctp, data, len, ntohl(recv_info.rcv_ppid), recv_info.rcv_sid, flags); } return 0; @@ -567,9 +613,9 @@ void sctp_destroy(Sctp *sctp) { #endif } -void sctp_onmessage(Sctp *sctp, void (*onmessasge)(char *msg, size_t len, void *userdata)) { +void sctp_onmessage(Sctp *sctp, void (*onmessage)(char *msg, size_t len, void *userdata, uint16_t sid)) { - sctp->onmessasge = onmessasge; + sctp->onmessage = onmessage; } void sctp_onopen(Sctp *sctp, void (*onopen)(void *userdata)) { diff --git a/src/sctp.h b/src/sctp.h index 70f29cb..ddcabca 100644 --- a/src/sctp.h +++ b/src/sctp.h @@ -105,7 +105,7 @@ typedef struct SctpDataChunk { uint8_t iube; uint16_t length; uint32_t tsn; - uint16_t si; + uint16_t sid; uint16_t sqn; uint32_t ppid; uint8_t data[0]; @@ -136,7 +136,12 @@ typedef enum SctpDataPpid { } SctpDataPpid; -typedef struct Sctp Sctp; +#define SCTP_MAX_STREAMS 5 + +typedef struct { + char label[32]; // Stream label + uint16_t sid; // Stream ID +} SctpStreamEntry; typedef struct Sctp { @@ -149,8 +154,11 @@ typedef struct Sctp { uint32_t tsn; DtlsSrtp *dtls_srtp; Buffer **data_rb; + int stream_count; + SctpStreamEntry stream_table[SCTP_MAX_STREAMS]; + /* datachannel */ - void (*onmessasge)(char *msg, size_t len, void *userdata); + void (*onmessage)(char *msg, size_t len, void *userdata, uint16_t sid); void (*onopen)(void *userdata); void (*onclose)(void *userdata); @@ -169,9 +177,9 @@ int sctp_is_connected(Sctp *sctp); void sctp_incoming_data(Sctp *sctp, char *buf, size_t len); -int sctp_outgoing_data(Sctp *sctp, char *buf, size_t len, SctpDataPpid ppid); +int sctp_outgoing_data(Sctp *sctp, char *buf, size_t len, SctpDataPpid ppid, uint16_t sid); -void sctp_onmessage(Sctp *sctp, void (*onmessasge)(char *msg, size_t len, void *userdata)); +void sctp_onmessage(Sctp *sctp, void (*onmessage)(char *msg, size_t len, void *userdata, uint16_t sid)); void sctp_onopen(Sctp *sctp, void (*onopen)(void *userdata));