nanomsg transport
The nanomsg transport carries the Janus API over a nanomsg NN_PAIR socket: one peer, one socket, no broker. Janus can bind the address (the default) or connect to it. Use it from C, or any language with a nanomsg binding, when you control a single Janus from a single application and want something lighter than HTTP.
NN_PAIR is a one-to-one pattern. Only one client talks to Janus at a time, and every session it creates lives on that socket. If you need several clients, use WebSockets, MQTT or RabbitMQ.
Enable and configure
The transport reads janus.transport.nanomsg.jcfg. It is off unless general.enabled (Janus API) or admin.admin_enabled (Admin API) is true.
general: {
enabled = true
json = "indented" # indented, plain or compact (the default)
mode = "bind" # bind (the default) or connect
address = "tcp://127.0.0.1:5000" # or ipc:///tmp/janus.ipc
}
admin: {
admin_enabled = true
admin_mode = "bind"
admin_address = "tcp://127.0.0.1:5001"
}The full table is in the transport files reference. Note that the transport's mode defaults to bind, while the nanomsg event handler's defaults to connect.
Addresses are what libnanomsg accepts for nn_bind and nn_connect: tcp://host:port and ipc://path. ws:// is refused here. A port of 0 is refused, as libnanomsg refuses it.
Try it
I did not have libnanomsg here. The client in this script is a small SP peer written for the test: it sends the 8-byte protocol header, reads Janus's header, and then sends and reads messages with an 8-byte big-endian length in front. That is the same wire format a real nanomsg NN_PAIR client produces over tcp://. A real client needs only nn_socket(AF_SP, NN_PAIR), nn_connect("tcp://127.0.0.1:5000"), nn_send and nn_recv; I did not run one.
// Janus binds a NN_PAIR socket on tcp://127.0.0.1:5000. The client here is not libnanomsg: it is a 60-line SP peer in this script, which does the 8-byte handshake and the length-prefixed framing. A real nanomsg client (nn_socket(AF_SP, NN_PAIR), nn_connect) does the same on the wire.
// ⇠ SP handshake: we send 00 53 50 00 00 10 00 00 (NN_PAIR); Janus answers
00 53 50 00 00 10 00 00
// → send message
{
"janus": "ping",
"transaction": "n1"
}
// ← receive message
{
"janus": "pong",
"transaction": "n1"
}
// → send message
{
"janus": "create",
"transaction": "n2"
}
// ← receive message
{
"janus": "success",
"transaction": "n2",
"data": {
"id": 1571923037352911
}
}
// → send message
{
"janus": "attach",
"session_id": 1571923037352911,
"plugin": "janus.plugin.echotest",
"transaction": "n3"
}
// ← receive message
{
"janus": "success",
"session_id": 1571923037352911,
"transaction": "n3",
"data": {
"id": 3554920946991694
}
}
// → send message
{
"janus": "message",
"session_id": 1571923037352911,
"handle_id": 3554920946991694,
"transaction": "n4",
"body": {
"audio": true
}
}
// ← receive message
{
"janus": "ack",
"session_id": 1571923037352911,
"transaction": "n4",
"hint": "I'm taking my time!"
}
// ⇠ receive message
{
"janus": "event",
"session_id": 1571923037352911,
"transaction": "n4",
"sender": 3554920946991694,
"plugindata": {
"plugin": "janus.plugin.echotest",
"data": {
"echotest": "event",
"result": "ok"
}
}
}
// Only one peer at a time: a second connection is refused while the first one is up.The parity/status.json note for this transport says the same exchange was compared with libnanomsg 1.1.5 in the oracle image, with the same replies byte for byte.
Reference
On the wire
| Step | Bytes |
|---|---|
| Handshake, each way | 00 53 50 00, then the protocol number as 16 bits, then 00 00. NN_PAIR is 0x0010. Janus answers 00 53 50 00 00 10 00 00. |
One message, over tcp:// | 8 bytes of length (big endian), then the JSON text. |
One message, over ipc:// | one type byte, 8 bytes of length, then the JSON text. |
From the source (not run here): Janus drops a message of more than 8191 bytes, with no reply, as C does. A message longer than 1 MiB makes the SP layer close the connection. The JSON parser stops at the first NUL byte. A second peer is refused while the first one is connected.
Events
The session events (the plugin's answer to a message, webrtcup, hangup, timeout) come back on the same socket as extra messages. The transcript shows the event after the ack.
From the source: at start Janus reports a transport event created, with the socket number, to the event handlers, once per API socket that bound.
Behaviour you may not expect
- verified A reply is a single SP message with no terminator, so read by message, not by line.
- From the source and
parity/status.json, not run here: a bind that fails (the port is taken) turns that API off and logs the failure. If no socket starts at all, Janus stops. - Janus does not check an API secret on this socket in its own code; the Admin API check is the core's, as on the other transports.
Known gaps
- gap
infodoes not listjanus.transport.nanomsg, though the transport works. See the transports overview. - gap
query_transportanswers error 490. - gap
ws://addresses are refused. - gap The interface list of
tcp://iface;host:portis checked, not applied. - gap Nesting depth: the JSON parser stops at 128 levels. jansson's limit is not the same; a message that C accepts can be an error here.
- gap A write error closes the connection. libnanomsg aborts the gateway in a few cases (an
ipcpath of 108 bytes or more, anipcmessage without the type byte); here they are errors. - gap
session createdevents from this transport carry notransportobject. See event types. - gap The Admin API over nanomsg was not compared with the C server.
Test it in Janus Bench
Janus Bench talks HTTP and WebSockets only. There is no check for this transport.