Sessions (0 )
diff --git a/html/admin.js b/html/admin.js
index 9e4121099b2..269a756bf28 100644
--- a/html/admin.js
+++ b/html/admin.js
@@ -16,6 +16,7 @@ var session = null; // Selected session
var handle = null; // Selected handle
var plugins = [], pluginsIndex = [];
+var transports = [], transportsIndex = [];
var settings = {};
var currentHandle = null;
@@ -81,6 +82,8 @@ function randomString(len) {
function updateServerInfo() {
plugins = [];
pluginsIndex = [];
+ transports = [];
+ transportsIndex = [];
$.ajax({
type: 'GET',
url: server + "/info",
@@ -176,6 +179,7 @@ function updateServerInfo() {
''
);
for(var t in transportsJson) {
+ transports.push(t);
var v = transportsJson[t];
$('#server-transports').append(
'
' +
@@ -184,6 +188,19 @@ function updateServerInfo() {
' ' + v.description + ' ' +
' ' + v.version_string + ' ' +
' ');
+ transportsIndex.push(t);
+ $('#transports-list').append(
+ '
'+t+' '
+ );
+ $('#transport-'+(transportsIndex.length-1)).click(function(event) {
+ event.preventDefault();
+ var ti = parseInt($(this).attr('id').split('transport-')[1]);
+ var transport = transportsIndex[ti];
+ console.log("Selected transport:", transport);
+ $('#transports-list a').removeClass('active');
+ $('#transport-'+ti).addClass('active');
+ resetTransportRequest();
+ });
}
$('#server-handlers').html(
'
' +
@@ -688,6 +705,129 @@ function sendPluginMessage(plugin, message) {
});
}
+// Transports
+function resetTransportRequest() {
+ $('#transport-request').empty().append(
+ ' ' +
+ ' Name ' +
+ ' Value ' +
+ ' Type ' +
+ ' ' +
+ ' ' +
+ '
' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' Send message ' +
+ ' ');
+ $('#addattr').click(addTransportMessageAttribute).click();
+ $('#sendmsg').click(function() {
+ var message = {};
+ var num = $('.pm-property').length;
+ for(var i=0; i
' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' string ' +
+ ' number ' +
+ ' boolean ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ''
+ );
+}
+
+function sendTransportMessage(transport, message) {
+ console.log("Sending message to " + transport + ":", message);
+ var request = {
+ janus: "query_transport",
+ transaction: randomString(12),
+ admin_secret: secret,
+ transport: transport,
+ request: message
+ };
+ $.ajax({
+ type: 'POST',
+ url: server,
+ cache: false,
+ contentType: "application/json",
+ data: JSON.stringify(request),
+ success: function(json) {
+ if(json["janus"] !== "success") {
+ console.log("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
+ var authenticate = (json["error"].code === 403);
+ if(!authenticate || (authenticate && !prompting && !alerted)) {
+ if(authenticate)
+ alerted = true;
+ bootbox.alert(json["error"].reason, function() {
+ if(authenticate) {
+ promptAccessDetails();
+ alerted = false;
+ }
+ });
+ }
+ }
+ $('#transport-response').text(JSON.stringify(json, null, 4));
+ },
+ error: function(XMLHttpRequest, textStatus, errorThrown) {
+ console.log(textStatus + ": " + errorThrown); // FIXME
+ if(!prompting && !alerted) {
+ alerted = true;
+ bootbox.alert("Couldn't contact the backend: is Janus down, or is the Admin/Monitor interface disabled?", function() {
+ promptAccessDetails();
+ alerted = false;
+ });
+ }
+ },
+ dataType: "json"
+ });
+}
+
// Handles
function updateSessions() {
diff --git a/janus.c b/janus.c
index 420a882bd48..a3601ac659b 100644
--- a/janus.c
+++ b/janus.c
@@ -144,6 +144,10 @@ static struct janus_json_parameter st_parameters[] = {
static struct janus_json_parameter ans_parameters[] = {
{"accept", JANUS_JSON_BOOL, JANUS_JSON_PARAM_REQUIRED}
};
+static struct janus_json_parameter querytransport_parameters[] = {
+ {"transport", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
+ {"request", JSON_OBJECT, 0}
+};
static struct janus_json_parameter queryhandler_parameters[] = {
{"handler", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
{"request", JSON_OBJECT, 0}
@@ -2200,6 +2204,40 @@ int janus_process_incoming_admin_request(janus_request *request) {
/* Send the success reply */
ret = janus_process_success(request, reply);
goto jsondone;
+ } else if(!strcasecmp(message_text, "query_transport")) {
+ /* Contact a transport and expect a response */
+ JANUS_VALIDATE_JSON_OBJECT(root, querytransport_parameters,
+ error_code, error_cause, FALSE,
+ JANUS_ERROR_MISSING_MANDATORY_ELEMENT, JANUS_ERROR_INVALID_ELEMENT_TYPE);
+ if(error_code != 0) {
+ ret = janus_process_error_string(request, session_id, transaction_text, error_code, error_cause);
+ goto jsondone;
+ }
+ json_t *transport = json_object_get(root, "transport");
+ const char *transport_value = json_string_value(transport);
+ janus_transport *t = g_hash_table_lookup(transports, transport_value);
+ if(t == NULL) {
+ /* No such transport... */
+ g_snprintf(error_cause, sizeof(error_cause), "%s", "Invalid transport");
+ ret = janus_process_error_string(request, session_id, transaction_text, JANUS_ERROR_PLUGIN_NOT_FOUND, error_cause);
+ goto jsondone;
+ }
+ if(t->query_transport == NULL) {
+ /* Transport doesn't implement the hook... */
+ g_snprintf(error_cause, sizeof(error_cause), "%s", "Transport plugin doesn't support queries");
+ ret = janus_process_error_string(request, session_id, transaction_text, JANUS_ERROR_UNKNOWN, error_cause);
+ goto jsondone;
+ }
+ json_t *query = json_object_get(root, "request");
+ json_t *response = t->query_transport(query);
+ /* Prepare JSON reply */
+ json_t *reply = json_object();
+ json_object_set_new(reply, "janus", json_string("success"));
+ json_object_set_new(reply, "transaction", json_string(transaction_text));
+ json_object_set_new(reply, "response", response ? response : json_object());
+ /* Send the success reply */
+ ret = janus_process_success(request, reply);
+ goto jsondone;
} else if(!strcasecmp(message_text, "query_eventhandler")) {
/* Contact an event handler and expect a response */
JANUS_VALIDATE_JSON_OBJECT(root, queryhandler_parameters,
diff --git a/mainpage.dox b/mainpage.dox
index 4ac97b0d045..8132cbcd400 100644
--- a/mainpage.dox
+++ b/mainpage.dox
@@ -2316,6 +2316,13 @@ const token = getJanusToken('janus', ['janus.plugin.videoroom']),
* - \c detach_handle: detached a specific handle; this behaves exactly
* as the \c detach request does in the Janus API.
*
+ * \subsection adminreqt Transport-related requests
+ * - \c query_transport: send a synchronous request to a transport plugin and
+ * return a response; whether this is implemented, and what functionality is
+ * provided, can vary from transport to transport, but in general this feature
+ * is available to tweak some setting dynamically and/or query some internal
+ * transport-specific information (e.g., the number of served connections).
+ *
* \subsection adminreqe Event handlers-related requests
* - \c query_eventhandler: send a synchronous request to an event handler and
* return a response; implemented by most event handlers to dynamically
diff --git a/transports/janus_http.c b/transports/janus_http.c
index fc3d56f4e6a..76e1a70803d 100644
--- a/transports/janus_http.c
+++ b/transports/janus_http.c
@@ -45,12 +45,12 @@
/* Transport plugin information */
-#define JANUS_REST_VERSION 2
-#define JANUS_REST_VERSION_STRING "0.0.2"
-#define JANUS_REST_DESCRIPTION "This transport plugin adds REST (HTTP/HTTPS) support to the Janus API via libmicrohttpd."
-#define JANUS_REST_NAME "JANUS REST (HTTP/HTTPS) transport plugin"
-#define JANUS_REST_AUTHOR "Meetecho s.r.l."
-#define JANUS_REST_PACKAGE "janus.transport.http"
+#define JANUS_HTTP_VERSION 2
+#define JANUS_HTTP_VERSION_STRING "0.0.2"
+#define JANUS_HTTP_DESCRIPTION "This transport plugin adds REST (HTTP/HTTPS) support to the Janus API via libmicrohttpd."
+#define JANUS_HTTP_NAME "JANUS REST (HTTP/HTTPS) transport plugin"
+#define JANUS_HTTP_AUTHOR "Meetecho s.r.l."
+#define JANUS_HTTP_PACKAGE "janus.transport.http"
/* Transport methods */
janus_transport *create(void);
@@ -69,6 +69,7 @@ int janus_http_send_message(janus_transport_session *transport, void *request_id
void janus_http_session_created(janus_transport_session *transport, guint64 session_id);
void janus_http_session_over(janus_transport_session *transport, guint64 session_id, gboolean timeout, gboolean claimed);
void janus_http_session_claimed(janus_transport_session *transport, guint64 session_id);
+json_t *janus_http_query_transport(json_t *request);
/* Transport setup */
@@ -92,11 +93,13 @@ static janus_transport janus_http_transport =
.session_created = janus_http_session_created,
.session_over = janus_http_session_over,
.session_claimed = janus_http_session_claimed,
+
+ .query_transport = janus_http_query_transport,
);
/* Transport creator */
janus_transport *create(void) {
- JANUS_LOG(LOG_VERB, "%s created!\n", JANUS_REST_NAME);
+ JANUS_LOG(LOG_VERB, "%s created!\n", JANUS_HTTP_NAME);
return &janus_http_transport;
}
@@ -111,6 +114,20 @@ static gboolean notify_events = TRUE;
/* JSON serialization options */
static size_t json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+/* Parameter validation (for tweaking and queries via Admin API) */
+static struct janus_json_parameter request_parameters[] = {
+ {"request", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
+};
+static struct janus_json_parameter configure_parameters[] = {
+ {"events", JANUS_JSON_BOOL, 0},
+ {"json", JSON_STRING, 0},
+};
+/* Error codes (for the tweaking and queries via Admin API) */
+#define JANUS_HTTP_ERROR_INVALID_REQUEST 411
+#define JANUS_HTTP_ERROR_MISSING_ELEMENT 412
+#define JANUS_HTTP_ERROR_INVALID_ELEMENT 413
+#define JANUS_HTTP_ERROR_UNKNOWN_ERROR 499
+
/* Incoming HTTP message */
typedef struct janus_http_msg {
@@ -565,7 +582,7 @@ static void janus_http_add_cors_headers(janus_http_msg *msg, struct MHD_Response
/* Static callback that we register to */
static void janus_http_mhd_panic(void *cls, const char *file, unsigned int line, const char *reason) {
JANUS_LOG(LOG_WARN, "[%s]: Error in GNU libmicrohttpd %s:%u: %s\n",
- JANUS_REST_PACKAGE, file, line, reason);
+ JANUS_HTTP_PACKAGE, file, line, reason);
}
/* Transport implementation */
@@ -599,12 +616,12 @@ int janus_http_init(janus_transport_callbacks *callback, const char *config_path
/* Read configuration */
char filename[255];
- g_snprintf(filename, 255, "%s/%s.jcfg", config_path, JANUS_REST_PACKAGE);
+ g_snprintf(filename, 255, "%s/%s.jcfg", config_path, JANUS_HTTP_PACKAGE);
JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
janus_config *config = janus_config_parse(filename);
if(config == NULL) {
- JANUS_LOG(LOG_WARN, "Couldn't find .jcfg configuration file (%s), trying .cfg\n", JANUS_REST_PACKAGE);
- g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_REST_PACKAGE);
+ JANUS_LOG(LOG_WARN, "Couldn't find .jcfg configuration file (%s), trying .cfg\n", JANUS_HTTP_PACKAGE);
+ g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_HTTP_PACKAGE);
JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
config = janus_config_parse(filename);
}
@@ -639,7 +656,7 @@ int janus_http_init(janus_transport_callbacks *callback, const char *config_path
if(events != NULL && events->value != NULL)
notify_events = janus_is_true(events->value);
if(!notify_events && callback->events_is_enabled()) {
- JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_REST_NAME);
+ JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_HTTP_NAME);
}
/* Check the base paths */
@@ -868,7 +885,7 @@ int janus_http_init(janus_transport_callbacks *callback, const char *config_path
/* Done */
g_atomic_int_set(&initialized, 1);
- JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_REST_NAME);
+ JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_HTTP_NAME);
return 0;
}
@@ -926,7 +943,7 @@ void janus_http_destroy(void) {
g_atomic_int_set(&initialized, 0);
g_atomic_int_set(&stopping, 0);
- JANUS_LOG(LOG_INFO, "%s destroyed!\n", JANUS_REST_NAME);
+ JANUS_LOG(LOG_INFO, "%s destroyed!\n", JANUS_HTTP_NAME);
}
int janus_http_get_api_compatibility(void) {
@@ -935,27 +952,27 @@ int janus_http_get_api_compatibility(void) {
}
int janus_http_get_version(void) {
- return JANUS_REST_VERSION;
+ return JANUS_HTTP_VERSION;
}
const char *janus_http_get_version_string(void) {
- return JANUS_REST_VERSION_STRING;
+ return JANUS_HTTP_VERSION_STRING;
}
const char *janus_http_get_description(void) {
- return JANUS_REST_DESCRIPTION;
+ return JANUS_HTTP_DESCRIPTION;
}
const char *janus_http_get_name(void) {
- return JANUS_REST_NAME;
+ return JANUS_HTTP_NAME;
}
const char *janus_http_get_author(void) {
- return JANUS_REST_AUTHOR;
+ return JANUS_HTTP_AUTHOR;
}
const char *janus_http_get_package(void) {
- return JANUS_REST_PACKAGE;
+ return JANUS_HTTP_PACKAGE;
}
gboolean janus_http_is_janus_api_enabled(void) {
@@ -1136,6 +1153,117 @@ void janus_http_session_claimed(janus_transport_session *transport, guint64 sess
janus_refcount_decrease(&old_session->ref);
}
+json_t *janus_http_query_transport(json_t *request) {
+ if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
+ return NULL;
+ }
+ /* We can use this request to dynamically change the behaviour of
+ * the transport plugin, and/or query for some specific information */
+ json_t *response = json_object();
+ int error_code = 0;
+ char error_cause[512];
+ JANUS_VALIDATE_JSON_OBJECT(request, request_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_HTTP_ERROR_MISSING_ELEMENT, JANUS_HTTP_ERROR_INVALID_ELEMENT);
+ if(error_code != 0)
+ goto plugin_response;
+ /* Get the request */
+ const char *request_text = json_string_value(json_object_get(request, "request"));
+ if(!strcasecmp(request_text, "configure")) {
+ /* We only allow for the configuration of some basic properties:
+ * changing more complex things (e.g., port to bind to, etc.)
+ * would likely require restarting backends, so just too much */
+ JANUS_VALIDATE_JSON_OBJECT(request, configure_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_HTTP_ERROR_MISSING_ELEMENT, JANUS_HTTP_ERROR_INVALID_ELEMENT);
+ /* Check if we now need to send events to handlers */
+ json_object_set_new(response, "result", json_integer(200));
+ json_t *notes = NULL;
+ gboolean events = json_is_true(json_object_get(request, "events"));
+ if(events && !gateway->events_is_enabled()) {
+ /* Notify that this will be ignored */
+ notes = json_array();
+ json_array_append_new(notes, json_string("Event handlers disabled at the core level"));
+ json_object_set_new(response, "notes", notes);
+ }
+ if(events != notify_events) {
+ notify_events = events;
+ if(!notify_events && gateway->events_is_enabled()) {
+ JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_HTTP_NAME);
+ }
+ }
+ const char *indentation = json_string_value(json_object_get(request, "json"));
+ if(indentation != NULL) {
+ if(!strcasecmp(indentation, "indented")) {
+ /* Default: indented, we use three spaces for that */
+ json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "plain")) {
+ /* Not indented and no new lines, but still readable */
+ json_format = JSON_INDENT(0) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "compact")) {
+ /* Compact, so no spaces between separators */
+ json_format = JSON_COMPACT | JSON_PRESERVE_ORDER;
+ } else {
+ JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', ignoring tweak\n", indentation);
+ /* Notify that this will be ignored */
+ if(notes == NULL) {
+ notes = json_array();
+ json_object_set_new(response, "notes", notes);
+ }
+ json_array_append_new(notes, json_string("Ignored unsupported indentation format"));
+ }
+ }
+ } else if(!strcasecmp(request_text, "connections")) {
+ /* Return the number of active connections currently handled by the plugin */
+ json_object_set_new(response, "result", json_integer(200));
+ json_t *connections = json_object();
+ json_object_set_new(response, "connections", connections);
+ if(ws != NULL) {
+ const union MHD_DaemonInfo *info = MHD_get_daemon_info(ws,
+ MHD_DAEMON_INFO_CURRENT_CONNECTIONS, NULL);
+ if(info != NULL)
+ json_object_set_new(connections, "http", json_integer(info->num_connections));
+ }
+ if(sws != NULL) {
+ const union MHD_DaemonInfo *info = MHD_get_daemon_info(sws,
+ MHD_DAEMON_INFO_CURRENT_CONNECTIONS, NULL);
+ if(info != NULL)
+ json_object_set_new(connections, "https", json_integer(info->num_connections));
+ }
+ if(admin_ws != NULL) {
+ const union MHD_DaemonInfo *info = MHD_get_daemon_info(admin_ws,
+ MHD_DAEMON_INFO_CURRENT_CONNECTIONS, NULL);
+ if(info != NULL)
+ json_object_set_new(connections, "admin_http", json_integer(info->num_connections));
+ }
+ if(admin_sws != NULL) {
+ const union MHD_DaemonInfo *info = MHD_get_daemon_info(admin_sws,
+ MHD_DAEMON_INFO_CURRENT_CONNECTIONS, NULL);
+ if(info != NULL)
+ json_object_set_new(connections, "admin_https", json_integer(info->num_connections));
+ }
+ /* Also add the global number of messages we're serving */
+ janus_mutex_lock(&messages_mutex);
+ guint count = g_hash_table_size(messages);
+ janus_mutex_unlock(&messages_mutex);
+ json_object_set_new(response, "messages", json_integer(count));
+ } else {
+ JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
+ error_code = JANUS_HTTP_ERROR_INVALID_REQUEST;
+ g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
+ }
+
+plugin_response:
+ {
+ if(error_code != 0) {
+ /* Prepare JSON error event */
+ json_object_set_new(response, "error_code", json_integer(error_code));
+ json_object_set_new(response, "error", json_string(error_cause));
+ }
+ return response;
+ }
+}
+
/* Connection notifiers */
static int janus_http_client_connect(void *cls, const struct sockaddr *addr, socklen_t addrlen) {
janus_network_address naddr;
diff --git a/transports/janus_mqtt.c b/transports/janus_mqtt.c
index 37149569543..1c44b5911f9 100644
--- a/transports/janus_mqtt.c
+++ b/transports/janus_mqtt.c
@@ -59,6 +59,7 @@ int janus_mqtt_send_message(janus_transport_session *transport, void *request_id
void janus_mqtt_session_created(janus_transport_session *transport, guint64 session_id);
void janus_mqtt_session_over(janus_transport_session *transport, guint64 session_id, gboolean timeout, gboolean claimed);
void janus_mqtt_session_claimed(janus_transport_session *transport, guint64 session_id);
+json_t *janus_mqtt_query_transport(json_t *request);
#define JANUS_MQTT_VERSION_3_1 "3.1"
#define JANUS_MQTT_VERSION_3_1_1 "3.1.1"
@@ -88,6 +89,8 @@ static janus_transport janus_mqtt_transport_ =
.session_created = janus_mqtt_session_created,
.session_over = janus_mqtt_session_over,
.session_claimed = janus_mqtt_session_claimed,
+
+ .query_transport = janus_mqtt_query_transport,
);
/* Transport creator */
@@ -104,7 +107,22 @@ static gboolean janus_mqtt_admin_api_enabled_ = FALSE;
static gboolean notify_events = TRUE;
/* JSON serialization options */
-static size_t json_format_ = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+static size_t json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+
+/* Parameter validation (for tweaking and queries via Admin API) */
+static struct janus_json_parameter request_parameters[] = {
+ {"request", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
+};
+static struct janus_json_parameter configure_parameters[] = {
+ {"events", JANUS_JSON_BOOL, 0},
+ {"json", JSON_STRING, 0},
+};
+/* Error codes (for the tweaking and queries via Admin API) */
+#define JANUS_MQTT_ERROR_INVALID_REQUEST 411
+#define JANUS_MQTT_ERROR_MISSING_ELEMENT 412
+#define JANUS_MQTT_ERROR_INVALID_ELEMENT 413
+#define JANUS_MQTT_ERROR_UNKNOWN_ERROR 499
+
/* MQTT client context */
typedef struct janus_mqtt_context {
@@ -323,16 +341,16 @@ int janus_mqtt_init(janus_transport_callbacks *callback, const char *config_path
/* Check how we need to format/serialize the JSON output */
if(!strcasecmp(json_item->value, "indented")) {
/* Default: indented, we use three spaces for that */
- json_format_ = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+ json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
} else if(!strcasecmp(json_item->value, "plain")) {
/* Not indented and no new lines, but still readable */
- json_format_ = JSON_INDENT(0) | JSON_PRESERVE_ORDER;
+ json_format = JSON_INDENT(0) | JSON_PRESERVE_ORDER;
} else if(!strcasecmp(json_item->value, "compact")) {
/* Compact, so no spaces between separators */
- json_format_ = JSON_COMPACT | JSON_PRESERVE_ORDER;
+ json_format = JSON_COMPACT | JSON_PRESERVE_ORDER;
} else {
JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', using default (indented)\n", json_item->value);
- json_format_ = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+ json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
}
}
@@ -840,7 +858,7 @@ int janus_mqtt_send_message(janus_transport_session *transport, void *request_id
return -1;
}
- char *payload = json_dumps(message, json_format_);
+ char *payload = json_dumps(message, json_format);
JANUS_LOG(LOG_HUGE, "Sending %s API message via MQTT: %s\n", admin ? "admin" : "Janus", payload);
int rc;
@@ -964,6 +982,83 @@ void janus_mqtt_session_claimed(janus_transport_session *transport, guint64 sess
/* FIXME Is the above statement accurate? Should we care? Unlike the HTTP transport, there is no hashtable to update */
}
+json_t *janus_mqtt_query_transport(json_t *request) {
+ if(context_ == NULL) {
+ return NULL;
+ }
+ /* We can use this request to dynamically change the behaviour of
+ * the transport plugin, and/or query for some specific information */
+ json_t *response = json_object();
+ int error_code = 0;
+ char error_cause[512];
+ JANUS_VALIDATE_JSON_OBJECT(request, request_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_MQTT_ERROR_MISSING_ELEMENT, JANUS_MQTT_ERROR_INVALID_ELEMENT);
+ if(error_code != 0)
+ goto plugin_response;
+ /* Get the request */
+ const char *request_text = json_string_value(json_object_get(request, "request"));
+ if(!strcasecmp(request_text, "configure")) {
+ /* We only allow for the configuration of some basic properties:
+ * changing more complex things (e.g., port to bind to, etc.)
+ * would likely require restarting backends, so just too much */
+ JANUS_VALIDATE_JSON_OBJECT(request, configure_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_MQTT_ERROR_MISSING_ELEMENT, JANUS_MQTT_ERROR_INVALID_ELEMENT);
+ /* Check if we now need to send events to handlers */
+ json_object_set_new(response, "result", json_integer(200));
+ json_t *notes = NULL;
+ gboolean events = json_is_true(json_object_get(request, "events"));
+ if(events && !context_->gateway->events_is_enabled()) {
+ /* Notify that this will be ignored */
+ notes = json_array();
+ json_array_append_new(notes, json_string("Event handlers disabled at the core level"));
+ json_object_set_new(response, "notes", notes);
+ }
+ if(events != notify_events) {
+ notify_events = events;
+ if(!notify_events && context_->gateway->events_is_enabled()) {
+ JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_MQTT_NAME);
+ }
+ }
+ const char *indentation = json_string_value(json_object_get(request, "json"));
+ if(indentation != NULL) {
+ if(!strcasecmp(indentation, "indented")) {
+ /* Default: indented, we use three spaces for that */
+ json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "plain")) {
+ /* Not indented and no new lines, but still readable */
+ json_format = JSON_INDENT(0) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "compact")) {
+ /* Compact, so no spaces between separators */
+ json_format = JSON_COMPACT | JSON_PRESERVE_ORDER;
+ } else {
+ JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', ignoring tweak\n", indentation);
+ /* Notify that this will be ignored */
+ if(notes == NULL) {
+ notes = json_array();
+ json_object_set_new(response, "notes", notes);
+ }
+ json_array_append_new(notes, json_string("Ignored unsupported indentation format"));
+ }
+ }
+ } else {
+ JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
+ error_code = JANUS_MQTT_ERROR_INVALID_REQUEST;
+ g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
+ }
+
+plugin_response:
+ {
+ if(error_code != 0) {
+ /* Prepare JSON error event */
+ json_object_set_new(response, "error_code", json_integer(error_code));
+ json_object_set_new(response, "error", json_string(error_cause));
+ }
+ return response;
+ }
+}
+
void janus_mqtt_client_connected(void *context, char *cause) {
JANUS_LOG(LOG_INFO, "Connected to MQTT broker: %s\n", cause);
janus_mqtt_context *ctx = (janus_mqtt_context *)context;
diff --git a/transports/janus_nanomsg.c b/transports/janus_nanomsg.c
index 6bf614e8839..84197310bc3 100644
--- a/transports/janus_nanomsg.c
+++ b/transports/janus_nanomsg.c
@@ -54,6 +54,7 @@ int janus_nanomsg_send_message(janus_transport_session *transport, void *request
void janus_nanomsg_session_created(janus_transport_session *transport, guint64 session_id);
void janus_nanomsg_session_over(janus_transport_session *transport, guint64 session_id, gboolean timeout, gboolean claimed);
void janus_nanomsg_session_claimed(janus_transport_session *transport, guint64 session_id);
+json_t *janus_nanomsg_query_transport(json_t *request);
/* Transport setup */
@@ -77,6 +78,8 @@ static janus_transport janus_nanomsg_transport =
.session_created = janus_nanomsg_session_created,
.session_over = janus_nanomsg_session_over,
.session_claimed = janus_nanomsg_session_claimed,
+
+ .query_transport = janus_nanomsg_query_transport,
);
/* Transport creator */
@@ -96,6 +99,21 @@ static size_t json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
#define BUFFER_SIZE 8192
+/* Parameter validation (for tweaking and queries via Admin API) */
+static struct janus_json_parameter request_parameters[] = {
+ {"request", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
+};
+static struct janus_json_parameter configure_parameters[] = {
+ {"events", JANUS_JSON_BOOL, 0},
+ {"json", JSON_STRING, 0},
+};
+/* Error codes (for the tweaking and queries via Admin API) */
+#define JANUS_NANOMSG_ERROR_INVALID_REQUEST 411
+#define JANUS_NANOMSG_ERROR_MISSING_ELEMENT 412
+#define JANUS_NANOMSG_ERROR_INVALID_ELEMENT 413
+#define JANUS_NANOMSG_ERROR_UNKNOWN_ERROR 499
+
+
/* Nanomsg server thread */
static GThread *nanomsg_thread = NULL;
void *janus_nanomsg_thread(void *data);
@@ -404,6 +422,83 @@ void janus_nanomsg_session_claimed(janus_transport_session *transport, guint64 s
/* FIXME Is the above statement accurate? Should we care? Unlike the HTTP transport, there is no hashtable to update */
}
+json_t *janus_nanomsg_query_transport(json_t *request) {
+ if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
+ return NULL;
+ }
+ /* We can use this request to dynamically change the behaviour of
+ * the transport plugin, and/or query for some specific information */
+ json_t *response = json_object();
+ int error_code = 0;
+ char error_cause[512];
+ JANUS_VALIDATE_JSON_OBJECT(request, request_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_NANOMSG_ERROR_MISSING_ELEMENT, JANUS_NANOMSG_ERROR_INVALID_ELEMENT);
+ if(error_code != 0)
+ goto plugin_response;
+ /* Get the request */
+ const char *request_text = json_string_value(json_object_get(request, "request"));
+ if(!strcasecmp(request_text, "configure")) {
+ /* We only allow for the configuration of some basic properties:
+ * changing more complex things (e.g., port to bind to, etc.)
+ * would likely require restarting backends, so just too much */
+ JANUS_VALIDATE_JSON_OBJECT(request, configure_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_NANOMSG_ERROR_MISSING_ELEMENT, JANUS_NANOMSG_ERROR_INVALID_ELEMENT);
+ /* Check if we now need to send events to handlers */
+ json_object_set_new(response, "result", json_integer(200));
+ json_t *notes = NULL;
+ gboolean events = json_is_true(json_object_get(request, "events"));
+ if(events && !gateway->events_is_enabled()) {
+ /* Notify that this will be ignored */
+ notes = json_array();
+ json_array_append_new(notes, json_string("Event handlers disabled at the core level"));
+ json_object_set_new(response, "notes", notes);
+ }
+ if(events != notify_events) {
+ notify_events = events;
+ if(!notify_events && gateway->events_is_enabled()) {
+ JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_NANOMSG_NAME);
+ }
+ }
+ const char *indentation = json_string_value(json_object_get(request, "json"));
+ if(indentation != NULL) {
+ if(!strcasecmp(indentation, "indented")) {
+ /* Default: indented, we use three spaces for that */
+ json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "plain")) {
+ /* Not indented and no new lines, but still readable */
+ json_format = JSON_INDENT(0) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "compact")) {
+ /* Compact, so no spaces between separators */
+ json_format = JSON_COMPACT | JSON_PRESERVE_ORDER;
+ } else {
+ JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', ignoring tweak\n", indentation);
+ /* Notify that this will be ignored */
+ if(notes == NULL) {
+ notes = json_array();
+ json_object_set_new(response, "notes", notes);
+ }
+ json_array_append_new(notes, json_string("Ignored unsupported indentation format"));
+ }
+ }
+ } else {
+ JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
+ error_code = JANUS_NANOMSG_ERROR_INVALID_REQUEST;
+ g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
+ }
+
+plugin_response:
+ {
+ if(error_code != 0) {
+ /* Prepare JSON error event */
+ json_object_set_new(response, "error_code", json_integer(error_code));
+ json_object_set_new(response, "error", json_string(error_cause));
+ }
+ return response;
+ }
+}
+
/* Thread */
void *janus_nanomsg_thread(void *data) {
diff --git a/transports/janus_pfunix.c b/transports/janus_pfunix.c
index 55da82bce32..898b7d16227 100644
--- a/transports/janus_pfunix.c
+++ b/transports/janus_pfunix.c
@@ -69,6 +69,7 @@ int janus_pfunix_send_message(janus_transport_session *transport, void *request_
void janus_pfunix_session_created(janus_transport_session *transport, guint64 session_id);
void janus_pfunix_session_over(janus_transport_session *transport, guint64 session_id, gboolean timeout, gboolean claimed);
void janus_pfunix_session_claimed(janus_transport_session *transport, guint64 session_id);
+json_t *janus_pfunix_query_transport(json_t *request);
/* Transport setup */
@@ -92,6 +93,8 @@ static janus_transport janus_pfunix_transport =
.session_created = janus_pfunix_session_created,
.session_over = janus_pfunix_session_over,
.session_claimed = janus_pfunix_session_claimed,
+
+ .query_transport = janus_pfunix_query_transport,
);
/* Transport creator */
@@ -111,6 +114,21 @@ static size_t json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
#define BUFFER_SIZE 8192
+/* Parameter validation (for tweaking and queries via Admin API) */
+static struct janus_json_parameter request_parameters[] = {
+ {"request", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
+};
+static struct janus_json_parameter configure_parameters[] = {
+ {"events", JANUS_JSON_BOOL, 0},
+ {"json", JSON_STRING, 0},
+};
+/* Error codes (for the tweaking and queries via Admin API) */
+#define JANUS_PFUNIX_ERROR_INVALID_REQUEST 411
+#define JANUS_PFUNIX_ERROR_MISSING_ELEMENT 412
+#define JANUS_PFUNIX_ERROR_INVALID_ELEMENT 413
+#define JANUS_PFUNIX_ERROR_UNKNOWN_ERROR 499
+
+
struct sockaddr_un sizecheck;
#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX sizeof(sizecheck.sun_path)
@@ -477,6 +495,90 @@ void janus_pfunix_session_claimed(janus_transport_session *transport, guint64 se
/* FIXME Is the above statement accurate? Should we care? Unlike the HTTP transport, there is no hashtable to update */
}
+json_t *janus_pfunix_query_transport(json_t *request) {
+ if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
+ return NULL;
+ }
+ /* We can use this request to dynamically change the behaviour of
+ * the transport plugin, and/or query for some specific information */
+ json_t *response = json_object();
+ int error_code = 0;
+ char error_cause[512];
+ JANUS_VALIDATE_JSON_OBJECT(request, request_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_PFUNIX_ERROR_MISSING_ELEMENT, JANUS_PFUNIX_ERROR_INVALID_ELEMENT);
+ if(error_code != 0)
+ goto plugin_response;
+ /* Get the request */
+ const char *request_text = json_string_value(json_object_get(request, "request"));
+ if(!strcasecmp(request_text, "configure")) {
+ /* We only allow for the configuration of some basic properties:
+ * changing more complex things (e.g., port to bind to, etc.)
+ * would likely require restarting backends, so just too much */
+ JANUS_VALIDATE_JSON_OBJECT(request, configure_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_PFUNIX_ERROR_MISSING_ELEMENT, JANUS_PFUNIX_ERROR_INVALID_ELEMENT);
+ /* Check if we now need to send events to handlers */
+ json_object_set_new(response, "result", json_integer(200));
+ json_t *notes = NULL;
+ gboolean events = json_is_true(json_object_get(request, "events"));
+ if(events && !gateway->events_is_enabled()) {
+ /* Notify that this will be ignored */
+ notes = json_array();
+ json_array_append_new(notes, json_string("Event handlers disabled at the core level"));
+ json_object_set_new(response, "notes", notes);
+ }
+ if(events != notify_events) {
+ notify_events = events;
+ if(!notify_events && gateway->events_is_enabled()) {
+ JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_PFUNIX_NAME);
+ }
+ }
+ const char *indentation = json_string_value(json_object_get(request, "json"));
+ if(indentation != NULL) {
+ if(!strcasecmp(indentation, "indented")) {
+ /* Default: indented, we use three spaces for that */
+ json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "plain")) {
+ /* Not indented and no new lines, but still readable */
+ json_format = JSON_INDENT(0) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "compact")) {
+ /* Compact, so no spaces between separators */
+ json_format = JSON_COMPACT | JSON_PRESERVE_ORDER;
+ } else {
+ JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', ignoring tweak\n", indentation);
+ /* Notify that this will be ignored */
+ if(notes == NULL) {
+ notes = json_array();
+ json_object_set_new(response, "notes", notes);
+ }
+ json_array_append_new(notes, json_string("Ignored unsupported indentation format"));
+ }
+ }
+ } else if(!strcasecmp(request_text, "connections")) {
+ /* Return the number of active connections currently handled by the plugin */
+ json_object_set_new(response, "result", json_integer(200));
+ janus_mutex_lock(&clients_mutex);
+ guint connections = g_hash_table_size(clients);
+ janus_mutex_unlock(&clients_mutex);
+ json_object_set_new(response, "connections", json_integer(connections));
+ } else {
+ JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
+ error_code = JANUS_PFUNIX_ERROR_INVALID_REQUEST;
+ g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
+ }
+
+plugin_response:
+ {
+ if(error_code != 0) {
+ /* Prepare JSON error event */
+ json_object_set_new(response, "error_code", json_integer(error_code));
+ json_object_set_new(response, "error", json_string(error_cause));
+ }
+ return response;
+ }
+}
+
/* Thread */
void *janus_pfunix_thread(void *data) {
diff --git a/transports/janus_rabbitmq.c b/transports/janus_rabbitmq.c
index 9c17a9a995e..d8babf9d81e 100644
--- a/transports/janus_rabbitmq.c
+++ b/transports/janus_rabbitmq.c
@@ -70,6 +70,7 @@ int janus_rabbitmq_send_message(janus_transport_session *transport, void *reques
void janus_rabbitmq_session_created(janus_transport_session *transport, guint64 session_id);
void janus_rabbitmq_session_over(janus_transport_session *transport, guint64 session_id, gboolean timeout, gboolean claimed);
void janus_rabbitmq_session_claimed(janus_transport_session *transport, guint64 session_id);
+json_t *janus_rabbitmq_query_transport(json_t *request);
/* Transport setup */
@@ -93,6 +94,8 @@ static janus_transport janus_rabbitmq_transport =
.session_created = janus_rabbitmq_session_created,
.session_over = janus_rabbitmq_session_over,
.session_claimed = janus_rabbitmq_session_claimed,
+
+ .query_transport = janus_rabbitmq_query_transport,
);
/* Transport creator */
@@ -114,6 +117,20 @@ static gboolean notify_events = TRUE;
/* JSON serialization options */
static size_t json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+/* Parameter validation (for tweaking and queries via Admin API) */
+static struct janus_json_parameter request_parameters[] = {
+ {"request", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
+};
+static struct janus_json_parameter configure_parameters[] = {
+ {"events", JANUS_JSON_BOOL, 0},
+ {"json", JSON_STRING, 0},
+};
+/* Error codes (for the tweaking and queries via Admin API) */
+#define JANUS_RABBITMQ_ERROR_INVALID_REQUEST 411
+#define JANUS_RABBITMQ_ERROR_MISSING_ELEMENT 412
+#define JANUS_RABBITMQ_ERROR_INVALID_ELEMENT 413
+#define JANUS_RABBITMQ_ERROR_UNKNOWN_ERROR 499
+
/* RabbitMQ client session: we only create a single one as of now */
typedef struct janus_rabbitmq_client {
@@ -653,6 +670,83 @@ void janus_rabbitmq_session_claimed(janus_transport_session *transport, guint64
/* FIXME Is the above statement accurate? Should we care? Unlike the HTTP transport, there is no hashtable to update */
}
+json_t *janus_rabbitmq_query_transport(json_t *request) {
+ if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
+ return NULL;
+ }
+ /* We can use this request to dynamically change the behaviour of
+ * the transport plugin, and/or query for some specific information */
+ json_t *response = json_object();
+ int error_code = 0;
+ char error_cause[512];
+ JANUS_VALIDATE_JSON_OBJECT(request, request_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_RABBITMQ_ERROR_MISSING_ELEMENT, JANUS_RABBITMQ_ERROR_INVALID_ELEMENT);
+ if(error_code != 0)
+ goto plugin_response;
+ /* Get the request */
+ const char *request_text = json_string_value(json_object_get(request, "request"));
+ if(!strcasecmp(request_text, "configure")) {
+ /* We only allow for the configuration of some basic properties:
+ * changing more complex things (e.g., port to bind to, etc.)
+ * would likely require restarting backends, so just too much */
+ JANUS_VALIDATE_JSON_OBJECT(request, configure_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_RABBITMQ_ERROR_MISSING_ELEMENT, JANUS_RABBITMQ_ERROR_INVALID_ELEMENT);
+ /* Check if we now need to send events to handlers */
+ json_object_set_new(response, "result", json_integer(200));
+ json_t *notes = NULL;
+ gboolean events = json_is_true(json_object_get(request, "events"));
+ if(events && !gateway->events_is_enabled()) {
+ /* Notify that this will be ignored */
+ notes = json_array();
+ json_array_append_new(notes, json_string("Event handlers disabled at the core level"));
+ json_object_set_new(response, "notes", notes);
+ }
+ if(events != notify_events) {
+ notify_events = events;
+ if(!notify_events && gateway->events_is_enabled()) {
+ JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_RABBITMQ_NAME);
+ }
+ }
+ const char *indentation = json_string_value(json_object_get(request, "json"));
+ if(indentation != NULL) {
+ if(!strcasecmp(indentation, "indented")) {
+ /* Default: indented, we use three spaces for that */
+ json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "plain")) {
+ /* Not indented and no new lines, but still readable */
+ json_format = JSON_INDENT(0) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "compact")) {
+ /* Compact, so no spaces between separators */
+ json_format = JSON_COMPACT | JSON_PRESERVE_ORDER;
+ } else {
+ JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', ignoring tweak\n", indentation);
+ /* Notify that this will be ignored */
+ if(notes == NULL) {
+ notes = json_array();
+ json_object_set_new(response, "notes", notes);
+ }
+ json_array_append_new(notes, json_string("Ignored unsupported indentation format"));
+ }
+ }
+ } else {
+ JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
+ error_code = JANUS_RABBITMQ_ERROR_INVALID_REQUEST;
+ g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
+ }
+
+plugin_response:
+ {
+ if(error_code != 0) {
+ /* Prepare JSON error event */
+ json_object_set_new(response, "error_code", json_integer(error_code));
+ json_object_set_new(response, "error", json_string(error_cause));
+ }
+ return response;
+ }
+}
+
/* Threads */
void *janus_rmq_in_thread(void *data) {
diff --git a/transports/janus_websockets.c b/transports/janus_websockets.c
index 4230da33a49..9728b01add8 100644
--- a/transports/janus_websockets.c
+++ b/transports/janus_websockets.c
@@ -66,6 +66,7 @@ int janus_websockets_send_message(janus_transport_session *transport, void *requ
void janus_websockets_session_created(janus_transport_session *transport, guint64 session_id);
void janus_websockets_session_over(janus_transport_session *transport, guint64 session_id, gboolean timeout, gboolean claimed);
void janus_websockets_session_claimed(janus_transport_session *transport, guint64 session_id);
+json_t *janus_websockets_query_transport(json_t *request);
/* Transport setup */
@@ -89,6 +90,8 @@ static janus_transport janus_websockets_transport =
.session_created = janus_websockets_session_created,
.session_over = janus_websockets_session_over,
.session_claimed = janus_websockets_session_claimed,
+
+ .query_transport = janus_websockets_query_transport,
);
/* Transport creator */
@@ -114,6 +117,21 @@ static janus_mutex writable_mutex;
/* JSON serialization options */
static size_t json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+/* Parameter validation (for tweaking and queries via Admin API) */
+static struct janus_json_parameter request_parameters[] = {
+ {"request", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
+};
+static struct janus_json_parameter configure_parameters[] = {
+ {"events", JANUS_JSON_BOOL, 0},
+ {"json", JSON_STRING, 0},
+ {"logging", JSON_STRING, 0},
+};
+/* Error codes (for the tweaking and queries via Admin API) */
+#define JANUS_WEBSOCKETS_ERROR_INVALID_REQUEST 411
+#define JANUS_WEBSOCKETS_ERROR_MISSING_ELEMENT 412
+#define JANUS_WEBSOCKETS_ERROR_INVALID_ELEMENT 413
+#define JANUS_WEBSOCKETS_ERROR_UNKNOWN_ERROR 499
+
/* Logging */
static int ws_log_level = 0;
@@ -997,6 +1015,138 @@ void janus_websockets_session_claimed(janus_transport_session *transport, guint6
/* FIXME Is the above statement accurate? Should we care? Unlike the HTTP transport, there is no hashtable to update */
}
+json_t *janus_websockets_query_transport(json_t *request) {
+ if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
+ return NULL;
+ }
+ /* We can use this request to dynamically change the behaviour of
+ * the transport plugin, and/or query for some specific information */
+ json_t *response = json_object();
+ int error_code = 0;
+ char error_cause[512];
+ JANUS_VALIDATE_JSON_OBJECT(request, request_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_WEBSOCKETS_ERROR_MISSING_ELEMENT, JANUS_WEBSOCKETS_ERROR_INVALID_ELEMENT);
+ if(error_code != 0)
+ goto plugin_response;
+ /* Get the request */
+ const char *request_text = json_string_value(json_object_get(request, "request"));
+ if(!strcasecmp(request_text, "configure")) {
+ /* We only allow for the configuration of some basic properties:
+ * changing more complex things (e.g., port to bind to, etc.)
+ * would likely require restarting backends, so just too much */
+ JANUS_VALIDATE_JSON_OBJECT(request, configure_parameters,
+ error_code, error_cause, TRUE,
+ JANUS_WEBSOCKETS_ERROR_MISSING_ELEMENT, JANUS_WEBSOCKETS_ERROR_INVALID_ELEMENT);
+ /* Check if we now need to send events to handlers */
+ json_object_set_new(response, "result", json_integer(200));
+ json_t *notes = NULL;
+ gboolean events = json_is_true(json_object_get(request, "events"));
+ if(events && !gateway->events_is_enabled()) {
+ /* Notify that this will be ignored */
+ notes = json_array();
+ json_array_append_new(notes, json_string("Event handlers disabled at the core level"));
+ json_object_set_new(response, "notes", notes);
+ }
+ if(events != notify_events) {
+ notify_events = events;
+ if(!notify_events && gateway->events_is_enabled()) {
+ JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_WEBSOCKETS_NAME);
+ }
+ }
+ const char *indentation = json_string_value(json_object_get(request, "json"));
+ if(indentation != NULL) {
+ if(!strcasecmp(indentation, "indented")) {
+ /* Default: indented, we use three spaces for that */
+ json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "plain")) {
+ /* Not indented and no new lines, but still readable */
+ json_format = JSON_INDENT(0) | JSON_PRESERVE_ORDER;
+ } else if(!strcasecmp(indentation, "compact")) {
+ /* Compact, so no spaces between separators */
+ json_format = JSON_COMPACT | JSON_PRESERVE_ORDER;
+ } else {
+ JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', ignoring tweak\n", indentation);
+ /* Notify that this will be ignored */
+ if(notes == NULL) {
+ notes = json_array();
+ json_object_set_new(response, "notes", notes);
+ }
+ json_array_append_new(notes, json_string("Ignored unsupported indentation format"));
+ }
+ }
+ const char *logging = json_string_value(json_object_get(request, "logging"));
+ if(logging != NULL) {
+ /* libwebsockets uses a mask to set log levels, as documented here:
+ * https://libwebsockets.org/lws-api-doc-master/html/group__log.html */
+ if(strstr(logging, "none")) {
+ /* Disable libwebsockets logging completely (the default) */
+ } else if(strstr(logging, "all")) {
+ /* Enable all libwebsockets logging */
+ ws_log_level = LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO |
+ LLL_DEBUG | LLL_PARSER | LLL_HEADER | LLL_EXT |
+#if (LWS_LIBRARY_VERSION_MAJOR >= 2 && LWS_LIBRARY_VERSION_MINOR >= 2) || (LWS_LIBRARY_VERSION_MAJOR >= 3)
+ LLL_CLIENT | LLL_LATENCY | LLL_USER | LLL_COUNT;
+#else
+ LLL_CLIENT | LLL_LATENCY | LLL_COUNT;
+#endif
+ } else {
+ /* Only enable some of the properties */
+ ws_log_level = 0;
+ if(strstr(logging, "err"))
+ ws_log_level |= LLL_ERR;
+ if(strstr(logging, "warn"))
+ ws_log_level |= LLL_WARN;
+ if(strstr(logging, "notice"))
+ ws_log_level |= LLL_NOTICE;
+ if(strstr(logging, "info"))
+ ws_log_level |= LLL_INFO;
+ if(strstr(logging, "debug"))
+ ws_log_level |= LLL_DEBUG;
+ if(strstr(logging, "parser"))
+ ws_log_level |= LLL_PARSER;
+ if(strstr(logging, "header"))
+ ws_log_level |= LLL_HEADER;
+ if(strstr(logging, "ext"))
+ ws_log_level |= LLL_EXT;
+ if(strstr(logging, "client"))
+ ws_log_level |= LLL_CLIENT;
+ if(strstr(logging, "latency"))
+ ws_log_level |= LLL_LATENCY;
+#if (LWS_LIBRARY_VERSION_MAJOR >= 2 && LWS_LIBRARY_VERSION_MINOR >= 2) || (LWS_LIBRARY_VERSION_MAJOR >= 3)
+ if(strstr(logging, "user"))
+ ws_log_level |= LLL_USER;
+#endif
+ if(strstr(logging, "count"))
+ ws_log_level |= LLL_COUNT;
+ }
+ JANUS_LOG(LOG_INFO, "libwebsockets logging: %d\n", ws_log_level);
+ lws_set_log_level(ws_log_level, janus_websockets_log_emit_function);
+ }
+ } else if(!strcasecmp(request_text, "connections")) {
+ /* Return the number of active connections currently handled by the plugin */
+ json_object_set_new(response, "result", json_integer(200));
+ janus_mutex_lock(&writable_mutex);
+ guint connections = g_hash_table_size(clients);
+ janus_mutex_unlock(&writable_mutex);
+ json_object_set_new(response, "connections", json_integer(connections));
+ } else {
+ JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
+ error_code = JANUS_WEBSOCKETS_ERROR_INVALID_REQUEST;
+ g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
+ }
+
+plugin_response:
+ {
+ if(error_code != 0) {
+ /* Prepare JSON error event */
+ json_object_set_new(response, "error_code", json_integer(error_code));
+ json_object_set_new(response, "error", json_string(error_cause));
+ }
+ return response;
+ }
+}
+
/* Thread */
void *janus_websockets_thread(void *data) {
diff --git a/transports/transport.h b/transports/transport.h
index d9140dd81ce..a3c3e112055 100644
--- a/transports/transport.h
+++ b/transports/transport.h
@@ -97,7 +97,7 @@ janus_transport *create(void) {
/*! \brief Version of the API, to match the one transport plugins were compiled against */
-#define JANUS_TRANSPORT_API_VERSION 7
+#define JANUS_TRANSPORT_API_VERSION 8
/*! \brief Initialization of all transport plugin properties to NULL
*
@@ -128,7 +128,8 @@ static janus_transport janus_http_transport_plugin =
.send_message = NULL, \
.session_created = NULL, \
.session_over = NULL, \
- .session_claimed = NULL, \
+ .session_claimed = NULL, \
+ .query_transport = NULL, \
## __VA_ARGS__ }
@@ -230,6 +231,19 @@ struct janus_transport {
* @param[in] session_id The session ID that was claimed (if the transport cares) */
void (* const session_claimed)(janus_transport_session *transport, guint64 session_id);
+ /*! \brief Method to send a management request to this specific transport plugin
+ * \details The method takes a Jansson json_t, that contains all the info related
+ * to the request. This object will come from an Admin API request, and is
+ * meant to represent a synchronous request. Since each transport plugin can have
+ * its own bells and whistles, there's no constraint on what this object should
+ * contain, which is entirely handler specific. A json_t object needs to be
+ * returned as a response, which will be sent in response to the Admin API call.
+ * This can be useful to tweak settings in real-time, or to probe the internals
+ * of the transport plugin for monitoring purposes.
+ * @param[in] request Jansson object containing the request
+ * @returns A Jansson object containing the response for the client */
+ json_t *(* const query_transport)(json_t *request);
+
};
/*! \brief Callbacks to contact the Janus core */