source: lib/format_etsilive.c @ 5577521

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

Fix out-of-date libwandder API usage when sending ETSI keepalive.

Also fixed a bunch of unused parameter warnings.

  • 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} 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        etsilive_get_link_type,         /* get_link_type */
651        NULL,                           /* get_direction */
652        NULL,                           /* set_direction */
653        NULL,                           /* get_erf_timestamp */
654        etsilive_get_timeval,           /* get_timeval */
655        NULL,                           /* get_timespec */
656        NULL,                           /* get_seconds */
657        NULL,                           /* seek_erf */
658        NULL,                           /* seek_timeval */
659        NULL,                           /* seek_seconds */
660        etsilive_get_pdu_length,       /* get_capture_length */
661        etsilive_get_pdu_length,       /* get_wire_length */
662        etsilive_get_framing_length,    /* get_framing_length */
663        NULL,                           /* set_capture_length */
664        NULL,                           /* get_received_packets */
665        NULL,                           /* get_filtered_packets */
666        NULL,                           /* get_dropped_packets */
667        NULL,                           /* get_statistics */
668        NULL,                           /* get_fd */
669        NULL, //trace_event_etsilive,           /* trace_event */
670        NULL,                           /* help */
671        NULL,                           /* next pointer */
672        NON_PARALLEL(true)              /* TODO this can be parallel */
673};
674
675
676void etsilive_constructor(void) {
677        register_format(&etsilive);
678}
679
680
681#define ENC_USEQUENCE(enc) wandder_encode_next(enc, WANDDER_TAG_SEQUENCE, \
682        WANDDER_CLASS_UNIVERSAL_CONSTRUCT, WANDDER_TAG_SEQUENCE, NULL, 0)
683
684#define ENC_CSEQUENCE(enc, x) wandder_encode_next(enc, WANDDER_TAG_SEQUENCE, \
685        WANDDER_CLASS_CONTEXT_CONSTRUCT, x, NULL, 0)
686
687#define LT_ETSI_LIID "none"
688#define LT_ETSI_NA "NA"
689#define LT_ETSI_OPERATOR "libtrace"
690
691static int send_etsili_keepalive_response(int fd, int64_t seqno) {
692
693        wandder_encoder_t *encoder;
694        wandder_encoded_result_t *tosend;
695        int ret = 0;
696        uint64_t zero = 0;
697        struct timeval tv;
698
699        encoder = init_wandder_encoder();
700
701        ENC_USEQUENCE(encoder);             // starts outermost sequence
702
703        ENC_CSEQUENCE(encoder, 1);
704        wandder_encode_next(encoder, WANDDER_TAG_OID,
705                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 0,
706                        (void *)(WANDDER_ETSILI_PSDOMAINID),
707                        sizeof(WANDDER_ETSILI_PSDOMAINID));
708        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
709                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, LT_ETSI_LIID,
710                        strlen(LT_ETSI_LIID));
711        wandder_encode_next(encoder, WANDDER_TAG_PRINTABLE,
712                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, LT_ETSI_NA,
713                        strlen(LT_ETSI_NA));
714
715        ENC_CSEQUENCE(encoder, 3);
716
717        ENC_CSEQUENCE(encoder, 0);
718        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
719                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 0, LT_ETSI_OPERATOR,
720                        strlen(LT_ETSI_OPERATOR));
721
722        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
723                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, LT_ETSI_OPERATOR,
724                        strlen(LT_ETSI_OPERATOR));
725        wandder_encode_endseq(encoder);
726
727        wandder_encode_next(encoder, WANDDER_TAG_INTEGER,
728                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, &(zero),
729                        sizeof(zero));
730        wandder_encode_next(encoder, WANDDER_TAG_PRINTABLE,
731                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, LT_ETSI_NA,
732                        strlen(LT_ETSI_NA));
733        wandder_encode_endseq(encoder);
734
735        wandder_encode_next(encoder, WANDDER_TAG_INTEGER,
736                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 4, &(seqno),
737                        sizeof(seqno));
738
739        gettimeofday(&tv, NULL);
740        wandder_encode_next(encoder, WANDDER_TAG_GENERALTIME,
741                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 5, &tv,
742                        sizeof(struct timeval));
743
744        wandder_encode_endseq(encoder);
745
746        ENC_CSEQUENCE(encoder, 2);          // Payload
747        ENC_CSEQUENCE(encoder, 2);          // TRIPayload
748        wandder_encode_next(encoder, WANDDER_TAG_NULL,
749                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 4, NULL, 0);
750        wandder_encode_endseq(encoder);     // End TRIPayload
751        wandder_encode_endseq(encoder);     // End Payload
752        wandder_encode_endseq(encoder);     // End Outermost Sequence
753
754        tosend = wandder_encode_finish(encoder);
755
756        if (tosend != NULL) {
757                /* Will block, but hopefully we shouldn't be doing much
758                 * sending.
759                 */
760                ret = send(fd, tosend->encoded, tosend->len, 0);
761        }
762
763        wandder_release_encoded_result(encoder, tosend);
764        free_wandder_encoder(encoder);
765        return ret;
766}
767
768
Note: See TracBrowser for help on using the repository browser.