diff --git a/dtls.c b/dtls.c index ba29380777..aab300c5a3 100644 --- a/dtls.c +++ b/dtls.c @@ -1052,10 +1052,10 @@ void janus_dtls_sctp_data_ready(janus_dtls_srtp *dtls) { janus_ice_notify_data_ready(handle); } -void janus_dtls_wrap_sctp_data(janus_dtls_srtp *dtls, char *label, gboolean textdata, char *buf, int len) { +void janus_dtls_wrap_sctp_data(janus_dtls_srtp *dtls, char *label, char *protocol, gboolean textdata, char *buf, int len) { if(dtls == NULL || !dtls->ready || dtls->sctp == NULL || buf == NULL || len < 1) return; - janus_sctp_send_data(dtls->sctp, label, textdata, buf, len); + janus_sctp_send_data(dtls->sctp, label, protocol, textdata, buf, len); } int janus_dtls_send_sctp_data(janus_dtls_srtp *dtls, char *buf, int len) { @@ -1069,7 +1069,7 @@ int janus_dtls_send_sctp_data(janus_dtls_srtp *dtls, char *buf, int len) { return res; } -void janus_dtls_notify_sctp_data(janus_dtls_srtp *dtls, char *label, gboolean textdata, char *buf, int len) { +void janus_dtls_notify_sctp_data(janus_dtls_srtp *dtls, char *label, char *protocol, gboolean textdata, char *buf, int len) { if(dtls == NULL || buf == NULL || len < 1) return; janus_ice_component *component = (janus_ice_component *)dtls->component; @@ -1087,7 +1087,7 @@ void janus_dtls_notify_sctp_data(janus_dtls_srtp *dtls, char *label, gboolean te JANUS_LOG(LOG_ERR, "No handle...\n"); return; } - janus_ice_incoming_data(handle, label, textdata, buf, len); + janus_ice_incoming_data(handle, label, protocol, textdata, buf, len); } #endif diff --git a/dtls.h b/dtls.h index f69a4a6d7b..152c0e2024 100644 --- a/dtls.h +++ b/dtls.h @@ -154,10 +154,11 @@ void janus_dtls_sctp_data_ready(janus_dtls_srtp *dtls); /*! \brief Callback (called from the ICE handle) to encapsulate in DTLS outgoing SCTP data (DataChannel) * @param[in] dtls The janus_dtls_srtp instance to use * @param[in] label The label of the data channel to use + * @param[in] protocol The protocol of the data channel to use * @param[in] textdata Whether the buffer is text (domstring) or binary data * @param[in] buf The data buffer to encapsulate * @param[in] len The data length */ -void janus_dtls_wrap_sctp_data(janus_dtls_srtp *dtls, char *label, gboolean textdata, char *buf, int len); +void janus_dtls_wrap_sctp_data(janus_dtls_srtp *dtls, char *label, char *protocol, gboolean textdata, char *buf, int len); /*! \brief Callback (called from the SCTP stack) to encapsulate in DTLS outgoing SCTP data (DataChannel) * @param[in] dtls The janus_dtls_srtp instance to use @@ -169,10 +170,11 @@ int janus_dtls_send_sctp_data(janus_dtls_srtp *dtls, char *buf, int len); /*! \brief Callback to be notified about incoming SCTP data (DataChannel) to forward to the handle * @param[in] dtls The janus_dtls_srtp instance to use * @param[in] label The label of the data channel the message is from + * @param[in] protocol The protocol of the data channel the message is from * @param[in] textdata Whether the buffer is text (domstring) or binary data * @param[in] buf The data buffer * @param[in] len The data length */ -void janus_dtls_notify_sctp_data(janus_dtls_srtp *dtls, char *label, gboolean textdata, char *buf, int len); +void janus_dtls_notify_sctp_data(janus_dtls_srtp *dtls, char *label, char *protocol, gboolean textdata, char *buf, int len); #endif /*! \brief DTLS retransmission timer diff --git a/html/janus.js b/html/janus.js index 109f73cb78..4f911e26cb 100644 --- a/html/janus.js +++ b/html/janus.js @@ -1420,7 +1420,7 @@ function Janus(gatewayCallbacks) { } // Private method to create a data channel - function createDataChannel(handleId, dclabel, incoming, pendingData) { + function createDataChannel(handleId, dclabel, dcprotocol, incoming, pendingData) { var pluginHandle = pluginHandles[handleId]; if(!pluginHandle || !pluginHandle.webrtcStuff) { Janus.warn("Invalid handle"); @@ -1435,6 +1435,7 @@ function Janus(gatewayCallbacks) { var onDataChannelStateChange = function(event) { Janus.log('Received state change on data channel:', event); var label = event.target.label; + var protocol = event.target.protocol; var dcState = config.dataChannel[label] ? config.dataChannel[label].readyState : "null"; Janus.log('State change on <' + label + '> data channel: ' + dcState); if(dcState === 'open') { @@ -1449,7 +1450,7 @@ function Janus(gatewayCallbacks) { config.dataChannel[label].pending = []; } // Notify the open data channel - pluginHandle.ondataopen(label); + pluginHandle.ondataopen(label, protocol); } }; var onDataChannelError = function(error) { @@ -1458,7 +1459,10 @@ function Janus(gatewayCallbacks) { }; if(!incoming) { // FIXME Add options (ordered, maxRetransmits, etc.) - config.dataChannel[dclabel] = config.pc.createDataChannel(dclabel, {ordered: true}); + var dcoptions = { ordered: true }; + if(dcprotocol) + dcoptions.protocol = dcprotocol; + config.dataChannel[dclabel] = config.pc.createDataChannel(dclabel, dcoptions); } else { // The channel was created by Janus config.dataChannel[dclabel] = incoming; @@ -1493,7 +1497,7 @@ function Janus(gatewayCallbacks) { var label = callbacks.label ? callbacks.label : Janus.dataChanDefaultLabel; if(!config.dataChannel[label]) { // Create new data channel and wait for it to open - createDataChannel(handleId, label, false, data); + createDataChannel(handleId, label, callbacks.protocol, false, data, callbacks.protocol); callbacks.success(); return; } @@ -1839,11 +1843,11 @@ function Janus(gatewayCallbacks) { } // Any data channel to create? if(isDataEnabled(media) && !config.dataChannel[Janus.dataChanDefaultLabel]) { - Janus.log("Creating data channel"); - createDataChannel(handleId, Janus.dataChanDefaultLabel, false); + Janus.log("Creating default data channel"); + createDataChannel(handleId, Janus.dataChanDefaultLabel, null, false); config.pc.ondatachannel = function(event) { Janus.log("Data channel created by Janus:", event); - createDataChannel(handleId, event.channel.label, event.channel); + createDataChannel(handleId, event.channel.label, event.channel.protocol, event.channel); }; } // If there's a new local stream, let's notify the application diff --git a/ice.c b/ice.c index 12a3f85895..01e2e64c9e 100644 --- a/ice.c +++ b/ice.c @@ -309,6 +309,7 @@ uint16_t rtp_range_max = 0; typedef struct janus_ice_queued_packet { char *data; char *label; + char *protocol; gint length; gint type; gboolean control; @@ -487,6 +488,7 @@ static void janus_ice_free_queued_packet(janus_ice_queued_packet *pkt) { } g_free(pkt->data); g_free(pkt->label); + g_free(pkt->protocol); g_free(pkt); } @@ -2921,6 +2923,7 @@ static void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint comp pkt->control = FALSE; pkt->retransmission = TRUE; pkt->label = NULL; + pkt->protocol = NULL; pkt->added = janus_get_monotonic_time(); /* What to send and how depends on whether we're doing RFC4588 or not */ if(!video || !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RFC4588_RTX)) { @@ -3005,7 +3008,7 @@ static void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint comp } } -void janus_ice_incoming_data(janus_ice_handle *handle, char *label, gboolean textdata, char *buffer, int length) { +void janus_ice_incoming_data(janus_ice_handle *handle, char *label, char *protocol, gboolean textdata, char *buffer, int length) { if(handle == NULL || buffer == NULL || length <= 0) return; janus_plugin_data data = { .label = label, .binary = !textdata, .buffer = buffer, .length = length }; @@ -4498,7 +4501,8 @@ static gboolean janus_ice_outgoing_traffic_handle(janus_ice_handle *handle, janu } component->noerrorlog = FALSE; /* TODO Support binary data */ - janus_dtls_wrap_sctp_data(component->dtls, pkt->label, pkt->type == JANUS_ICE_PACKET_TEXT, pkt->data, pkt->length); + janus_dtls_wrap_sctp_data(component->dtls, pkt->label, pkt->protocol, + pkt->type == JANUS_ICE_PACKET_TEXT, pkt->data, pkt->length); #endif } else if(pkt->type == JANUS_ICE_PACKET_SCTP) { /* SCTP data to push */ @@ -4649,6 +4653,7 @@ void janus_ice_relay_rtp(janus_ice_handle *handle, janus_plugin_rtp *packet) { pkt->encrypted = FALSE; pkt->retransmission = FALSE; pkt->label = NULL; + pkt->protocol = NULL; pkt->added = janus_get_monotonic_time(); janus_ice_queue_packet(handle, pkt); /* Restore the extension flag to what the plugin set it to */ @@ -4692,6 +4697,7 @@ void janus_ice_relay_rtcp_internal(janus_ice_handle *handle, janus_plugin_rtcp * pkt->encrypted = FALSE; pkt->retransmission = FALSE; pkt->label = NULL; + pkt->protocol = NULL; pkt->added = janus_get_monotonic_time(); janus_ice_queue_packet(handle, pkt); if(rtcp_buf != packet->buffer) { @@ -4757,6 +4763,7 @@ void janus_ice_relay_data(janus_ice_handle *handle, janus_plugin_data *packet) { pkt->encrypted = FALSE; pkt->retransmission = FALSE; pkt->label = packet->label ? g_strdup(packet->label) : NULL; + pkt->protocol = packet->protocol ? g_strdup(packet->protocol) : NULL; pkt->added = janus_get_monotonic_time(); janus_ice_queue_packet(handle, pkt); } @@ -4776,6 +4783,7 @@ void janus_ice_relay_sctp(janus_ice_handle *handle, char *buffer, int length) { pkt->encrypted = FALSE; pkt->retransmission = FALSE; pkt->label = NULL; + pkt->protocol = NULL; pkt->added = janus_get_monotonic_time(); janus_ice_queue_packet(handle, pkt); #endif diff --git a/ice.h b/ice.h index ab94a74bc6..68de20c668 100644 --- a/ice.h +++ b/ice.h @@ -632,10 +632,11 @@ void janus_ice_send_remb(janus_ice_handle *handle, uint32_t bitrate); /*! \brief Plugin SCTP/DataChannel callback, called by the SCTP stack when when there's data for a plugin * @param[in] handle The Janus ICE handle associated with the peer * @param[in] label The label of the data channel the message is from + * @param[in] protocol The protocol of the data channel to use * @param[in] textdata Whether the buffer is text (domstring) or binary data * @param[in] buffer The message data (buffer) * @param[in] length The buffer length */ -void janus_ice_incoming_data(janus_ice_handle *handle, char *label, gboolean textdata, char *buffer, int length); +void janus_ice_incoming_data(janus_ice_handle *handle, char *label, char *protocol, gboolean textdata, char *buffer, int length); /*! \brief Core SCTP/DataChannel callback, called by the SCTP stack when when there's data to send. * @param[in] handle The Janus ICE handle associated with the peer * @param[in] buffer The message data (buffer) diff --git a/plugins/janus_duktape.c b/plugins/janus_duktape.c index d5bbc26485..4ce44b1e28 100644 --- a/plugins/janus_duktape.c +++ b/plugins/janus_duktape.c @@ -1079,7 +1079,13 @@ static duk_ret_t janus_duktape_method_relaytextdata(duk_context *ctx) { return duk_throw(ctx); } /* Send the data */ - janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = (char *)payload, .length = len }; + janus_plugin_data data = { + .label = NULL, + .protocol = NULL, + .binary = TRUE, + .buffer = (char *)payload, + .length = len + }; janus_core->relay_data(session->handle, &data); janus_refcount_decrease(&session->ref); duk_push_int(ctx, 0); @@ -1126,7 +1132,13 @@ static duk_ret_t janus_duktape_method_relaybinarydata(duk_context *ctx) { duk_push_error_object(ctx, DUK_ERR_ERROR, "Datachannel not ready yet for session %"SCNu32, id); return duk_throw(ctx); } - janus_plugin_data data = { .label = NULL, .binary = TRUE, .buffer = (char *)payload, .length = len }; + janus_plugin_data data = { + .label = NULL, + .protocol = NULL, + .binary = TRUE, + .buffer = (char *)payload, + .length = len + }; janus_core->relay_data(session->handle, &data); janus_refcount_decrease(&session->ref); duk_push_int(ctx, 0); @@ -2488,8 +2500,13 @@ static void janus_duktape_relay_data_packet(gpointer data, gpointer user_data) { if(janus_core != NULL) { JANUS_LOG(LOG_VERB, "Forwarding %s DataChannel message (%d bytes) to session %"SCNu32"\n", packet->textdata ? "text" : "binary", packet->length, session->id); - janus_plugin_data data = { .label = NULL, .binary = !packet->textdata, - .buffer = (char *)packet->data, .length = packet->length }; + janus_plugin_data data = { + .label = NULL, + .protocol = NULL, + .binary = !packet->textdata, + .buffer = (char *)packet->data, + .length = packet->length + }; janus_core->relay_data(session->handle, &data); } return; diff --git a/plugins/janus_lua.c b/plugins/janus_lua.c index 74224207f3..d1c4a58dde 100644 --- a/plugins/janus_lua.c +++ b/plugins/janus_lua.c @@ -955,7 +955,13 @@ static int janus_lua_method_relaytextdata(lua_State *s) { return 1; } /* Send the data */ - janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = (char *)payload, .length = len }; + janus_plugin_data data = { + .label = NULL, + .protocol = NULL, + .binary = FALSE, + .buffer = (char *)payload, + .length = len + }; janus_core->relay_data(session->handle, &data); janus_refcount_decrease(&session->ref); lua_pushnumber(s, 0); @@ -996,7 +1002,13 @@ static int janus_lua_method_relaybinarydata(lua_State *s) { return 1; } /* Send the data */ - janus_plugin_data data = { .label = NULL, .binary = TRUE, .buffer = (char *)payload, .length = len }; + janus_plugin_data data = { + .label = NULL, + .protocol = NULL, + .binary = TRUE, + .buffer = (char *)payload, + .length = len + }; janus_core->relay_data(session->handle, &data); janus_refcount_decrease(&session->ref); lua_pushnumber(s, 0); @@ -2158,8 +2170,13 @@ static void janus_lua_relay_data_packet(gpointer data, gpointer user_data) { if(janus_core != NULL) { JANUS_LOG(LOG_VERB, "Forwarding %s DataChannel message (%d bytes) to session %"SCNu32"\n", packet->textdata ? "text" : "binary", packet->length, session->id); - janus_plugin_data data = { .label = NULL, .binary = !packet->textdata, - .buffer = (char *)packet->data, .length = packet->length }; + janus_plugin_data data = { + .label = NULL, + .protocol = NULL, + .binary = !packet->textdata, + .buffer = (char *)packet->data, + .length = packet->length + }; janus_core->relay_data(session->handle, &data); } return; diff --git a/plugins/janus_streaming.c b/plugins/janus_streaming.c index 9c2f96a395..a77e936362 100644 --- a/plugins/janus_streaming.c +++ b/plugins/janus_streaming.c @@ -8215,8 +8215,13 @@ static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data) if(!session->data) return; if(gateway != NULL && packet->data != NULL && g_atomic_int_get(&session->dataready)) { - janus_plugin_data data = { .label = NULL, .binary = !packet->textdata, - .buffer = (char *)packet->data, .length = packet->length }; + janus_plugin_data data = { + .label = NULL, + .protocol = NULL, + .binary = !packet->textdata, + .buffer = (char *)packet->data, + .length = packet->length + }; gateway->relay_data(session->handle, &data); } } diff --git a/plugins/janus_textroom.c b/plugins/janus_textroom.c index 6e4c46df16..8f88dae25b 100644 --- a/plugins/janus_textroom.c +++ b/plugins/janus_textroom.c @@ -1524,7 +1524,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session janus_textroom_participant *top = g_hash_table_lookup(textroom->participants, to); if(top) { janus_refcount_increase(&top->ref); - janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = msg_text, .length = strlen(msg_text) }; + janus_plugin_data data = { .label = NULL, .protocol = NULL, .binary = FALSE, .buffer = msg_text, .length = strlen(msg_text) }; gateway->relay_data(top->session->handle, &data); janus_refcount_decrease(&top->ref); json_object_set_new(sent, to, json_true()); @@ -1544,7 +1544,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session janus_textroom_participant *top = g_hash_table_lookup(textroom->participants, to); if(top) { janus_refcount_increase(&top->ref); - janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = msg_text, .length = strlen(msg_text) }; + janus_plugin_data data = { .label = NULL, .protocol = NULL, .binary = FALSE, .buffer = msg_text, .length = strlen(msg_text) }; gateway->relay_data(top->session->handle, &data); janus_refcount_decrease(&top->ref); json_object_set_new(sent, to, json_true()); @@ -1565,7 +1565,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session janus_textroom_participant *top = value; JANUS_LOG(LOG_VERB, " >> To %s in %s: %s\n", top->username, room_id_str, message); janus_refcount_increase(&top->ref); - janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = msg_text, .length = strlen(msg_text) }; + janus_plugin_data data = { .label = NULL, .protocol = NULL, .binary = FALSE, .buffer = msg_text, .length = strlen(msg_text) }; gateway->relay_data(top->session->handle, &data); janus_refcount_decrease(&top->ref); } @@ -1714,7 +1714,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session json_object_set_new(event, "display", json_string(display_text)); char *event_text = json_dumps(event, json_format); json_decref(event); - janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = event_text, .length = strlen(event_text) }; + janus_plugin_data data = { .label = NULL, .protocol = NULL, .binary = FALSE, .buffer = event_text, .length = strlen(event_text) }; gateway->relay_data(handle, &data); /* Broadcast */ GHashTableIter iter; @@ -1818,7 +1818,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session json_object_set_new(event, "username", json_string(participant->username)); char *event_text = json_dumps(event, json_format); json_decref(event); - janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = event_text, .length = strlen(event_text) }; + janus_plugin_data data = { .label = NULL, .protocol = NULL, .binary = FALSE, .buffer = event_text, .length = strlen(event_text) }; gateway->relay_data(handle, &data); /* Broadcast */ GHashTableIter iter; @@ -2140,7 +2140,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session while(g_hash_table_iter_next(&iter, NULL, &value)) { janus_textroom_participant *top = value; JANUS_LOG(LOG_VERB, " >> To %s in %s\n", top->username, room_id_str); - janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = event_text, .length = strlen(event_text) }; + janus_plugin_data data = { .label = NULL, .protocol = NULL, .binary = FALSE, .buffer = event_text, .length = strlen(event_text) }; gateway->relay_data(top->session->handle, &data); } free(event_text); @@ -2242,7 +2242,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session janus_textroom_participant *top = value; JANUS_LOG(LOG_VERB, " >> To %s in %s: %s\n", top->username, room_id_str, message); janus_refcount_increase(&top->ref); - janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = msg_text, .length = strlen(msg_text) }; + janus_plugin_data data = { .label = NULL, .protocol = NULL, .binary = FALSE, .buffer = msg_text, .length = strlen(msg_text) }; gateway->relay_data(top->session->handle, &data); janus_refcount_decrease(&top->ref); } @@ -2738,7 +2738,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session json_object_set_new(event, "room", string_ids ? json_string(textroom->room_id_str) : json_integer(textroom->room_id)); char *event_text = json_dumps(event, json_format); json_decref(event); - janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = event_text, .length = strlen(event_text) }; + janus_plugin_data data = { .label = NULL, .protocol = NULL, .binary = FALSE, .buffer = event_text, .length = strlen(event_text) }; gateway->relay_data(handle, &data); /* Broadcast */ GHashTableIter iter; @@ -2803,7 +2803,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session /* Reply via data channels */ char *reply_text = json_dumps(reply, json_format); json_decref(reply); - janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = reply_text, .length = strlen(reply_text) }; + janus_plugin_data data = { .label = NULL, .protocol = NULL, .binary = FALSE, .buffer = reply_text, .length = strlen(reply_text) }; gateway->relay_data(handle, &data); free(reply_text); } else { diff --git a/plugins/janus_videocall.c b/plugins/janus_videocall.c index 3bee0e5f3b..7140dace19 100644 --- a/plugins/janus_videocall.c +++ b/plugins/janus_videocall.c @@ -881,6 +881,7 @@ void janus_videocall_incoming_data(janus_plugin_session *handle, janus_plugin_da /* Forward the packet to the peer */ janus_plugin_data r = { .label = label, + .protocol = NULL, .binary = packet->binary, .buffer = buf, .length = len diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 2288b89ac7..6e82a17a70 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -5974,7 +5974,6 @@ static void *janus_videoroom_handler(void *data) { subscriber->paused = TRUE; /* We need an explicit start from the subscriber */ g_atomic_int_set(&subscriber->destroyed, 0); janus_refcount_init(&subscriber->ref, janus_videoroom_subscriber_free); - janus_refcount_increase(&subscriber->ref); /* This reference is for handling the setup */ janus_refcount_increase(&subscriber->ref); /* The publisher references the new subscriber too */ /* Check if a simulcasting-related request is involved */ janus_rtp_simulcasting_context_reset(&subscriber->sim_context); @@ -6054,10 +6053,8 @@ static void *janus_videoroom_handler(void *data) { json_decref(event); json_decref(jsep); janus_videoroom_message_free(msg); - janus_refcount_decrease(&subscriber->ref); continue; } - janus_refcount_decrease(&subscriber->ref); janus_mutex_unlock(&publisher->subscribers_mutex); } } else { @@ -7495,7 +7492,13 @@ static void janus_videoroom_relay_data_packet(gpointer data, gpointer user_data) if(gateway != NULL && packet->data != NULL) { JANUS_LOG(LOG_VERB, "Forwarding %s DataChannel message (%d bytes) to viewer\n", packet->textdata ? "text" : "binary", packet->length); - janus_plugin_data data = { .label = NULL, .binary = !packet->textdata, .buffer = (char *)packet->data, .length = packet->length }; + janus_plugin_data data = { + .label = NULL, + .protocol = NULL, + .binary = !packet->textdata, + .buffer = (char *)packet->data, + .length = packet->length + }; gateway->relay_data(session->handle, &data); } return; diff --git a/plugins/plugin.h b/plugins/plugin.h index 3f583db96c..7794dd4923 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -372,6 +372,9 @@ struct janus_callbacks { * @param[in] packet The RTCP packet and related data */ void (* const relay_rtcp)(janus_plugin_session *handle, janus_plugin_rtcp *packet); /*! \brief Callback to relay SCTP/DataChannel messages to a peer + * @note The protocol is only used for the first message sent on a new data + * channel, as it will be used to create it; it will be ignored for following + * messages on the same label, so you can set NULL after that * @param[in] handle The plugin/gateway session that will be used for this peer * @param[in] packet The message data and related info */ void (* const relay_data)(janus_plugin_session *handle, janus_plugin_data *packet); @@ -603,6 +606,8 @@ void janus_plugin_rtcp_reset(janus_plugin_rtcp *packet); struct janus_plugin_data { /*! \brief The label this message belongs to */ char *label; + /*! \brief The subprotocol this message refers to */ + char *protocol; /*! \brief Whether the message data is text (default=FALSE) or binary */ gboolean binary; /*! \brief The message data */ diff --git a/sctp.c b/sctp.c index 555463b266..f85610466d 100644 --- a/sctp.c +++ b/sctp.c @@ -95,11 +95,11 @@ janus_sctp_channel *janus_sctp_find_channel_by_stream(janus_sctp_association *sc janus_sctp_channel *janus_sctp_find_free_channel(janus_sctp_association *sctp); uint16_t janus_sctp_find_free_stream(janus_sctp_association *sctp); void janus_sctp_request_more_streams(janus_sctp_association *sctp); -int janus_sctp_send_open_request_message(struct socket *sock, uint16_t stream, char *label, uint8_t unordered, uint16_t pr_policy, uint32_t pr_value); +int janus_sctp_send_open_request_message(struct socket *sock, uint16_t stream, char *label, char *protocol, uint8_t unordered, uint16_t pr_policy, uint32_t pr_value); int janus_sctp_send_open_response_message(struct socket *sock, uint16_t stream); int janus_sctp_send_open_ack_message(struct socket *sock, uint16_t stream); void janus_sctp_send_deferred_messages(janus_sctp_association *sctp); -int janus_sctp_open_channel(janus_sctp_association *sctp, char *label, uint8_t unordered, uint16_t pr_policy, uint32_t pr_value); +int janus_sctp_open_channel(janus_sctp_association *sctp, char *label, char *protocol, uint8_t unordered, uint16_t pr_policy, uint32_t pr_value); int janus_sctp_send_text_or_binary(janus_sctp_association *sctp, uint16_t id, gboolean textdata, char *text, size_t length); void janus_sctp_reset_outgoing_stream(janus_sctp_association *sctp, uint16_t stream); void janus_sctp_send_outgoing_stream_reset(janus_sctp_association *sctp); @@ -374,7 +374,7 @@ static int janus_sctp_incoming_data(struct socket *sock, union sctp_sockstore ad return 1; } -void janus_sctp_send_data(janus_sctp_association *sctp, char *label, gboolean textdata, char *buf, int len) { +void janus_sctp_send_data(janus_sctp_association *sctp, char *label, char *protocol, gboolean textdata, char *buf, int len) { if(sctp == NULL) return; if(sctp->pending_messages != NULL && !g_queue_is_empty(sctp->pending_messages)) { @@ -412,7 +412,7 @@ void janus_sctp_send_data(janus_sctp_association *sctp, char *label, gboolean te if(!found) { /* There's no open channel, try opening one now */ JANUS_LOG(LOG_VERB, "[%"SCNu64"] Creating channel '%s'...\n", sctp->handle_id, label); - if(janus_sctp_open_channel(sctp, label, 0, 0, 0) < 0) { + if(janus_sctp_open_channel(sctp, label, protocol, 0, 0, 0) < 0) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Couldn't open channel...\n", sctp->handle_id); return; } @@ -541,7 +541,7 @@ void janus_sctp_request_more_streams(janus_sctp_association *sctp) { return; } -int janus_sctp_send_open_request_message(struct socket *sock, uint16_t stream, char *label, uint8_t unordered, uint16_t pr_policy, uint32_t pr_value) { +int janus_sctp_send_open_request_message(struct socket *sock, uint16_t stream, char *label, char *protocol, uint8_t unordered, uint16_t pr_policy, uint32_t pr_value) { /* XXX: This should be encoded in a better way */ janus_datachannel_open_request *req = NULL; struct sctp_sndinfo sndinfo; @@ -549,10 +549,12 @@ int janus_sctp_send_open_request_message(struct socket *sock, uint16_t stream, c /* Use the default label, if none was provided */ if(label == NULL) label = (char *)default_label; - guint label_size = (strlen(label)+3) & ~3; - JANUS_LOG(LOG_VERB, "Opening channel with label '%s' (%zu, %u with padding)\n", label, strlen(label), label_size); + size_t label_size = strlen(label); + size_t protocol_size = protocol ? strlen(protocol) : 0; + JANUS_LOG(LOG_VERB, "Opening channel with label '%s' (%zu, protocol %s)\n", + label, label_size, (protocol ? protocol : "unknown")); - req = g_malloc0(sizeof(janus_datachannel_open_request) + label_size); + req = g_malloc0(sizeof(janus_datachannel_open_request) + label_size + protocol_size); req->msg_type = DATA_CHANNEL_OPEN_REQUEST; switch (pr_policy) { case SCTP_PR_SCTP_NONE: @@ -572,7 +574,10 @@ int janus_sctp_send_open_request_message(struct socket *sock, uint16_t stream, c req->priority = htons(0); /* XXX: add support */ req->reliability_params = htonl((uint32_t)pr_value); req->label_length = htons(label_size); - memcpy(&req->label, label, strlen(label)); + req->protocol_length = htons(protocol_size); + memcpy(req->label, label, label_size); + if(protocol != NULL) + memcpy(req->label + label_size, protocol, protocol_size); memset(&sndinfo, 0, sizeof(struct sctp_sndinfo)); sndinfo.snd_sid = stream; @@ -580,7 +585,7 @@ int janus_sctp_send_open_request_message(struct socket *sock, uint16_t stream, c sndinfo.snd_ppid = htonl(DATA_CHANNEL_PPID_CONTROL); if(usrsctp_sendv(sock, - req, sizeof(janus_datachannel_open_request) + label_size, + req, sizeof(janus_datachannel_open_request) + label_size + protocol_size, NULL, 0, &sndinfo, (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) { @@ -652,7 +657,7 @@ void janus_sctp_send_deferred_messages(janus_sctp_association *sctp) { channel = &(sctp->channels[i]); if(channel->flags & DATA_CHANNEL_FLAGS_SEND_REQ) { if(janus_sctp_send_open_request_message(sctp->sock, channel->stream, - channel->label, channel->unordered, channel->pr_policy, channel->pr_value)) { + channel->label, channel->protocol, channel->unordered, channel->pr_policy, channel->pr_value)) { channel->flags &= ~DATA_CHANNEL_FLAGS_SEND_REQ; } else { if(errno != EAGAIN) { @@ -682,7 +687,7 @@ void janus_sctp_send_deferred_messages(janus_sctp_association *sctp) { return; } -int janus_sctp_open_channel(janus_sctp_association *sctp, char *label, uint8_t unordered, uint16_t pr_policy, uint32_t pr_value) { +int janus_sctp_open_channel(janus_sctp_association *sctp, char *label, char *protocol, uint8_t unordered, uint16_t pr_policy, uint32_t pr_value) { if(sctp == NULL) return -1; janus_sctp_channel *channel; @@ -710,10 +715,13 @@ int janus_sctp_open_channel(janus_sctp_association *sctp, char *label, uint8_t u channel->stream = stream; channel->flags = 0; g_snprintf(channel->label, sizeof(channel->label), "%s", (label ? label : default_label)); + channel->protocol[0] = '\0'; + if(protocol != NULL) + g_snprintf(channel->protocol, sizeof(channel->protocol), "%s", protocol); if(stream == 0) { janus_sctp_request_more_streams(sctp); } else { - if(janus_sctp_send_open_request_message(sctp->sock, stream, channel->label, unordered, pr_policy, pr_value)) { + if(janus_sctp_send_open_request_message(sctp->sock, stream, channel->label, channel->protocol, unordered, pr_policy, pr_value)) { sctp->stream_channel[stream] = channel; } else { if(errno == EAGAIN) { @@ -721,6 +729,7 @@ int janus_sctp_open_channel(janus_sctp_association *sctp, char *label, uint8_t u channel->flags |= DATA_CHANNEL_FLAGS_SEND_REQ; } else { channel->label[0] = '\0'; + channel->protocol[0] = '\0'; channel->state = DATA_CHANNEL_CLOSED; channel->unordered = 0; channel->pr_policy = 0; @@ -847,6 +856,7 @@ void janus_sctp_handle_open_request_message(janus_sctp_association *sctp, janus_ if((channel = janus_sctp_find_channel_by_stream(sctp, stream))) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] channel %d is in state %d instead of CLOSED.\n", sctp->handle_id, channel->id, channel->state); + JANUS_LOG(LOG_ERR, "%.*s\n", req->label_length, req->label); /* XXX: some error handling */ return; } @@ -903,6 +913,7 @@ void janus_sctp_handle_open_request_message(janus_sctp_association *sctp, janus_ /* XXX: Signal error to the other end */ sctp->stream_channel[stream] = NULL; channel->label[0] = '\0'; + channel->protocol[0] = '\0'; channel->state = DATA_CHANNEL_CLOSED; channel->unordered = 0; channel->pr_policy = 0; @@ -920,10 +931,19 @@ void janus_sctp_handle_open_request_message(janus_sctp_association *sctp, janus_ label[len] = '\0'; g_snprintf(channel->label, sizeof(channel->label), "%s", label); } - JANUS_LOG(LOG_VERB, "[%"SCNu64"] Opened channel '%s' (id=%"SCNu16") (%d/%d/%d)\n", - sctp->handle_id, label ? label : "??", + char *protocol = NULL; + guint plen = ntohs(req->protocol_length); + if(plen > 0 && plen < length) { + protocol = g_malloc(plen+1); + memcpy(protocol, req->label+len, plen); + protocol[plen] = '\0'; + g_snprintf(channel->protocol, sizeof(channel->protocol), "%s", protocol); + } + JANUS_LOG(LOG_VERB, "[%"SCNu64"] Opened channel '%s' (protocol=%s, id=%"SCNu16") (%d/%d/%d)\n", + sctp->handle_id, label ? label : "??", protocol ? protocol : "??", channel->stream, channel->unordered, channel->pr_policy, channel->pr_value); g_free(label); + g_free(protocol); } void janus_sctp_handle_open_response_message(janus_sctp_association *sctp, janus_datachannel_open_response *rsp, size_t length, uint16_t stream) { @@ -1006,7 +1026,9 @@ void janus_sctp_handle_data_message(janus_sctp_association *sctp, gboolean textd JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming SCTP contents: %.*s\n", sctp->handle_id, (int)length, buffer); /* Pass this to the core */ - janus_dtls_notify_sctp_data(sctp->dtls, channel->label, textdata, buffer, (int)length); + janus_dtls_notify_sctp_data(sctp->dtls, channel->label, + strlen(channel->protocol) ? channel->protocol : NULL, + textdata, buffer, (int)length); } return; } diff --git a/sctp.h b/sctp.h index c49e840b6a..042e7dc3c9 100644 --- a/sctp.h +++ b/sctp.h @@ -82,6 +82,8 @@ typedef struct janus_sctp_channel { uint32_t id; /*! \brief SCTP channel label */ char label[64]; + /*! \brief SCTP protocol */ + char protocol[64]; /*! \brief Value of the PR-SCTP policy (http://tools.ietf.org/html/rfc6458) */ uint32_t pr_value; /*! \brief PR-SCTP policy to use (http://tools.ietf.org/html/rfc6458) */ @@ -164,7 +166,7 @@ typedef struct janus_datachannel_open_request { uint16_t protocol_length; /*! \brief Optional label */ char label[0]; - /* We ignore the Protocol field */ + /* The Protocol field will come after the label, if available */ } janus_datachannel_open_request; typedef struct janus_datachannel_open_response { @@ -205,10 +207,11 @@ void janus_sctp_data_from_dtls(janus_sctp_association *sctp, char *buf, int len) /*! \brief Method to send data via SCTP to the peer * \param[in] sctp The SCTP association this data is from * @param[in] label The label of the data channel to use + * @param[in] protocol The protocol of the data channel to use * @param[in] textdata Whether the buffer is text (domstring) or binary data * \param[in] buf The data buffer * \param[in] len The buffer length */ -void janus_sctp_send_data(janus_sctp_association *sctp, char *label, gboolean textdata, char *buf, int len); +void janus_sctp_send_data(janus_sctp_association *sctp, char *label, char *protocol, gboolean textdata, char *buf, int len); #endif