From 79f9c7671ba5daccd8da3c7e4722f24e09680287 Mon Sep 17 00:00:00 2001 From: Raffaele Rossi Date: Fri, 22 Jan 2016 16:49:57 +0000 Subject: [PATCH] dtsl: add some documentation https://bugzilla.gnome.org/show_bug.cgi?id=760994 --- ext/dtls/README | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 ext/dtls/README diff --git a/ext/dtls/README b/ext/dtls/README new file mode 100644 index 0000000..8d165ec --- /dev/null +++ b/ext/dtls/README @@ -0,0 +1,153 @@ +INTRODUCTION +============ +This document is an attempt to describe the basics of the DTLS element. +It hasn't been written by the author(s) and so, besides being incomplete, +*IT MIGHT ALSO BE INCORRECT*. So take it with a pinch of salt. + +As always, if in doubt ask the #gstreamer IRC channel. + +THE INTERNALS +============= +This plugin provides two main elements (dtlssrtpdec and dtlssrtpenc) and a few +minor elements necessary to implement them. The two elements dtlssrtpdec and +dtlssrtpenc are the only ones you are supposed to include in, respectively, the +RX and TX pipelines of your DTLS-enabled application. This means you're not +supposed to directly include those minor elements in your pipelines. + +dtlssrtpenc +----------- +This element is to be included in the TX pipeline and will initiate the DTLS +handshake if configured to be the client. Its main configuration parameters are: + + - connection-id: a string that must match the connection-id in dtlssrtpdec; + - is-client: a boolean that indicates whether this is going to be the client + or the server during the DTLS handshake. + +Internally this element comprises the standard srtpenc element, the dtlsenc +element and a funnel to connect both these elements to one single output. +The srtpenc can be used to encrypt SRTP/SRTCP packets while the dtlsenc can be +used to encrypt generic data, e.g. for non-SRTP applications. + +NB With the current implementation the TX pipeline containing the dtlssrtpenc + must be created *AFTER* the RX pipeline. + +dtlssrtpdec +----------- +It is to be included in the RX pipeline. Its main configuration parameters are: + + - connection-id: a string that must match the connection-id in dtlssrtpenc; + - pem: a string that can be used to provide your own certificate *AND* private + key in PEM format. The private key is required to carry out the + handshake so do not forget it or the DTLS negotiation will fail; + - peer_pem: a read only parameter that can be used to retrieve the + certificate sent from the other party in PEM format once the + handshake is completed. + +Internally this element comprises a dtlssrtpdemux, a standard srtpdec element +and the dtlsdec element. The dtlssrtpdemux element switches SRT(C)P packets to +the srtpdec element and DTLS packets to the dtlsdec element and discards any +other unknown packet. So, similarly for the dtlssrtpenc case, DTLS-SRTP +applications would exercise the srtpdec element and any other non-SRTP +application would exercise the dtlsdec element. + +NB With the current implementation the RX pipeline containing the dtlssrtpdec + must be created *BEFORE* the TX pipeline. + +EXAMPLE PIPELINE +================ +The following is an example usage of the DTLS plugin. It is a python script that +creates two endpoints that exchange encrypted audio using DTLS to exchange the +encryption keys. + +NB In theory we would show an example gst-launch command. However that would not + be enough because you need two pairs of TX/RX pipelines for a proper + handshake and you can't use gst-launch two start 4 different pipelines. + This why there is a python script in here. + +``` +#!/usr/bin/env python3 + +# create two endpoints, each with tx and rx pipelines using the DTLS +# elements and let audio flowing for a while to give time for a packet capture + +import time +from gi.repository import Gst, GObject, GLib +GObject.threads_init() +Gst.init(None) + + +def _start_pipeline(pipeline): + pipeline.set_state(Gst.State.PLAYING) + pipeline.get_state(Gst.CLOCK_TIME_NONE) + + +def _sleep_while_iterating_gloop(secs): + """ block for secs seconds but iterate the gloop while you do """ + for _ in range(10 * secs): + gloop = GLib.MainLoop() + gloop_context = gloop.get_context() + gloop_context.iteration(may_block=False) + time.sleep(0.1) + +def dtls_tx_pipeline_description(name, is_client, port): + return ' ! '.join([ + 'audiotestsrc is-live=true', + 'audio/x-raw, rate=8000, format=S16LE, channels=1', + 'opusenc frame-size=10', + 'rtpopuspay pt=103', + '.rtp_sink_0 dtlssrtpenc connection-id={name} is-client={client} .src', + 'udpsink port={port}' + ]).format(name=name, client=is_client, port=port) + + +def dtls_rx_pipeline_description(name, port): + return ' ! '.join([ + 'udpsrc port={port}', + '.sink dtlssrtpdec connection-id={name} .rtp_src', + 'queue', + 'fakesink async=false' + ]).format(name=name, port=port) + + +class Endpoint: + def __init__(self, name, is_client, tx_port, rx_port): + self.name = name + tx_pipeline_description = dtls_tx_pipeline_description( + name, is_client, tx_port + ) + rx_pipeline_description = dtls_rx_pipeline_description(name, rx_port) + print(rx_pipeline_description) + print(tx_pipeline_description) + + self.rx_pipeline = Gst.parse_launch(rx_pipeline_description) + self.tx_pipeline = Gst.parse_launch(tx_pipeline_description) + + def start(self): + # Start RX first, otherwise it fails due to the current implementation + self.start_rx_pipeline() + self.start_tx_pipeline() + + def start_rx_pipeline(self): + _start_pipeline(self.rx_pipeline) + + def start_tx_pipeline(self): + _start_pipeline(self.tx_pipeline) + + def stop(self): + def stop_pipeline(p): + p.set_state(Gst.State.NULL) + p.get_state(Gst.CLOCK_TIME_NONE) + stop_pipeline(self.tx_pipeline) + stop_pipeline(self.rx_pipeline) + +blue = Endpoint("blue", is_client=True, tx_port=23000, rx_port=23002) +red = Endpoint("red", is_client=False, tx_port=23002, rx_port=23000) + +red.start() +blue.start() + +_sleep_while_iterating_gloop(3) + +red.stop() +blue.stop() +``` -- 2.7.4