source: lib/format_etsilive.c @ 32ee9b2

cachetimestampsdeveloprc-4.0.4ringdecrementfixringperformance
Last change on this file since 32ee9b2 was 32ee9b2, checked in by Shane Alcock <salcock@…>, 2 years ago

Add new trace_flush_output() to public API

Can be used to force a libtrace output to dump any buffered output
to disk immediately.

Note that if the file is compressed or the output trace format
requires a trailer, the flushed file will still not be properly
readable afterwards as this will not result in any trailers
being written. You'll still have to close the file for that.

Mainly this is useful for ensuring that output file sizes grow
over time in situations where the amount of output is relatively
small, rather than staying stuck at 0 bytes until we either reach
1MB of output or the file is closed. For instance, you could have
a timer that calls trace_flush_output() every 30 seconds so that
the output file size will grow if any packets were written in the
last 30 seconds.

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