source: lib/format_etsilive.c @ f27e335

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

Don't decode the ETSI timestamp repeatedly.

In fact, we already decode the timestamp when we read the packet
and store it in ERF timestamp format within the "order" field.
Next time someone wants the packet's timestamp, just return that
ERF timestamp and everything will be nice and quick.

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