source: lib/format_etsilive.c @ b359a11

develop
Last change on this file since b359a11 was b359a11, checked in by Shane Alcock <salcock@…>, 2 years ago

Fix uninitialised ETSI live sockets bug

If we ever had to extend the socket array, the sockets in the
extended portion of the array were not being initialised properly.

  • Property mode set to 100644
File size: 27.1 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2017 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26
27#define _GNU_SOURCE
28
29#include "config.h"
30#include "common.h"
31#include "libtrace.h"
32#include "libtrace_int.h"
33#include "format_helper.h"
34#include "data-struct/simple_circular_buffer.h"
35
36#include <libwandder.h>
37#include <libwandder_etsili.h>
38
39#include <errno.h>
40#include <fcntl.h>
41#include <stdio.h>
42#include <string.h>
43#include <stdlib.h>
44#include <unistd.h>
45#include <sys/socket.h>
46#include <sys/types.h>
47#include <netdb.h>
48
49#define ETSI_RECVBUF_SIZE (64 * 1024 * 1024)
50
51#define FORMAT_DATA ((etsilive_format_data_t *)libtrace->format_data)
52
53typedef struct etsipktcache {
54
55        uint64_t timestamp;
56        uint16_t length;
57
58} etsi_packet_cache_t;
59
60typedef struct etsisocket {
61        int sock;
62        struct sockaddr *srcaddr;
63
64        libtrace_scb_t recvbuffer;
65        etsi_packet_cache_t cached;
66
67} etsisocket_t;
68
69typedef struct etsithread {
70        libtrace_message_queue_t mqueue;
71        etsisocket_t *sources;
72        uint16_t sourcecount;
73        uint16_t sourcealloc;
74        uint16_t activesources;
75        int threadindex;
76        wandder_etsispec_t *etsidec;
77} etsithread_t;
78
79typedef struct etsilive_format_data {
80        char *listenport;
81        char *listenaddr;
82
83        pthread_t listenthread;
84        etsithread_t *receivers;
85        int nextthreadid;
86        wandder_etsispec_t *shareddec;
87} etsilive_format_data_t;
88
89typedef struct newsendermessage {
90        int recvsock;
91        struct sockaddr *recvaddr;
92} newsend_message_t;
93
94static int send_etsili_keepalive_response(int fd, int64_t seqno);
95
96static void *etsi_listener(void *tdata) {
97        libtrace_t *libtrace = (libtrace_t *)tdata;
98        struct addrinfo hints, *listenai;
99        struct sockaddr_storage *connected;
100        socklen_t addrsize;
101        int sock, consock;
102        int reuse = 1;
103
104        hints.ai_family = PF_UNSPEC;
105        hints.ai_socktype = SOCK_STREAM;
106        hints.ai_flags = AI_PASSIVE;
107        hints.ai_protocol = 0;
108
109        sock = -1;
110        listenai = NULL;
111
112        if (getaddrinfo(FORMAT_DATA->listenaddr, FORMAT_DATA->listenport,
113                        &hints, &listenai) != 0) {
114                fprintf(stderr,
115                        "Call to getaddrinfo failed for %s:%s -- %s\n",
116                        FORMAT_DATA->listenaddr, FORMAT_DATA->listenport,
117                        strerror(errno));
118                goto listenerror;
119        }
120
121        sock = socket(listenai->ai_family, listenai->ai_socktype, 0);
122        if (sock < 0) {
123                fprintf(stderr, "Failed to create socket for %s:%s -- %s\n",
124                        FORMAT_DATA->listenaddr, FORMAT_DATA->listenport,
125                        strerror(errno));
126                goto listenerror;
127        }
128
129        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))
130                        < 0) {
131
132                fprintf(stderr, "Failed to configure socket for %s:%s -- %s\n",
133                        FORMAT_DATA->listenaddr, FORMAT_DATA->listenport,
134                        strerror(errno));
135
136                goto listenerror;
137        }
138
139        if (bind(sock, (struct sockaddr *)listenai->ai_addr,
140                        listenai->ai_addrlen) < 0) {
141
142                fprintf(stderr, "Failed to bind socket for %s:%s -- %s\n",
143                        FORMAT_DATA->listenaddr, FORMAT_DATA->listenport,
144                        strerror(errno));
145                goto listenerror;
146        }
147
148        if (listen(sock, 10) < 0) {
149                fprintf(stderr, "Failed to listen on socket for %s:%s -- %s\n",
150                        FORMAT_DATA->listenaddr, FORMAT_DATA->listenport,
151                        strerror(errno));
152                goto listenerror;
153        }
154
155        freeaddrinfo(listenai);
156
157        /* TODO consider possibility of pausing and resuming? */
158        while ((is_halted(libtrace) == -1)) {
159                newsend_message_t msg;
160                etsithread_t *et;
161
162                /* accept */
163                connected = (struct sockaddr_storage *)malloc(sizeof(struct
164                                sockaddr_storage));
165                addrsize = sizeof(struct sockaddr_storage);
166                consock = accept(sock, (struct sockaddr *)connected,
167                                &addrsize);
168                if (consock < 0) {
169                        fprintf(stderr, "Failed to accept connection on socket for %s:%s -- %s\n",
170                                FORMAT_DATA->listenaddr,
171                                FORMAT_DATA->listenport,
172                                strerror(errno));
173                        free(connected);
174                        goto listenerror;
175                }
176
177                /* if successful, send consock to next available thread */
178                msg.recvsock = consock;
179                msg.recvaddr = (struct sockaddr *)connected;
180                et = &(FORMAT_DATA->receivers[FORMAT_DATA->nextthreadid]);
181                libtrace_message_queue_put(&(et->mqueue), (void *)&msg);
182
183                if (libtrace->perpkt_thread_count > 0) {
184                        FORMAT_DATA->nextthreadid =
185                                ((FORMAT_DATA->nextthreadid + 1) %
186                                libtrace->perpkt_thread_count);
187                }
188        }
189
190        goto listenshutdown;
191
192listenerror:
193        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
194                "Unable to create listening socket for etsilive");
195
196listenshutdown:
197        if (sock >= 0) {
198                close(sock);
199        }
200        if (listenai) {
201                freeaddrinfo(listenai);
202        }
203        if (!is_halted(libtrace)) {
204                trace_interrupt();
205        }
206        pthread_exit(NULL);
207}
208
209
210
211static int etsilive_init_input(libtrace_t *libtrace) {
212        char *scan = NULL;
213        libtrace->format_data = (etsilive_format_data_t *)malloc(
214                        sizeof(etsilive_format_data_t));
215
216        if (!libtrace->format) {
217                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
218                        "format data inside etsilive_init_input()");
219                return 1;
220        }
221
222        FORMAT_DATA->receivers = NULL;
223        FORMAT_DATA->nextthreadid = 0;
224        FORMAT_DATA->listenaddr = NULL;
225
226        /* TODO is there a sensible default port number? */
227        scan = strchr(libtrace->uridata, ':');
228        if (scan == NULL) {
229                trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT,
230                        "Bad etsilive URI. Should be etsilive:<listenaddr>:<port number>");
231                return -1;
232        }
233        FORMAT_DATA->listenaddr = strndup(libtrace->uridata,
234                        (size_t)(scan - libtrace->uridata));
235        FORMAT_DATA->listenport = strdup(scan + 1);
236
237        FORMAT_DATA->shareddec = wandder_create_etsili_decoder();
238
239        return 0;
240}
241
242static int etsilive_fin_input(libtrace_t *libtrace) {
243        if (FORMAT_DATA->receivers) {
244                free(FORMAT_DATA->receivers);
245        }
246
247        if (FORMAT_DATA->listenaddr) {
248                free(FORMAT_DATA->listenaddr);
249        }
250        if (FORMAT_DATA->listenport) {
251                free(FORMAT_DATA->listenport);
252        }
253        if (FORMAT_DATA->shareddec) {
254                wandder_free_etsili_decoder(FORMAT_DATA->shareddec);
255        }
256        free(libtrace->format_data);
257        return 0;
258}
259
260static int etsilive_start_threads(libtrace_t *libtrace, uint32_t maxthreads) {
261        int ret;
262        uint32_t i;
263        /* Configure the set of receiver threads */
264
265        if (FORMAT_DATA->receivers == NULL) {
266                /* What if the number of threads changes between a pause and
267                 * a restart? Can this happen? */
268                FORMAT_DATA->receivers = (etsithread_t *)
269                                malloc(sizeof(etsithread_t) * maxthreads);
270        }
271
272        for (i = 0; i < maxthreads; i++) {
273
274                libtrace_message_queue_init(&(FORMAT_DATA->receivers[i].mqueue),
275                                sizeof(newsend_message_t));
276
277                FORMAT_DATA->receivers[i].sources = NULL;
278                FORMAT_DATA->receivers[i].sourcealloc = 0;
279                FORMAT_DATA->receivers[i].sourcecount = 0;
280                FORMAT_DATA->receivers[i].activesources = 0;
281                FORMAT_DATA->receivers[i].threadindex = i;
282                FORMAT_DATA->receivers[i].etsidec =
283                                wandder_create_etsili_decoder();
284
285        }
286
287        /* Start the listening thread */
288        /* TODO consider affinity of this thread? */
289
290        ret = pthread_create(&(FORMAT_DATA->listenthread), NULL,
291                        etsi_listener, libtrace);
292        if (ret != 0) {
293                return -1;
294        }
295        return maxthreads;
296}
297
298static int etsilive_start_input(libtrace_t *libtrace) {
299        return etsilive_start_threads(libtrace, 1);
300}
301
302static void halt_etsi_thread(etsithread_t *receiver) {
303        int i;
304        libtrace_message_queue_destroy(&(receiver->mqueue));
305        if (receiver->sources == NULL)
306                return;
307        for (i = 0; i < receiver->sourcecount; i++) {
308                etsisocket_t src = receiver->sources[i];
309                libtrace_scb_destroy(&(src.recvbuffer));
310                if (src.srcaddr) {
311                        free(src.srcaddr);
312                }
313                if (src.sock != -1) {
314                        close(src.sock);
315                }
316        }
317        wandder_free_etsili_decoder(receiver->etsidec);
318        free(receiver->sources);
319}
320
321static int etsilive_pause_input(libtrace_t *libtrace) {
322
323        int i;
324        for (i = 0; i < libtrace->perpkt_thread_count; i++) {
325                halt_etsi_thread(&(FORMAT_DATA->receivers[i]));
326        }
327        return 0;
328
329}
330
331static int receiver_read_message(etsithread_t *et) {
332        newsend_message_t msg;
333
334        while (libtrace_message_queue_try_get(&(et->mqueue), (void *)&msg)
335                        != LIBTRACE_MQ_FAILED) {
336                etsisocket_t *esock = NULL;
337                int i;
338
339                if (et->sourcecount == 0) {
340                        et->sources = (etsisocket_t *)malloc(
341                                        sizeof(etsisocket_t) * 10);
342                        et->sourcealloc = 10;
343
344                        for (i = 0; i < et->sourcealloc; i++) {
345                                et->sources[i].sock = -1;
346                                et->sources[i].srcaddr = NULL;
347                        }
348
349                        esock = &(et->sources[0]);
350                        et->sourcecount = 1;
351                } else {
352                        for (i = 0; i < et->sourcealloc; i++) {
353                                if (et->sources[i].sock == -1) {
354                                        esock = &(et->sources[i]);
355                                        break;
356                                }
357                        }
358                }
359
360                if (esock == NULL) {
361                        et->sources = (etsisocket_t *)realloc(et->sources,
362                                sizeof(etsisocket_t) * (et->sourcealloc + 10));
363
364                        for (i = et->sourcealloc; i < et->sourcealloc + 10;
365                                        i++) {
366                                et->sources[i].sock = -1;
367                                et->sources[i].srcaddr = NULL;
368                        }
369                        esock = &(et->sources[et->sourcealloc]);
370                        et->sourcealloc += 10;
371                        et->sourcecount += 1;
372
373                }
374
375                esock->sock = msg.recvsock;
376                esock->srcaddr = msg.recvaddr;
377                libtrace_scb_init(&(esock->recvbuffer), ETSI_RECVBUF_SIZE,
378                                et->threadindex);
379                esock->cached.timestamp = 0;
380                esock->cached.length = 0;
381
382                et->activesources += 1;
383
384                fprintf(stderr, "Thread %d is now handling %u sources.\n",
385                                et->threadindex, et->activesources);
386        }
387        return 1;
388}
389
390static void receive_from_single_socket(etsisocket_t *esock, etsithread_t *et) {
391
392        int ret = 0;
393
394        if (esock->sock == -1) {
395                return;
396        }
397
398        ret = libtrace_scb_recv_sock(&(esock->recvbuffer), esock->sock,
399                        MSG_DONTWAIT);
400        if (ret < 0) {
401                if (errno == EAGAIN || errno == EWOULDBLOCK) {
402                        /* Would have blocked, nothing available */
403                        return;
404                }
405                fprintf(stderr, "Error receiving on socket %d: %s\n",
406                                esock->sock, strerror(errno));
407                close(esock->sock);
408                esock->sock = -1;
409                et->activesources -= 1;
410        }
411
412        if (ret == 0) {
413                fprintf(stderr, "Socket %d has disconnected\n", esock->sock);
414                close(esock->sock);
415                esock->sock = -1;
416                et->activesources -= 1;
417        }
418
419}
420
421static int receive_etsi_sockets(libtrace_t *libtrace, etsithread_t *et) {
422
423        int iserr = 0;
424        int i;
425
426        if ((iserr = is_halted(libtrace)) != -1) {
427                return iserr;
428        }
429
430        iserr = receiver_read_message(et);
431        if (iserr <= 0) {
432                return iserr;
433        }
434
435        if (et->activesources == 0) {
436                return 1;
437        }
438
439        for (i = 0; i < et->sourcecount; i++) {
440                receive_from_single_socket(&(et->sources[i]), et);
441        }
442        return 1;
443
444}
445
446static inline void inspect_next_packet(etsisocket_t *sock,
447                etsisocket_t **earliestsock, uint64_t *earliesttime,
448                wandder_etsispec_t *dec, etsithread_t *et) {
449
450
451        struct timeval tv;
452        uint32_t available;
453        uint8_t *ptr = NULL;
454        uint32_t reclen = 0;
455        uint64_t current;
456
457        if (sock->sock == -1) {
458                return;
459        }
460        /* Have we already successfully decoded this? Cool,
461         * just use whatever we cached last time.
462         */
463        if (sock->cached.timestamp != 0) {
464                current = sock->cached.timestamp;
465
466                if (*earliesttime == 0 || *earliesttime > current) {
467                        *earliesttime = current;
468                        *earliestsock = sock;
469                }
470                return;
471        }
472
473        ptr = libtrace_scb_get_read(&(sock->recvbuffer), &available);
474
475        if (available == 0 || ptr == NULL) {
476                return;
477        }
478
479        wandder_attach_etsili_buffer(dec, ptr, available, false);
480        if (sock->cached.length != 0) {
481                reclen = sock->cached.length;
482        } else {
483                reclen = wandder_etsili_get_pdu_length(dec);
484
485                if (reclen == 0) {
486                        return;
487                }
488        }
489
490        if (available < reclen) {
491                /* Don't have the whole PDU yet */
492                return;
493        }
494
495        if (wandder_etsili_is_keepalive(dec)) {
496                int64_t kaseq = wandder_etsili_get_sequence_number(dec);
497                if (kaseq < 0) {
498                        fprintf(stderr, "bogus sequence number in ETSILI keep alive.\n");
499                        close(sock->sock);
500                        sock->sock = -1;
501                        et->activesources -= 1;
502                        return;
503                }
504                /* Send keep alive response */
505                if (send_etsili_keepalive_response(sock->sock, kaseq) < 0) {
506                        fprintf(stderr, "error sending response to ETSILI keep alive: %s.\n", strerror(errno));
507                        close(sock->sock);
508                        sock->sock = -1;
509                        et->activesources -= 1;
510                        return;
511                }
512                /* Skip past KA */
513                libtrace_scb_advance_read(&(sock->recvbuffer), reclen);
514                return;
515        }
516
517        /* Get the timestamp */
518
519        tv = wandder_etsili_get_header_timestamp(dec);
520        if (tv.tv_sec == 0) {
521                return;
522        }
523        current = ((((uint64_t)tv.tv_sec) << 32) +
524                        (((uint64_t)tv.tv_usec << 32)/1000000)); 
525
526        /* Success, cache everything we used so we don't have to
527         * decode this packet again.
528         */
529        sock->cached.timestamp = current;
530        sock->cached.length = reclen;
531
532
533        /* Don't forget to update earliest and esock... */
534        if (current < *earliesttime || *earliesttime == 0) {
535                *earliestsock = sock;
536                *earliesttime = current;
537        }
538}
539
540static etsisocket_t *select_next_packet(etsithread_t *et) {
541
542        int i;
543        etsisocket_t *esock = NULL;
544        uint64_t earliest = 0;
545
546        for (i = 0; i < et->sourcecount; i++) {
547                inspect_next_packet(&(et->sources[i]), &esock, &earliest,
548                        et->etsidec, et);
549        }
550        return esock;
551}
552
553static int etsilive_prepare_received(libtrace_t *libtrace,
554                etsithread_t *et UNUSED,
555                etsisocket_t *esock, libtrace_packet_t *packet) {
556
557        uint32_t available = 0;
558
559        packet->trace = libtrace;
560        packet->buffer = libtrace_scb_get_read(&(esock->recvbuffer),
561                                        &available);
562        packet->buf_control = TRACE_CTRL_EXTERNAL;
563        packet->header = NULL;          // Check this is ok to do
564        packet->payload = packet->buffer;
565        packet->type = TRACE_RT_DATA_ETSILI;
566        packet->order = esock->cached.timestamp;
567        packet->error = esock->cached.length;
568
569        packet->cached.wire_length = esock->cached.length;
570        packet->cached.capture_length = esock->cached.length;
571
572        /* Advance the read pointer for this buffer
573         * TODO should really do this in fin_packet, but will need a ref
574         * to esock to do this properly */
575        libtrace_scb_advance_read(&(esock->recvbuffer), esock->cached.length);
576        esock->cached.length = 0;
577        esock->cached.timestamp = 0;
578
579
580        return 1;
581}
582
583
584static int etsilive_read_packet(libtrace_t *libtrace,
585                libtrace_packet_t *packet) {
586
587        etsisocket_t *nextavail = NULL;
588        int ret;
589
590        while (1) {
591                /* Read from sockets for any buffers that do not have
592                 * a complete packet */
593                ret = receive_etsi_sockets(libtrace,
594                                &(FORMAT_DATA->receivers[0]));
595                if (ret <= 0) {
596                        return ret;
597                }
598
599                nextavail = select_next_packet(&(FORMAT_DATA->receivers[0]));
600                if (nextavail == NULL) {
601                        /* No complete packets available, take a short
602                         * break before trying again. */
603                        if (FORMAT_DATA->receivers[0].sourcecount == 0) {
604                                /* No sources yet, so we can wait a bit
605                                 * longer. */
606                                usleep(10000);
607                        } else {
608                                usleep(100);
609                        }
610                        continue;
611                }
612                break;
613        }
614
615        return etsilive_prepare_received(libtrace,
616                        &(FORMAT_DATA->receivers[0]), nextavail,
617                        packet);
618}
619
620static int etsilive_prepare_packet(libtrace_t *libtrace UNUSED,
621                libtrace_packet_t *packet UNUSED,
622                void *buffer UNUSED, libtrace_rt_types_t rt_type UNUSED,
623                uint32_t flags UNUSED) {
624        return 0;
625}
626
627static int etsilive_get_pdu_length(const libtrace_packet_t *packet) {
628
629        /* Should never get here because cache is set when packet is read */
630        size_t reclen;
631        libtrace_t *libtrace = packet->trace;
632
633        if (!libtrace) {
634                fprintf(stderr, "Packet is not associated with a trace in etsilive_get_pdu_length()\n");
635                return TRACE_ERR_NULL_TRACE;
636        }
637        if (!FORMAT_DATA->shareddec) {
638                trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT, "Etsilive format data shareddec is NULL in etsilive_get_pdu_length()\n");
639                return -1;
640        }
641
642        /* 0 should be ok here for quickly evaluating the first length
643         * field... */
644        wandder_attach_etsili_buffer(FORMAT_DATA->shareddec, packet->buffer,
645                        0, false);
646        reclen = (size_t)wandder_etsili_get_pdu_length(
647                        FORMAT_DATA->shareddec);
648
649        return reclen;
650}
651
652static int etsilive_get_framing_length(const libtrace_packet_t *packet UNUSED) {
653
654        return 0;
655}
656
657static uint64_t etsilive_get_erf_timestamp(const libtrace_packet_t *packet) {
658        return packet->order;
659}
660
661static libtrace_linktype_t etsilive_get_link_type(
662                const libtrace_packet_t *packet UNUSED) {
663        return TRACE_TYPE_ETSILI;
664}
665
666static struct libtrace_format_t etsilive = {
667        "etsilive",
668        "$Id$",
669        TRACE_FORMAT_ETSILIVE,
670        NULL,                           /* probe filename */
671        NULL,                           /* probe magic */
672        etsilive_init_input,            /* init_input */
673        NULL,                           /* config_input */
674        etsilive_start_input,           /* start_input */
675        etsilive_pause_input,           /* pause */
676        NULL,                           /* init_output */
677        NULL,                           /* config_output */
678        NULL,                           /* start_output */
679        etsilive_fin_input,             /* fin_input */
680        NULL,                           /* fin_output */
681        etsilive_read_packet,           /* read_packet */
682        etsilive_prepare_packet,        /* prepare_packet */
683        NULL,                           /* fin_packet */
684        NULL,                           /* write_packet */
685        NULL,                           /* flush_output */
686        etsilive_get_link_type,         /* get_link_type */
687        NULL,                           /* get_direction */
688        NULL,                           /* set_direction */
689        etsilive_get_erf_timestamp,     /* get_erf_timestamp */
690        NULL,                           /* get_timeval */
691        NULL,                           /* get_timespec */
692        NULL,                           /* get_seconds */
693        NULL,                           /* seek_erf */
694        NULL,                           /* seek_timeval */
695        NULL,                           /* seek_seconds */
696        etsilive_get_pdu_length,       /* get_capture_length */
697        etsilive_get_pdu_length,       /* get_wire_length */
698        etsilive_get_framing_length,    /* get_framing_length */
699        NULL,                           /* set_capture_length */
700        NULL,                           /* get_received_packets */
701        NULL,                           /* get_filtered_packets */
702        NULL,                           /* get_dropped_packets */
703        NULL,                           /* get_statistics */
704        NULL,                           /* get_fd */
705        NULL, //trace_event_etsilive,           /* trace_event */
706        NULL,                           /* help */
707        NULL,                           /* next pointer */
708        NON_PARALLEL(true)              /* TODO this can be parallel */
709};
710
711
712void etsilive_constructor(void) {
713        register_format(&etsilive);
714}
715
716
717#define ENC_USEQUENCE(enc) wandder_encode_next(enc, WANDDER_TAG_SEQUENCE, \
718        WANDDER_CLASS_UNIVERSAL_CONSTRUCT, WANDDER_TAG_SEQUENCE, NULL, 0)
719
720#define ENC_CSEQUENCE(enc, x) wandder_encode_next(enc, WANDDER_TAG_SEQUENCE, \
721        WANDDER_CLASS_CONTEXT_CONSTRUCT, x, NULL, 0)
722
723#define LT_ETSI_LIID "none"
724#define LT_ETSI_NA "NA"
725#define LT_ETSI_OPERATOR "libtrace"
726
727static int send_etsili_keepalive_response(int fd, int64_t seqno) {
728
729        wandder_encoder_t *encoder;
730        wandder_encoded_result_t *tosend;
731        int ret = 0;
732        uint64_t zero = 0;
733        struct timeval tv;
734
735        encoder = init_wandder_encoder();
736
737        ENC_USEQUENCE(encoder);             // starts outermost sequence
738
739        ENC_CSEQUENCE(encoder, 1);
740        wandder_encode_next(encoder, WANDDER_TAG_OID,
741                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 0,
742                        (void *)(WANDDER_ETSILI_PSDOMAINID),
743                        sizeof(WANDDER_ETSILI_PSDOMAINID));
744        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
745                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, LT_ETSI_LIID,
746                        strlen(LT_ETSI_LIID));
747        wandder_encode_next(encoder, WANDDER_TAG_PRINTABLE,
748                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, LT_ETSI_NA,
749                        strlen(LT_ETSI_NA));
750
751        ENC_CSEQUENCE(encoder, 3);
752
753        ENC_CSEQUENCE(encoder, 0);
754        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
755                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 0, LT_ETSI_OPERATOR,
756                        strlen(LT_ETSI_OPERATOR));
757
758        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
759                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, LT_ETSI_OPERATOR,
760                        strlen(LT_ETSI_OPERATOR));
761        wandder_encode_endseq(encoder);
762
763        wandder_encode_next(encoder, WANDDER_TAG_INTEGER,
764                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, &(zero),
765                        sizeof(zero));
766        wandder_encode_next(encoder, WANDDER_TAG_PRINTABLE,
767                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, LT_ETSI_NA,
768                        strlen(LT_ETSI_NA));
769        wandder_encode_endseq(encoder);
770
771        wandder_encode_next(encoder, WANDDER_TAG_INTEGER,
772                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 4, &(seqno),
773                        sizeof(seqno));
774
775        gettimeofday(&tv, NULL);
776        wandder_encode_next(encoder, WANDDER_TAG_GENERALTIME,
777                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 5, &tv,
778                        sizeof(struct timeval));
779
780        wandder_encode_endseq(encoder);
781
782        ENC_CSEQUENCE(encoder, 2);          // Payload
783        ENC_CSEQUENCE(encoder, 2);          // TRIPayload
784        wandder_encode_next(encoder, WANDDER_TAG_NULL,
785                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 4, NULL, 0);
786        wandder_encode_endseq(encoder);     // End TRIPayload
787        wandder_encode_endseq(encoder);     // End Payload
788        wandder_encode_endseq(encoder);     // End Outermost Sequence
789
790        tosend = wandder_encode_finish(encoder);
791
792        if (tosend != NULL) {
793                /* Will block, but hopefully we shouldn't be doing much
794                 * sending.
795                 */
796                ret = send(fd, tosend->encoded, tosend->len, 0);
797        }
798
799        wandder_release_encoded_result(encoder, tosend);
800        free_wandder_encoder(encoder);
801        return ret;
802}
803
804
Note: See TracBrowser for help on using the repository browser.