sender.c 4.62 KB
Newer Older
1 2
#include <stdio.h>
#include <string.h>
3
#include <stdint.h>
4
#include <signal.h>
5
#include <argp.h>
6
#include "util/dbg.h"
7
#include "proto/socket.h"
8

9 10 11
PrrtSocket *s = NULL;
static volatile int keepRunning = true;

12
static char doc[] = "PRRT Sender";
13

14
static struct argp_option options[] = {
15 16 17 18 19 20 21
        {"target",              't', "HOST",       0,  "Target Host" },
        {"port",                'p', "PORT",       0,  "Target Port" },
        {"local port",          'l', "PORT",       0,  "Local Port" },
        {"rounds",              'r', "ROUNDS",     0,  "Rounds" },
        {"output",              'o', "FILE",       0,  "Output to FILE instead of standard output" },
        {"threadpinning",       'T',  0,           0,  "Enable thread pinning"},
        {"hardwaretimestamping", 777, "INTERFACE", 0,  "Enable hardware timestamping and bind to interface"},
22 23 24
        { 0 }
};

Andreas Schmidt's avatar
Andreas Schmidt committed
25
typedef struct arguments
26 27 28
{
    char* target;
    uint16_t port;
29
    uint16_t local_port;
30 31
    uint16_t rounds;
    char* outfile;
32
    bool thread_pinning;
33
    char* hardwarestamping_interface;
Andreas Schmidt's avatar
Andreas Schmidt committed
34
} arguments_t;
35 36 37 38 39

static char args_doc[] = "";

static error_t parse_opt (int key, char *arg, struct argp_state *state)
{
Andreas Schmidt's avatar
Andreas Schmidt committed
40
    arguments_t* arguments = state->input;
41 42 43 44 45 46 47 48 49 50

    char* pEnd;
    switch (key)
    {
        case 't':
            arguments->target = arg;
            break;
        case 'p':
            arguments->port = (uint16_t) strtol(arg, &pEnd, 10);
            break;
51 52 53
        case 'l':
            arguments->local_port = (uint16_t) strtol(arg, &pEnd, 10);
            break;
54 55 56 57 58 59
        case 'r':
            arguments->rounds = (uint16_t) strtol(arg, &pEnd, 10);
            break;
        case 'o':
            arguments->outfile = arg;
            break;
60 61 62
        case 'T':
            arguments->thread_pinning = true;
            break;
63 64 65 66 67 68 69 70 71
        case 777:
            arguments->hardwarestamping_interface = arg;
            break;

        case ARGP_KEY_END:
            break;

        default:
            return ARGP_ERR_UNKNOWN;
72
    }
73 74 75
    return 0;
}

76 77 78 79
void intHandler(int dummy) {
    keepRunning = false;
    PrrtSocket_interrupt(s);
}
80

81
int main(int argc, char **argv) {
82 83
    signal(SIGINT, intHandler);

84 85 86 87 88
    struct argp argp = { options, parse_opt, args_doc, doc };

    struct arguments arguments = {
        .target = "127.0.0.1",
        .port = 5000,
89
        .local_port = 6000,
90 91
        .rounds = 127,
        .outfile = "-",
92
        .thread_pinning = false,
93 94 95 96 97 98 99 100
        .hardwarestamping_interface = "-"
    };
    argp_parse (&argp, argc, argv, 0, 0, &arguments);

    bool file_output = false;
    FILE *out_desc = stdout;

    if (strcmp(arguments.outfile, "-") != 0) {
101
        file_output = true;
102
        out_desc = fopen(arguments.outfile, "w");
103 104
    }

105
    uint32_t rounds = arguments.rounds;
106 107 108 109 110 111
    #ifdef XLAP
    if (rounds >= TS_ROWS) {
        printf("Sender: Too many rounds for use with XLAP (max: %d).\n", TS_ROWS-1);
        return -1;
    }
    #endif
112

113

114
    s = PrrtSocket_create(1400, 10 * 1000 * 1000);
115 116
    check(s != NULL, "Socket create failed.");

117
    if(strcmp(arguments.hardwarestamping_interface, "-") != 0) {
118
        PrrtSocket_enable_hardware_timestamping(s, arguments.hardwarestamping_interface);
119
    }
120

121 122 123 124
    if(arguments.thread_pinning) {
        PrrtSocket_enable_thread_pinning(s);
    }

Andreas Schmidt's avatar
Andreas Schmidt committed
125
    check(PrrtSocket_bind(s, "0.0.0.0", arguments.local_port) == EXIT_SUCCESS, "bind failed");
126 127

    //PrrtSocket_set_coding_parameters(s, 1, 1); // comment this line to re-enable coding.
128

129
    PrrtSocket_connect(s, arguments.target, arguments.port);
130

Andreas Schmidt's avatar
Andreas Schmidt committed
131 132 133 134
    XlapTimestampTable *tstable_data = malloc(sizeof(XlapTimestampTable));
    XlapTimestampTable *tstable_redundancy = malloc(sizeof(XlapTimestampTable));
    check(tstable_data != NULL, "malloc failed");
    check(tstable_redundancy != NULL, "malloc failed");
135 136
    XlapTimestampTableInstall(s, ts_data_packet, tstable_data);
    XlapTimestampTableInstall(s, ts_redundancy_packet, tstable_redundancy);
Stefan Reif's avatar
Stefan Reif committed
137

Andreas Schmidt's avatar
Andreas Schmidt committed
138
    uint32_t j = 0;
139
    while (j < rounds && keepRunning) {
Andreas Schmidt's avatar
Andreas Schmidt committed
140
        char buf[MAX_PAYLOAD_LENGTH];
141 142
        // 1400 bytes.
        sprintf(buf, "%1400d", j + 1);
Stefan Reif's avatar
Stefan Reif committed
143

Andreas Schmidt's avatar
Andreas Schmidt committed
144
        PrrtSocket_send_async(s, (unsigned char *) buf, strlen(buf));
Stefan Reif's avatar
Stefan Reif committed
145

146
        j++;
Andreas Schmidt's avatar
Andreas Schmidt committed
147 148
        // Send every 100us, as this is a sensible packet interval.
        usleep_nano(100);
149
    }
150
    sleep_nano(10);
151

152 153 154
    XlapTimestampTableDumpHeader(out_desc);
    XlapTimestampTableDump(out_desc, ts_data_packet, tstable_data);
    XlapTimestampTableDump(out_desc, ts_redundancy_packet, tstable_redundancy);
155

Andreas Schmidt's avatar
Andreas Schmidt committed
156
    if (file_output) {
157
        fflush(out_desc);
158 159
        fclose(out_desc);
    }
160

161 162
    PrrtSocket_close(s);
    free(s);
Andreas Schmidt's avatar
Andreas Schmidt committed
163 164
    free(tstable_data);
    free(tstable_redundancy);
165
    return 0;
166 167

    error:
168
    return -1;
169
}