source: lib/format_etsilive.c @ 5cdb37d

develop
Last change on this file since 5cdb37d was 5cdb37d, checked in by GitHub <noreply@…>, 2 years ago

Merge pull request #101 from jacobvw/meta-api

Meta API

  • Property mode set to 100644
File size: 27.2 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,                           /* get_meta_section */
694        NULL,                           /* seek_erf */
695        NULL,                           /* seek_timeval */
696        NULL,                           /* seek_seconds */
697        etsilive_get_pdu_length,       /* get_capture_length */
698        etsilive_get_pdu_length,       /* get_wire_length */
699        etsilive_get_framing_length,    /* get_framing_length */
700        NULL,                           /* set_capture_length */
701        NULL,                           /* get_received_packets */
702        NULL,                           /* get_filtered_packets */
703        NULL,                           /* get_dropped_packets */
704        NULL,                           /* get_statistics */
705        NULL,                           /* get_fd */
706        NULL, //trace_event_etsilive,           /* trace_event */
707        NULL,                           /* help */
708        NULL,                           /* next pointer */
709        NON_PARALLEL(true)              /* TODO this can be parallel */
710};
711
712
713void etsilive_constructor(void) {
714        register_format(&etsilive);
715}
716
717
718#define ENC_USEQUENCE(enc) wandder_encode_next(enc, WANDDER_TAG_SEQUENCE, \
719        WANDDER_CLASS_UNIVERSAL_CONSTRUCT, WANDDER_TAG_SEQUENCE, NULL, 0)
720
721#define ENC_CSEQUENCE(enc, x) wandder_encode_next(enc, WANDDER_TAG_SEQUENCE, \
722        WANDDER_CLASS_CONTEXT_CONSTRUCT, x, NULL, 0)
723
724#define LT_ETSI_LIID "none"
725#define LT_ETSI_NA "NA"
726#define LT_ETSI_OPERATOR "libtrace"
727
728static int send_etsili_keepalive_response(int fd, int64_t seqno) {
729
730        wandder_encoder_t *encoder;
731        wandder_encoded_result_t *tosend;
732        int ret = 0;
733        uint64_t zero = 0;
734        struct timeval tv;
735
736        encoder = init_wandder_encoder();
737
738        ENC_USEQUENCE(encoder);             // starts outermost sequence
739
740        ENC_CSEQUENCE(encoder, 1);
741        wandder_encode_next(encoder, WANDDER_TAG_OID,
742                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 0,
743                        (void *)(WANDDER_ETSILI_PSDOMAINID),
744                        sizeof(WANDDER_ETSILI_PSDOMAINID));
745        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
746                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, LT_ETSI_LIID,
747                        strlen(LT_ETSI_LIID));
748        wandder_encode_next(encoder, WANDDER_TAG_PRINTABLE,
749                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, LT_ETSI_NA,
750                        strlen(LT_ETSI_NA));
751
752        ENC_CSEQUENCE(encoder, 3);
753
754        ENC_CSEQUENCE(encoder, 0);
755        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
756                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 0, LT_ETSI_OPERATOR,
757                        strlen(LT_ETSI_OPERATOR));
758
759        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
760                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, LT_ETSI_OPERATOR,
761                        strlen(LT_ETSI_OPERATOR));
762        wandder_encode_endseq(encoder);
763
764        wandder_encode_next(encoder, WANDDER_TAG_INTEGER,
765                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, &(zero),
766                        sizeof(zero));
767        wandder_encode_next(encoder, WANDDER_TAG_PRINTABLE,
768                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, LT_ETSI_NA,
769                        strlen(LT_ETSI_NA));
770        wandder_encode_endseq(encoder);
771
772        wandder_encode_next(encoder, WANDDER_TAG_INTEGER,
773                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 4, &(seqno),
774                        sizeof(seqno));
775
776        gettimeofday(&tv, NULL);
777        wandder_encode_next(encoder, WANDDER_TAG_GENERALTIME,
778                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 5, &tv,
779                        sizeof(struct timeval));
780
781        wandder_encode_endseq(encoder);
782
783        ENC_CSEQUENCE(encoder, 2);          // Payload
784        ENC_CSEQUENCE(encoder, 2);          // TRIPayload
785        wandder_encode_next(encoder, WANDDER_TAG_NULL,
786                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 4, NULL, 0);
787        wandder_encode_endseq(encoder);     // End TRIPayload
788        wandder_encode_endseq(encoder);     // End Payload
789        wandder_encode_endseq(encoder);     // End Outermost Sequence
790
791        tosend = wandder_encode_finish(encoder);
792
793        if (tosend != NULL) {
794                /* Will block, but hopefully we shouldn't be doing much
795                 * sending.
796                 */
797                ret = send(fd, tosend->encoded, tosend->len, 0);
798        }
799
800        wandder_release_encoded_result(encoder, tosend);
801        free_wandder_encoder(encoder);
802        return ret;
803}
804
805
Note: See TracBrowser for help on using the repository browser.