Commit 2c8058a4 authored by Andreas Schmidt's avatar Andreas Schmidt
Browse files

Merge branch 'develop'

parents ab2b00fd 17b3cb02
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9,3 +9,4 @@ tests/__pycache__/
MANIFEST
prrt.cpython*.so
prrt.so
.ipynb_checkpoints/
+28 −1
Original line number Diff line number Diff line
@@ -38,6 +38,17 @@ build:container:
        - docker push $CI_REGISTRY_IMAGE:$DOCKER_TAG
        - docker rmi $CI_REGISTRY_IMAGE:$DOCKER_TAG

build:container_tcp:
    stage: build
    tags:
        - docker
    script:
        - export DOCKER_TAG=$(echo "$CI_BUILD_REF_NAME""_tcp" | sed 's#/#_#' | sed 's#^master$#latest#')
        - docker build -t $CI_REGISTRY_IMAGE:$DOCKER_TAG --build-arg http_proxy=http://www-proxy.uni-saarland.de:3128 -f docker/Dockerfile_tcp .
        - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
        - docker push $CI_REGISTRY_IMAGE:$DOCKER_TAG
        - docker rmi $CI_REGISTRY_IMAGE:$DOCKER_TAG

test:prrt_mem:
  stage: test
  dependencies:
@@ -79,3 +90,19 @@ deploy:pypi:
    - echo "password=$PYPI_PASSWORD" >> ~/.pypirc
    - python3 setup.py check sdist bdist upload -r on
    - rm -vf ~/.pypirc

deploy:profile:
  stage: deploy
  tags:
    - gprof
  script:
    - ls -lahv
    - rm CMakeCache.txt
    - CC=gcc-5 CXX=g++-5 cmake . -DGPROF=1
    - make
    - bash profiling/profile.sh
  artifacts:
    paths:
    - gprof-send.txt
    - gprof-recv.txt
    expire_in: 30 days
 No newline at end of file
+7 −1
Original line number Diff line number Diff line
@@ -2,16 +2,22 @@ cmake_minimum_required (VERSION 2.8.11)
project (PRRT)

option(PRRT_TESTS "Build tests" OFF)
option(GPROF "Compile with profiler" OFF)

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

set(CMAKE_C_FLAGS "-O2 -Wall -std=gnu11 -D_GNU_SOURCE -fPIC" )
set(CMAKE_C_FLAGS_DEBUG "-O0 -fsanitize=undefined -fsanitize=address -g3" )
set(CMAKE_CXX_FLAGS "-fstack-protector -fstack-protector-all -Wall -std=gnu++11 -D_GNU_SOURCE" )
set(CMAKE_CXX_FLAGS_DEBUG "-O2 -Wall -ggdb" )
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -Wall -ggdb -fsanitize=undefined -fsanitize=address -g3" )
set(CMAKE_CXX_FLAGS_RELEASE "-Os -Wall" )

if(GPROF)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg")
endif()

find_package (Threads)
find_library(M_LIB m)
+26 −8
Original line number Diff line number Diff line
@@ -4,12 +4,14 @@

## Features

* Forward Error Correction (FEC) using systematic Vandermonde codes
* Hybrid error control (FEC + ARQ) using systematic Vandermonde codes
* Congestion control and pacing using a variant of [BBR](https://groups.google.com/forum/#!forum/bbr-dev)
* Clock synchronization between sending stack and receiving stack
* Applications can specify packet-level expiration times
* Different receive modes for ASAP and time-synchronized operation
* Passive measurement of propagation delay, bottleneck data rate and packet loss rate
* Packet-level timing analysis using [X-Lap](http://xlap.larn.systems)
* Wireshark dissector written in Lua
* [Hardware timestamping support](https://git.nt.uni-saarland.de/LARN/PRRT/wikis/hardware-timestamping)

## Installation
@@ -29,9 +31,9 @@ port = int(sys.argv[1])
s = prrt.PrrtSocket(port=port)

while True:
    d = s.recv()
    d = s.recv().decode("utf8")
    if d != "Close":
        print d
        print(d)
    else:
        break
```
@@ -44,25 +46,27 @@ import prrt

host = sys.argv[1]
port = int(sys.argv[2])
localport = int(sys.argv[3])

s = prrt.PrrtSocket(port=port)
s = prrt.PrrtSocket(port=localport)
s.connect(host, port)


for i in range(10):
    s.send("Packet {}".format(i))
s.send("Close")
    s.send("Packet {}".format(i).encode("utf8"))
s.send("Close".encode("utf8"))
```

Start the receiver by:

```bash
python receiver.py 5000
python3 receiver.py 5000
```

In a separate terminal, run:

```bash
python sender.py 127.0.0.1 5000
python3 sender.py 127.0.0.1 5000 6000
```

This should generate the following output in the receiver console:
@@ -79,6 +83,20 @@ Packet 9
* [PRRT Wiki](https://git.nt.uni-saarland.de/LARN/PRRT/wikis)
* [LARN Project Website](http://larn.systems)

## Citing Us

If you find PRRT useful and incorporate it in your works, we are very happy to hear about it. Please also consider to cite us like this:

```bibtex
@misc{sic2018prrt,
      author = {Schmidt, Andreas},
      title = {PRRT: Predictably Reliable Real-time Transport},
      howpublished={Web page},
      url = {http://prrt.larn.systems},
      year = {2018}
}
```

## License

[MIT Licence](LICENSE)

dissect/prrt.lua

0 → 100644
+208 −0
Original line number Diff line number Diff line
-- For an excellent example script, see
-- https://wiki.wireshark.org/Lua/Examples?action=AttachFile&do=get&target=dissector.lua


-- declare our protocol
local prrt_proto = Proto("prrt","Predictably Reliable Real-time Transport")

local prrtPacketTypeNames = {
    [0] = "Data",
    [1] = "Repetition",
    [2] = "Redundancy",
    [3] = "Feedback",
    [4] = "Pre-sent Redundancy",
    [5] = "Channel Feedback"
}

-- create the fields
local pf_type = ProtoField.uint8("prrt.type", "Type", base.DEC, prrtPacketTypeNames, 240)
local pf_prio = ProtoField.uint8("prrt.priority", "Priority", base.DEC, nil, 15)
local pf_idx = ProtoField.uint8("prrt.index", "Index")
local pf_seqN = ProtoField.uint16("prrt.sequenceNumber", "Sequence Number")

local pf_data = ProtoField.new("Data", "prrt.data", ftypes.BYTES, base.NONE)
local pf_data_length = ProtoField.uint32("prrt.data.length", "Length")
local pf_data_timestamp = ProtoField.uint32("prrt.data.timestamp", "Timestamp")
local pf_data_groupRTprop = ProtoField.uint32("prrt.data.grouprtprop", "Group RTprop")
local pf_data_packettimeout = ProtoField.uint32("prrt.data.packettimeout", "Packet Timeout")

local pf_red = ProtoField.new("Redundancy", "prrt.redundancy", ftypes.BYTES, base.NONE)
local pf_red_baseSeqN = ProtoField.uint16("prrt.redundancy.baseSequenceNumber", "Base Sequence Number", base.DEC)
local pf_red_timestamp = ProtoField.uint32("prrt.redundancy.timestamp", "Timestamp")
local pf_red_n = ProtoField.uint8("prrt.redundancy.n", "n")
local pf_red_k = ProtoField.uint8("prrt.redundancy.k", "k")

local pf_fb = ProtoField.new("Feedback", "prrt.feedback", ftypes.BYTES, base.NONE)
local pf_fb_groupRTT = ProtoField.uint32("prrt.feedback.groupRTT", "Group RTT")
local pf_fb_ftt = ProtoField.uint32("prrt.feedback.FTT", "FTT")
local pf_fb_erasurecount = ProtoField.uint16("prrt.feedback.erasureCount", "Erasure count")
local pf_fb_packetcount = ProtoField.uint16("prrt.feedback.packetCount", "Packet count")
local pf_fb_gaplength = ProtoField.uint16("prrt.feedback.gapLength", "Gap length")
local pf_fb_gapcount = ProtoField.uint16("prrt.feedback.gapCount", "Gap count")
local pf_fb_burstlength = ProtoField.uint16("prrt.feedback.burstLength", "Burst length")
local pf_fb_burstcount = ProtoField.uint16("prrt.feedback.burstCount", "Burst count")
local pf_fb_acktype = ProtoField.uint8("prrt.feedback.ackPacketType", "Ack Packet Type", base.DEC, prrtPacketTypeNames)
local pf_fb_ackSeqN = ProtoField.uint16("prrt.feedback.ackSequenceNumber", "Ack Sequence Number")

-- add the fields to the protocol
prrt_proto.fields = {
    pf_type,
    pf_prio,
    pf_idx,
    pf_seqN,

    pf_data,
    pf_data_length,
    pf_data_timestamp,
    pf_data_groupRTprop,
    pf_data_packettimeout,

    pf_red,
    pf_red_baseSeqN,
    pf_red_timestamp,
    pf_red_n,
    pf_red_k,

    pf_fb,
    pf_fb_groupRTT,
    pf_fb_ftt,
    pf_fb_erasurecount,
    pf_fb_packetcount,
    pf_fb_gaplength,
    pf_fb_gapcount,
    pf_fb_burstlength,
    pf_fb_burstcount,
    pf_fb_acktype,
    pf_fb_ackSeqN,
}

-- create expert info fields
local ef_too_short = ProtoExpert.new("prrt.too_short.expert", "PRRT Packet too short",
                                     expert.group.MALFORMED, expert.severity.ERROR)

prrt_proto.experts = {
    ef_too_short
}

-- Create extractor fields (for some reason this can't be done with the fields that already exist)
local ex_type = Field.new("prrt.type")
local function getType() return ex_type()() end
local function getTypeName() return prrtPacketTypeNames[getType()] end

local ex_index = Field.new("prrt.index")
local function getIndex() return ex_index()() end

local ex_data_length = Field.new("prrt.data.length")
local function getDataLength() return ex_data_length()() end

local ex_red_baseseqno = Field.new("prrt.redundancy.baseSequenceNumber")
local function getRedBaseSeqNo() return ex_red_baseseqno()() end


local ex_red_n = Field.new("prrt.redundancy.n")
local function getRedN() return ex_red_n()() end

local ex_red_k = Field.new("prrt.redundancy.k")
local function getRedK() return ex_red_k()() end

-- some constants
local PRRT_MIN_SIZE = 8

-- create sub-dissectors for different types
local function dissect_data(buffer, pinfo, root)
    local tree = root:add(pf_data, buffer:range(0))
    tree:add(pf_data_length, buffer:range(0,4))
    tree:add(pf_data_timestamp, buffer:range(4,4))
    tree:add(pf_data_groupRTprop, buffer:range(8,4))
    tree:add(pf_data_packettimeout, buffer:range(12,4))

    local label = "[D] Idx=" .. getIndex() .. " Len=" .. getDataLength()
    tree:set_text(label)
    pinfo.cols.info:set(label)
end

local function dissect_redundancy(buffer, pinfo, root)
    local tree = root:add(pf_red, buffer:range(0))
    tree:add(pf_red_baseSeqN, buffer:range(0,2))
    tree:add(pf_red_timestamp, buffer:range(2,4))
    tree:add(pf_red_n, buffer:range(6,1))
    tree:add(pf_red_k, buffer:range(7,1))

    local label = "[R] Idx=" .. getIndex() .. " b=" .. getRedBaseSeqNo() .. " n=" .. getRedN() .. " k=" .. getRedK()
    tree:set_text(label)
    pinfo.cols.info:set(label)
end

local function dissect_feedback(buffer, pinfo, root)
    local tree = root:add(pf_fb, buffer:range(0))
    tree:add(pf_fb_groupRTT, buffer:range(0,4))
    tree:add(pf_fb_ftt, buffer:range(4,4))
    tree:add(pf_fb_erasurecount, buffer:range(8,2))
    tree:add(pf_fb_packetcount, buffer:range(10,2))
    tree:add(pf_fb_gaplength, buffer:range(12,2))
    tree:add(pf_fb_gapcount, buffer:range(14,2))
    tree:add(pf_fb_burstlength, buffer:range(16,2))
    tree:add(pf_fb_burstcount, buffer:range(18,2))
    tree:add(pf_fb_acktype, buffer:range(20,1))
    tree:add(pf_fb_ackSeqN, buffer:range(21, 2))

    local label = "[F]"
    tree:set_text(label)
    pinfo.cols.info:set(label)
end

local subdissectors = {
    [0] = dissect_data,
    [2] = dissect_redundancy,
    [3] = dissect_feedback
}

-- create a function to dissect each frame
function prrt_proto.dissector(buffer,pinfo,root)
    -- set the protocol column
    pinfo.cols.protocol:set("PRRT")

    local pktlen = buffer:reported_length_remaining()

    --[[ TODO
         parse whether the packet has a payload first
         if it has, do not use the entire buffer:range(0)
         in the tree label, but only up to the payload
         and add another "Data" subtree containing only
         the payload
    --]]
    local tree = root:add(prrt_proto, buffer:range(0))

    if pktlen < PRRT_MIN_SIZE then
        tree:add_proto_expert_info(ef_too_short)
        return
    end

    tree:add(pf_type, buffer:range(0,1))
    tree:add(pf_prio, buffer:range(0,1))
    tree:add(pf_idx,  buffer:range(1,1))
    tree:add(pf_seqN, buffer:range(2,2))

    if subdissectors[getType()] then
        subdissectors[getType()](buffer:range(4,nil):tvb(), pinfo, tree)
    end

end

local current_port = 6000
DissectorTable.get("udp.port"):add(current_port, prrt_proto)

prrt_proto.prefs.port = Pref.uint("Port number", current_port, "The UDP Port number for PRRT")

function prrt_proto.prefs_changed()
    if current_port ~= prrt_proto.prefs.port then
        if curent_port ~= 0 then
            DissectorTable.get("udp.port"):remove(current_port, prrt_proto)
        end
        current_port = prrt_proto.prefs.port
        if current_port ~= 0 then
            DissectorTable.get("udp.port"):add(current_port, prrt_proto)
        end
    end
end
Loading