Merge branch 'master' of gitlab.inria.fr:qdufour/donar

This commit is contained in:
Quentin 2020-01-28 19:49:50 +01:00
commit d715ee2f34
5 changed files with 546 additions and 5 deletions

View file

@ -49,11 +49,13 @@ add_executable(torecho ${CSOURCES} src/tor_echo.c)
add_executable(capdiff ${CSOURCES} src/capdiff.c)
add_executable(capreplay ${CSOURCES} src/capreplay.c)
add_executable(donar_unit_test ${CSOURCES} src/test.c)
add_executable(dcall src/call.c)
add_executable(dcall src/dcall.c)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED glib-2.0)
pkg_check_modules(GST REQUIRED gstreamer-1.0>=1.16)
pkg_search_module(GST REQUIRED gstreamer-1.0 >= 1.14)
>>>>>>> 22c07f1e26d7ad8bd76249bf690e437f27e25529
target_include_directories(donar PRIVATE ${GLIB_INCLUDE_DIRS})
target_link_libraries(donar ${GLIB_LDFLAGS})

View file

@ -1,4 +1,4 @@
FROM fedora:30 as builder
FROM fedora:31 as builder
RUN dnf install -y \
coreutils \
cmake \
@ -14,7 +14,8 @@ RUN dnf install -y \
automake \
libzstd-devel \
xz-devel \
git
git \
gstreamer1-devel
WORKDIR /home/donar-build
RUN chown -R 1000 /home/donar-build
@ -41,7 +42,7 @@ RUN mkdir out && \
#####
FROM fedora:30
FROM fedora:31
RUN dnf install -y \
glib2 \
procps-ng \
@ -69,6 +70,7 @@ COPY --from=builder /home/donar-build/out/donar /usr/local/bin
COPY --from=builder /home/donar-build/out/measlat /usr/local/bin
COPY --from=builder /home/donar-build/out/udpecho /usr/local/bin
COPY --from=builder /home/donar-build/out/torecho /usr/local/bin
COPY --from=builder /home/donar-build/out/dcall /usr/local/bin
COPY --from=builder /home/donar-build/tor2/src/app/tor /usr/local/bin/tor2
COPY --from=builder /home/donar-build/tor3/src/app/tor /usr/local/bin/tor3
COPY ./scripts/container/* /usr/local/bin/

300
README.more.md Normal file
View file

@ -0,0 +1,300 @@
# Donar
## Quickstart
### Installation
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
```
### 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
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
```
### Introduction to the debug tools `udpecho` and `measlat`
Now let's start simple, we will launch our udp echo server and access it locally:
```bash
udpecho -p 8000 &
nc 127.0.0.1 8000
```
If you write some data on your terminal and press enter, you will see that your data has been repeated. Well done!
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
measlat -h 127.0.0.1 -p 8000 -t udp
```
`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
measlat -h 127.0.0.1 -p 8000 -t udp -c 10 -i 100 -s 150
```
### 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
donar -s -a naive -e 3000 -r 3001
```
In a third terminal, launch your echo service:
```bash
udpecho -p 3000
```
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 -a naive -o machine_a.pub -r 3000 -e 3001
```
In a third terminal, launch your echo service:
```bash
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: <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
```

13
create_binaries.sh Executable file
View file

@ -0,0 +1,13 @@
#!/usr/bin/bash
mkdir -p release
docker run \
--rm \
-it \
-v `pwd`/release:/tmp/release \
registry.gitlab.inria.fr/qdufour/donar \
cp \
/usr/local/bin/{tor2,tor3,dcall,donar,measlat} \
/etc/{torrc_guard_12,torrc_guard_2,torrc_single_hop_12} \
/tmp/release
zip -r donar.zip release/

224
src/dcall.c Normal file
View file

@ -0,0 +1,224 @@
#include <gst/gst.h>
#include <glib-2.0/glib.h>
#include <glib-2.0/gmodule.h>
#include <glib-2.0/glib-object.h>
#include <glib-2.0/glib-unix.h>
#include <gst/rtp/gstrtpbuffer.h>
struct dcall_elements {
GstElement *pipeline;
GstElement *rx_tap, *rx_jitterbuffer, *rx_depay, *rx_opusdec, *rx_resample, *rx_echocancel, *rx_sink;
GstElement *tx_tap, *tx_echocancel, *tx_queue, *tx_resample, *tx_opusenc, *tx_pay, *tx_sink;
char* remote_host;
guint bus_watch_id;
};
int create_rx_chain(struct dcall_elements* de) {
de->rx_tap = gst_element_factory_make("udpsrc", "rx-tap");
de->rx_jitterbuffer = gst_element_factory_make("rtpjitterbuffer", "rx-jitterbuffer");
de->rx_depay = gst_element_factory_make("rtpopusdepay", "rx-depay");
de->rx_opusdec = gst_element_factory_make("opusdec", "rx-opusdec");
de->rx_resample = gst_element_factory_make("audioresample", "rx-audioresample");
de->rx_echocancel = gst_element_factory_make("webrtcechoprobe", "rx-echocancel");
de->rx_sink = gst_element_factory_make("autoaudiosink", "rx-sink");
if (!de->rx_tap || !de->rx_jitterbuffer || !de->rx_depay || !de->rx_opusdec || !de->rx_resample || !de->rx_echocancel || !de->rx_sink) {
g_printerr ("One element of the rx chain could not be created. Exiting.\n");
return -1;
}
g_object_set(G_OBJECT (de->rx_tap), "port", 5000, NULL);
//g_object_set(G_OBJECT (rx_tap), "address", "127.0.0.1", NULL);
g_object_set(G_OBJECT (de->rx_tap), "caps", gst_caps_new_simple("application/x-rtp", "media", G_TYPE_STRING, "audio", NULL), NULL);
g_object_set(G_OBJECT (de->rx_jitterbuffer), "do-lost", TRUE, NULL);
g_object_set(G_OBJECT (de->rx_jitterbuffer), "do-retransmission", FALSE, NULL);
g_object_set(G_OBJECT (de->rx_jitterbuffer), "latency", 50, NULL);
g_object_set(G_OBJECT (de->rx_jitterbuffer), "drop-on-latency", TRUE, NULL);
//g_object_set(G_OBJECT (de->rx_jitterbuffer), "post-drop-messages", TRUE, NULL);
g_object_set(G_OBJECT (de->rx_opusdec), "plc", TRUE, NULL);
g_object_set(G_OBJECT (de->rx_opusdec), "use-inband-fec", FALSE, NULL);
gst_bin_add_many (GST_BIN (de->pipeline), de->rx_tap, de->rx_jitterbuffer, de->rx_depay, de->rx_opusdec, de->rx_resample, de->rx_echocancel, de->rx_sink, NULL);
gst_element_link_many (de->rx_tap, de->rx_jitterbuffer, de->rx_depay, de->rx_opusdec, de->rx_resample, de->rx_echocancel, de->rx_sink, NULL);
return 0;
}
int create_tx_chain(struct dcall_elements* de) {
de->tx_tap = gst_element_factory_make("autoaudiosrc", "tx-tap");
de->tx_echocancel = gst_element_factory_make("webrtcdsp", "tx-echocancel");
//tx_queue = gst_element_factory_make("queue", "tx-queue");
de->tx_resample = gst_element_factory_make("audioresample", "tx-resample");
de->tx_opusenc = gst_element_factory_make("opusenc", "tx-opusenc");
de->tx_pay = gst_element_factory_make("rtpopuspay", "tx-rtpopuspay");
de->tx_sink = gst_element_factory_make("udpsink", "tx-sink");
if (!de->tx_tap || !de->tx_echocancel || /*!de->tx_queue ||*/ !de->tx_resample || !de->tx_opusenc || !de->tx_pay || !de->tx_sink) {
g_printerr("One element of the tx chain could not be created. Exiting.\n");
return -1;
}
gst_util_set_object_arg(G_OBJECT(de->tx_opusenc), "audio-type", "voice");
g_object_set(G_OBJECT(de->tx_opusenc), "inband-fec", FALSE, NULL);
g_object_set(G_OBJECT(de->tx_opusenc), "frame-size", 40, NULL);
g_object_set(G_OBJECT(de->tx_opusenc), "bitrate", 32000, NULL);
g_object_set(G_OBJECT(de->tx_opusenc), "dtx", FALSE, NULL); // gstreamer dtx opus implem. is broken
g_object_set(G_OBJECT(de->tx_sink), "host", de->remote_host, NULL);
g_object_set(G_OBJECT(de->tx_sink), "port", 5000, NULL);
g_object_set(G_OBJECT(de->tx_sink), "async", FALSE, NULL);
g_object_set(G_OBJECT(de->tx_echocancel), "echo-cancel", TRUE, NULL);
g_object_set(G_OBJECT(de->tx_echocancel), "extended-filter", TRUE, NULL);
g_object_set(G_OBJECT(de->tx_echocancel), "gain-control", TRUE, NULL);
g_object_set(G_OBJECT(de->tx_echocancel), "high-pass-filter", TRUE, NULL);
g_object_set(G_OBJECT(de->tx_echocancel), "limiter", FALSE, NULL);
g_object_set(G_OBJECT(de->tx_echocancel), "noise-suppression", TRUE, NULL);
g_object_set(G_OBJECT(de->tx_echocancel), "probe", "rx-echocancel", NULL);
g_object_set(G_OBJECT(de->tx_echocancel), "voice-detection", FALSE, NULL);
gst_bin_add_many(GST_BIN(de->pipeline), de->tx_tap, de->tx_echocancel, /*tx_queue,*/ de->tx_resample, de->tx_opusenc, de->tx_pay, de->tx_sink, NULL);
gst_element_link_many(de->tx_tap, de->tx_echocancel, /*tx_queue,*/ de->tx_resample, de->tx_opusenc, de->tx_pay, de->tx_sink, NULL);
return 0;
}
static GstPadProbeReturn jitter_buffer_sink_event(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) {
struct dcall_elements *de = user_data;
GstEvent *event = NULL;
g_print("Entering rtpjitterbuffer sink pad handler for events...\n");
event = gst_pad_probe_info_get_event (info);
if (event == NULL) return GST_PAD_PROBE_OK;
g_print("We successfully extracted an event from the pad... \n");
const GstStructure *struc = NULL;
struc = gst_event_get_structure(event);
if (struc == NULL) return GST_PAD_PROBE_OK;
g_print("We successfully extracted a structure from the event... \n");
const gchar* struc_name = NULL;
struc_name = gst_structure_get_name(struc);
if (struc_name == NULL) return GST_PAD_PROBE_OK;
g_print("We extracted the structure \"%s\"...\n", struc_name);
if (strcmp(struc_name, "GstRTPPacketLost") != 0) return GST_PAD_PROBE_OK;
g_print("And that's the structure we want !\n");
guint seqnum = 0, retry = 0;
guint64 timestamp = 0, duration = 0;
gst_structure_get_uint(struc, "seqnum", &seqnum);
gst_structure_get_uint(struc, "retry", &retry);
gst_structure_get_uint64(struc, "timestamp", &timestamp);
gst_structure_get_uint64(struc, "duration", &duration);
g_print("GstRTPPacketLost{seqnum=%d, retry=%d, duration=%ld, timestamp=%ld}\n", seqnum, retry, duration, timestamp);
return GST_PAD_PROBE_OK;
}
static GstPadProbeReturn jitter_buffer_sink_buffer(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) {
//g_print("Entering rtpjitterbuffer sink pad handler for buffers...\n");
GstBuffer *buffer = NULL;
buffer = gst_pad_probe_info_get_buffer (info);
if (buffer == NULL) return GST_PAD_PROBE_OK;
//if (gst_buffer_get_size (buffer) != 172) g_print("buffer size is %ld\n", gst_buffer_get_size (buffer));
GstMapInfo gmi;
gst_buffer_map(buffer, &gmi, GST_MAP_READ);
GstRTPBuffer *rtp_buffer;
rtp_buffer->
return GST_PAD_PROBE_OK;
}
void register_pad(struct dcall_elements *de) {
GstPad *pad;
pad = gst_element_get_static_pad (de->rx_jitterbuffer, "sink");
//gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, jitter_buffer_sink_event, &de, NULL);
gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, jitter_buffer_sink_buffer, &de, NULL);
}
static gboolean pipeline_bus_handler (GstBus *bus, GstMessage *message, gpointer data) {
g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
const GstStructure *struc = NULL;
struc = gst_message_get_structure(message);
g_print("structure is: %s \n", gst_structure_to_string (struc));
return TRUE;
}
void register_bus(struct dcall_elements *de) {
GstBus *bus;
bus = gst_pipeline_get_bus (GST_PIPELINE (de->pipeline));
de->bus_watch_id = gst_bus_add_watch (bus, pipeline_bus_handler, de);
gst_object_unref(bus);
}
gboolean stop_handler(gpointer user_data) {
GMainLoop *loop = user_data;
g_main_loop_quit(loop);
return TRUE;
}
int main(int argc, char *argv[]) {
GMainLoop *loop;
struct dcall_elements de;
/* Check input arguments */
if (argc != 2) {
g_printerr ("Usage: %s <Remote host>\n", argv[0]);
return -1;
}
de.remote_host = argv[1];
gst_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
de.pipeline = gst_pipeline_new ("pipeline");
if (!de.pipeline) {
g_printerr ("Pipeline could not be created. Exiting.\n");
return -1;
}
if (create_rx_chain (&de) != 0) return -1;
if (create_tx_chain (&de) != 0) return -1;
register_pad(&de);
//register_bus(&de);
gst_element_set_state (de.pipeline, GST_STATE_PLAYING);
g_unix_signal_add (SIGTERM, stop_handler, loop);
g_unix_signal_add (SIGINT, stop_handler, loop);
g_print ("Running...\n");
g_main_loop_run (loop);
g_print ("Main loop stopped...\n");
GstStructure *stats;
guint64 num_pushed, num_lost, num_late, num_duplicates;
g_object_get(de.rx_jitterbuffer, "stats", &stats, NULL);
gst_structure_get_uint64(stats, "num-pushed", &num_pushed);
gst_structure_get_uint64(stats, "num-lost", &num_lost);
gst_structure_get_uint64(stats, "num-late", &num_late);
gst_structure_get_uint64(stats, "num-duplicates", &num_duplicates);
g_print("pkt_delivered=%ld, pkt_lost=%ld, pkt_late=%ld, pkt_duplicates=%ld\n", num_pushed, num_lost, num_late, num_duplicates);
gst_element_set_state (de.pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (de.pipeline));
// g_source_remove (de.bus_watch_id);
g_main_loop_unref (loop);
return 0;
}