diff --git a/README.md b/README.md index 65b4624..67c77b1 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,300 @@ -# DONAR +# Donar -## 1) Runtime dependencies +## Quickstart -On Fedora: +### Installation -```bash -sudo dnf install -y \ - glib2 \ - gstreamer1.0 \ - libevent \ - zlib \ - openssl \ - libzstd \ - xz-libs \ - wget \ - unzip +The following steps are provided for [Fedora 29 Workstation](https://getfedora.org/fr/workstation/download/). +We assume you have two containers or two virtual machines or two physical machines. + +To setup each machine, you should do: + +``` +sudo dnf install --refresh -y cmake gcc gcc-c++ ninja-build glib2-devel glib2 tor valgrind git net-tools nmap-ncat +git clone https://gitlab.inria.fr/qdufour/donar.git +cd donar +mkdir out && cd out && cmake -GNinja .. && ninja && sudo ninja install ``` -On Ubuntu: +### Commands + +Now your machine is ready and you will be able to use the following commads: + + * `donar` is our main binary. It can be run as a client or a server. + * `udpecho` is a simple udp server that send back the data sent to him. + * `torecho` is a simple tcp server that send back the data sent to him + configure the tor daemon to generate a hidden service URL and be accessible on the Tor network. + * `measlat` can be used in conjunction with `udpecho` or `torecho` to measure a Round Trip Time (RTT) + +Try to run the previous commands in your terminal without any option, you will see their help. + +At any moment, you can use the following commands that are not part of the project to understand what you are doing: ```bash -sudo apt-get install -y \ - libglib2.0-0 \ - libgstreamer1.0 \ - gstreamer1.0-alsa \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-good \ - gstreamer1.0-plugins-ugly \ - gstreamer1.0-pulseaudio \ - libevent-2.1 \ - zlib1g \ - libssl1.1 \ - zstd \ - liblzma5 \ - wget \ - unzip +netstat -ulpn # Show programs that listen on an UDP port +netstat -tlpn # Show prograns that listen on a TCP port +nc 127.0.0.1 8000 # Connect via TCP on server 127.0.0.1 listening on port 8000 +nc -u 127.0.0.1 8000 # Connect via UDP on server 127.0.0.1 listening on port 8000 ``` -## 2) Obtain binaries +### Introduction to the debug tools `udpecho` and `measlat` -Download the version you want here: https://cloud.deuxfleurs.fr/d/612993c04e9d40609242/ - -And extract the zip file: +Now let's start simple, we will launch our udp echo server and access it locally: ```bash -unzip donar*.zip -cd release +udpecho -p 8000 & +nc 127.0.0.1 8000 ``` -## 3) Callee +If you write some data on your terminal and press enter, you will see that your data has been repeated. Well done! -In a first terminal: +Now, instead of using `nc`, we will use `measlat` to use this echo server to measure latencies (make sure that `udpecho` is still running): ```bash -./tor2 -f torrc_guard_12 +measlat -h 127.0.0.1 -p 8000 -t udp ``` -In a second terminal: +`measlat` will send one packet to our udpecho server and wait to receive it back, measure the time it took, display it and exit. + +You can use `measlat` more extensively by defining the number of measures to do, an interval and the size of the packet: ```bash -./donar -s -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 +measlat -h 127.0.0.1 -p 8000 -t udp -c 10 -i 100 -s 150 ``` -In a third terminal: +### Introduction to `donar` + +Now, let's introduce our main project. +First, kill all the remaining processes `killall udpecho measlat nc`. + +*On both machine* +Move to the donar repository root where you will see the `torrc_simple` file. +We will need to start by launching tor in a terminal: + +```bash +tor -f ./torrc_simple +``` + +*On machine A* +Launch Donar server in a second terminal: ```bash -./dcall 127.13.3.7 +donar -s -a naive -e 3000 -r 3001 ``` -Your "address" is contained inside the `onion_services.pub`, you must transmit it out of band to people that want to call you. - -## 4) Caller - -In a first terminal: +In a third terminal, launch your echo service: ```bash -./tor2 -f torrc_guard_12 +udpecho -p 3000 ``` -In a second terminal: +Display the content of the file `onion_services.pub` that has been created in your working directory. + +*On machine B* +Copy the content of the file `onion_services.pub` that is on *machine A* to *machine B* in a file named `machine_a.pub`. +Now, run Donar client in a second terminal: ```bash -./donar -c -o onion_service.pub -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 +donar -c -a naive -o machine_a.pub -r 3000 -e 3001 ``` -In a third terminal: +In a third terminal, launch your echo service: ```bash -./dcall 127.13.3.7 +udpecho -p 3001 ``` +*On machine A* +You can access to the echo service from *machine B* by running: +```bash +nc 127.13.3.7 3001 +# or +measlat -h 127.13.3.7 -p 3001 -t udp +``` + +*On machine B* +You can access to the echo service from *machine A* by running: + +```bash +nc 127.13.3.7 3000 +# or +measlat -h 127.13.3.7 -p 3000 -t udp +``` + +If it works, that's all! You are now mastering Donar! + +## Linphone configuration + +Choose a SIP UDP, Audio RTP/UDP and Video RTP/UDP that is different between your clients. +Go to manage account. +Add a new SIP proxy. + +``` +Username: @127.13.3.7:5061 +Proxy: 127.13.3.7:5060 +Leave the rest empty. +Uncheck all the checkboxes. +``` + +You also need to say to Linphone that you are behind a NAT and put `127.13.3.7` as your public IP address. + +## Docker build + +``` +sudo docker build -t registry.gitlab.inria.fr/qdufour/donar . +sudo docker push registry.gitlab.inria.fr/qdufour/donar +sudo docker pull registry.gitlab.inria.fr/qdufour/donar +``` + +``` +mkdir -p ./{xp1-shared,xp1-res} +sudo chown -R 1000 ./{xp1-shared,xp1-res} + +sudo docker run -t -i \ + --privileged \ + -v `pwd`/xp1-shared:/home/donar/shared \ + registry.gitlab.inria.fr/qdufour/donar \ + xp1-server + +sudo docker run -t -i \ + --privileged \ + -v `pwd`/xp1-res:/home/donar/res \ + -v `pwd`/xp1-shared:/home/donar/shared \ + registry.gitlab.inria.fr/qdufour/donar \ + xp1-client 1000 100 100 + +``` + +## Run an XP instance + +``` +sudo ./scripts/xp1 1000 100 100 +``` + +## Run instances in parallel + +We generate the name of the algorithm to run on the right side of the parallel command. +The idea is to generate a sequence like the following: `orig naive rr rrh orig naive rr rrh orig...`. + +``` +parallel -j 12 bash -c './xp-instance-runner $1 6000 100 100' -- `xp0=orig xp1=naive xp2=rr xp3=rrh xp4=witness; for i in {0..99}; do q='xp'$((i % 5)); echo ${!q}; done` +parallel.moreutils -j 16 bash -c './xp-instance-runner $0 6000 100 100' -- `xp0=orig xp1=naive xp2=rr xp3=rrh xp4=witness; for i in {0..274}; do q='xp'$((i % 5)); echo ${!q}; done` +parallel.moreutils -j 16 bash -c './xp-instance-runner $0 6000 100 100' -- `for i in {0..55}; do echo -n 'orig naive rr rrh witness '; done` +``` + +Tests: + +``` +parallel.moreutils -j 16 bash -c './xp-instance-runner rr 6000 100 100' -- `seq 0 15` +``` + +## Helpers + +Track measures that didn't finish: + +``` +ls | grep -P '^naive-|^rrh-|^rr-|^orig-' | while read n; do echo -n "$n "; tail -n1 $n/res/*.csv ; done | grep -v "Measurement done" +``` + +Check if timer's bug occured: + +``` +ls | grep -P '^naive-|^rrh-|^rr-|^orig-' | while read n; do echo "$n "; grep 'bug' $n/log/client-measlat-stderr.log; done +``` + +Check if a free() invalid pointer bug occured: + +``` +grep 'free' naive-*/log/*-donar-*.log +grep -rn 'free()' . +``` + +## Use a Linphone container + +``` +docker build -f linphone.dockerfile -t superboum/linphone . +``` + +Run it: + +``` +docker run \ + -ti \ + -e DISPLAY=$DISPLAY \ + -v /tmp/.X11-unix:/tmp/.X11-unix \ + --ipc=host \ + superboum/linphone \ + bash +``` + +http://gstreamer-devel.966125.n4.nabble.com/Need-help-with-using-OPUS-over-RTP-td4661409.html + +``` +# some sources +audiotestsrc +pulsesrc + +# some sinks +pulsesink + +# sender +gst-launch-1.0 \ + pulsesrc ! \ + audioconvert ! \ + opusenc audio-type=voice inband-fec=false frame-size=20 ! \ + rtpopuspay ! \ + udpsink host=127.0.0.1 port=5000 + +# receiver +gst-launch-1.0 \ + udpsrc port=5000 caps="application/x-rtp" ! \ + rtpjitterbuffer do-lost=true do-retransmission=false ! \ + rtpopusdepay ! \ + opusdec plc=true use-inband-fec=false ! \ + pulsesink + +# both sides +export TARGET=192.168.1.1 +gst-launch-1.0 \ + autoaudiosrc ! \ + queue ! \ + audioresample ! \ + opusenc audio-type=voice inband-fec=FALSE frame-size=20 bitrate=64000 dtx=TRUE ! \ + rtpopuspay ! \ + udpsink host=$TARGET port=5000 async=FALSE \ + udpsrc port=5000 caps="application/x-rtp" ! \ + rtpjitterbuffer do-lost=TRUE do-retransmission=FALSE latency=10 ! \ + rtpopusdepay ! \ + opusdec plc=TRUE use-inband-fec=FALSE ! \ + audioresample ! \ + autoaudiosink + +# both sides with echo cancellation +export TARGET=192.168.1.1 +gst-launch-1.0 \ + autoaudiosrc ! \ + webrtcdsp ! \ + queue ! \ + audioresample ! \ + opusenc audio-type=voice inband-fec=FALSE frame-size=20 bitrate=64000 dtx=TRUE ! \ + rtpopuspay ! \ + udpsink host=$TARGET port=5000 async=FALSE \ + udpsrc port=5000 caps="application/x-rtp" ! \ + rtpjitterbuffer do-lost=TRUE do-retransmission=FALSE latency=10 ! \ + rtpopusdepay ! \ + opusdec plc=TRUE use-inband-fec=FALSE ! \ + audioresample ! \ + webrtcechoprobe ! \ + autoaudiosink +``` + +``` +sudo docker run \ + --rm \ + -it \ + -e PULSE_SERVER=unix:/run/user/1000/pulse/native \ + -v ${XDG_RUNTIME_DIR}/pulse/native:/run/user/1000/pulse/native \ + -v ~/.config/pulse/cookie:/root/.config/pulse/cookie \ + --group-add $(getent group audio | cut -d: -f3) \ + registry.gitlab.inria.fr/qdufour/donar +``` diff --git a/src/dcall.c b/src/dcall.c index 8bbe006..d95d0d4 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -1,21 +1,23 @@ #include int create_rx_chain(GstElement *pipeline) { - GstElement *rx_tap, *rx_jitterbuffer, *rx_depay, *rx_opusdec, *rx_resample, *rx_sink; + GstElement *rx_tap, *rx_jitterbuffer, *rx_depay, *rx_opusdec, *rx_resample, *rx_echocancel, *rx_sink; rx_tap = gst_element_factory_make("udpsrc", "rx-tap"); rx_jitterbuffer = gst_element_factory_make("rtpjitterbuffer", "rx-jitterbuffer"); rx_depay = gst_element_factory_make("rtpopusdepay", "rx-depay"); rx_opusdec = gst_element_factory_make("opusdec", "rx-opusdec"); rx_resample = gst_element_factory_make("audioresample", "rx-audioresample"); + rx_echocancel = gst_element_factory_make("webrtcechoprobe", "rx-echocancel"); rx_sink = gst_element_factory_make("autoaudiosink", "rx-sink"); - if (!rx_tap || !rx_jitterbuffer || !rx_depay || !rx_opusdec || !rx_resample || !rx_sink) { + if (!rx_tap || !rx_jitterbuffer || !rx_depay || !rx_opusdec || !rx_resample || !rx_echocancel || !rx_sink) { g_printerr ("One element of the rx chain could not be created. Exiting.\n"); return -1; } g_object_set(G_OBJECT (rx_tap), "port", 5000, NULL); + g_object_set(G_OBJECT (rx_tap), "address", "127.0.0.1", NULL); g_object_set(G_OBJECT (rx_tap), "caps", gst_caps_new_simple("application/x-rtp", "media", G_TYPE_STRING, "audio", NULL), NULL); g_object_set(G_OBJECT (rx_jitterbuffer), "do-lost", TRUE, NULL); @@ -25,22 +27,23 @@ int create_rx_chain(GstElement *pipeline) { g_object_set(G_OBJECT (rx_opusdec), "plc", TRUE, NULL); g_object_set(G_OBJECT (rx_opusdec), "use-inband-fec", FALSE, NULL); - gst_bin_add_many (GST_BIN (pipeline), rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_sink, NULL); - gst_element_link_many (rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_sink, NULL); + gst_bin_add_many (GST_BIN (pipeline), rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_echocancel, rx_sink, NULL); + gst_element_link_many (rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_echocancel, rx_sink, NULL); return 0; } int create_tx_chain(GstElement *pipeline, char* remote_host) { - GstElement *tx_tap, *tx_resample, *tx_opusenc, *tx_pay, *tx_sink; + GstElement *tx_tap, *tx_echocancel, *tx_resample, *tx_opusenc, *tx_pay, *tx_sink; tx_tap = gst_element_factory_make("autoaudiosrc", "tx-tap"); + tx_echocancel = gst_element_factory_make("webrtcdsp", "tx-echocancel"); tx_resample = gst_element_factory_make("audioresample", "tx-resample"); tx_opusenc = gst_element_factory_make("opusenc", "tx-opusenc"); tx_pay = gst_element_factory_make("rtpopuspay", "tx-rtpopuspay"); tx_sink = gst_element_factory_make("udpsink", "tx-sink"); - if (!tx_tap || !tx_resample || !tx_opusenc || !tx_pay || !tx_sink) { + if (!tx_tap || !tx_echocancel || !tx_resample || !tx_opusenc || !tx_pay || !tx_sink) { g_printerr("One element of the tx chain could not be created. Exiting.\n"); return -1; } @@ -55,8 +58,8 @@ int create_tx_chain(GstElement *pipeline, char* remote_host) { g_object_set(G_OBJECT(tx_sink), "port", 5000, NULL); g_object_set(G_OBJECT(tx_sink), "async", FALSE, NULL); - gst_bin_add_many(GST_BIN(pipeline), tx_tap, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); - gst_element_link_many(tx_tap, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); + gst_bin_add_many(GST_BIN(pipeline), tx_tap, tx_echocancel, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); + gst_element_link_many(tx_tap, tx_echocancel, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); return 0; }