source: lib/format_etsilive.c @ 2044185

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

Remove unused code from format_etsilive.

  • Property mode set to 100644
File size: 25.3 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        /* Advance the read pointer for this buffer
532         * TODO should really do this in fin_packet, but will need a ref
533         * to esock to do this properly */
534        libtrace_scb_advance_read(&(esock->recvbuffer), esock->cached.length);
535        esock->cached.length = 0;
536        esock->cached.timestamp = 0;
537
538
539        return 1;
540}
541
542
543static int etsilive_read_packet(libtrace_t *libtrace,
544                libtrace_packet_t *packet) {
545
546        etsisocket_t *nextavail = NULL;
547        int ret;
548
549        while (1) {
550                /* Read from sockets for any buffers that do not have
551                 * a complete packet */
552                ret = receive_etsi_sockets(libtrace,
553                                &(FORMAT_DATA->receivers[0]));
554                if (ret <= 0) {
555                        return ret;
556                }
557
558                nextavail = select_next_packet(&(FORMAT_DATA->receivers[0]));
559                if (nextavail == NULL) {
560                        /* No complete packets available, take a short
561                         * break before trying again. */
562                        if (FORMAT_DATA->receivers[0].sourcecount == 0) {
563                                /* No sources yet, so we can wait a bit
564                                 * longer. */
565                                usleep(10000);
566                        } else {
567                                usleep(100);
568                        }
569                        continue;
570                }
571                break;
572        }
573
574        return etsilive_prepare_received(libtrace,
575                        &(FORMAT_DATA->receivers[0]), nextavail,
576                        packet);
577}
578
579static int etsilive_prepare_packet(libtrace_t *libtrace UNUSED,
580                libtrace_packet_t *packet UNUSED,
581                void *buffer UNUSED, libtrace_rt_types_t rt_type UNUSED,
582                uint32_t flags UNUSED) {
583        return 0;
584}
585
586static int etsilive_get_pdu_length(const libtrace_packet_t *packet) {
587
588        /* Should never get here because cache is set when packet is read */
589        size_t reclen;
590        libtrace_t *libtrace = packet->trace;
591
592        assert(libtrace);
593        assert(FORMAT_DATA->shareddec);
594
595        /* 0 should be ok here for quickly evaluating the first length
596         * field... */
597        wandder_attach_etsili_buffer(FORMAT_DATA->shareddec, packet->buffer,
598                        0, false);
599        reclen = (size_t)wandder_etsili_get_pdu_length(
600                        FORMAT_DATA->shareddec);
601
602        return reclen;
603}
604
605static int etsilive_get_framing_length(const libtrace_packet_t *packet UNUSED) {
606
607        return 0;
608}
609
610static uint64_t etsilive_get_erf_timestamp(const libtrace_packet_t *packet) {
611        return packet->order;
612}
613
614static libtrace_linktype_t etsilive_get_link_type(
615                const libtrace_packet_t *packet UNUSED) {
616        return TRACE_TYPE_ETSILI;
617}
618
619static struct libtrace_format_t etsilive = {
620        "etsilive",
621        "$Id$",
622        TRACE_FORMAT_ETSILIVE,
623        NULL,                           /* probe filename */
624        NULL,                           /* probe magic */
625        etsilive_init_input,            /* init_input */
626        NULL,                           /* config_input */
627        etsilive_start_input,           /* start_input */
628        etsilive_pause_input,           /* pause */
629        NULL,                           /* init_output */
630        NULL,                           /* config_output */
631        NULL,                           /* start_output */
632        etsilive_fin_input,             /* fin_input */
633        NULL,                           /* fin_output */
634        etsilive_read_packet,           /* read_packet */
635        etsilive_prepare_packet,        /* prepare_packet */
636        NULL,                           /* fin_packet */
637        NULL,                           /* write_packet */
638        NULL,                           /* flush_output */
639        etsilive_get_link_type,         /* get_link_type */
640        NULL,                           /* get_direction */
641        NULL,                           /* set_direction */
642        etsilive_get_erf_timestamp,     /* get_erf_timestamp */
643        NULL,                           /* get_timeval */
644        NULL,                           /* get_timespec */
645        NULL,                           /* get_seconds */
646        NULL,                           /* seek_erf */
647        NULL,                           /* seek_timeval */
648        NULL,                           /* seek_seconds */
649        etsilive_get_pdu_length,       /* get_capture_length */
650        etsilive_get_pdu_length,       /* get_wire_length */
651        etsilive_get_framing_length,    /* get_framing_length */
652        NULL,                           /* set_capture_length */
653        NULL,                           /* get_received_packets */
654        NULL,                           /* get_filtered_packets */
655        NULL,                           /* get_dropped_packets */
656        NULL,                           /* get_statistics */
657        NULL,                           /* get_fd */
658        NULL, //trace_event_etsilive,           /* trace_event */
659        NULL,                           /* help */
660        NULL,                           /* next pointer */
661        NON_PARALLEL(true)              /* TODO this can be parallel */
662};
663
664
665void etsilive_constructor(void) {
666        register_format(&etsilive);
667}
668
669
670#define ENC_USEQUENCE(enc) wandder_encode_next(enc, WANDDER_TAG_SEQUENCE, \
671        WANDDER_CLASS_UNIVERSAL_CONSTRUCT, WANDDER_TAG_SEQUENCE, NULL, 0)
672
673#define ENC_CSEQUENCE(enc, x) wandder_encode_next(enc, WANDDER_TAG_SEQUENCE, \
674        WANDDER_CLASS_CONTEXT_CONSTRUCT, x, NULL, 0)
675
676#define LT_ETSI_LIID "none"
677#define LT_ETSI_NA "NA"
678#define LT_ETSI_OPERATOR "libtrace"
679
680static int send_etsili_keepalive_response(int fd, int64_t seqno) {
681
682        wandder_encoder_t *encoder;
683        wandder_encoded_result_t *tosend;
684        int ret = 0;
685        uint64_t zero = 0;
686        struct timeval tv;
687
688        encoder = init_wandder_encoder();
689
690        ENC_USEQUENCE(encoder);             // starts outermost sequence
691
692        ENC_CSEQUENCE(encoder, 1);
693        wandder_encode_next(encoder, WANDDER_TAG_OID,
694                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 0,
695                        (void *)(WANDDER_ETSILI_PSDOMAINID),
696                        sizeof(WANDDER_ETSILI_PSDOMAINID));
697        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
698                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, LT_ETSI_LIID,
699                        strlen(LT_ETSI_LIID));
700        wandder_encode_next(encoder, WANDDER_TAG_PRINTABLE,
701                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, LT_ETSI_NA,
702                        strlen(LT_ETSI_NA));
703
704        ENC_CSEQUENCE(encoder, 3);
705
706        ENC_CSEQUENCE(encoder, 0);
707        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
708                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 0, LT_ETSI_OPERATOR,
709                        strlen(LT_ETSI_OPERATOR));
710
711        wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING,
712                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, LT_ETSI_OPERATOR,
713                        strlen(LT_ETSI_OPERATOR));
714        wandder_encode_endseq(encoder);
715
716        wandder_encode_next(encoder, WANDDER_TAG_INTEGER,
717                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, &(zero),
718                        sizeof(zero));
719        wandder_encode_next(encoder, WANDDER_TAG_PRINTABLE,
720                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, LT_ETSI_NA,
721                        strlen(LT_ETSI_NA));
722        wandder_encode_endseq(encoder);
723
724        wandder_encode_next(encoder, WANDDER_TAG_INTEGER,
725                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 4, &(seqno),
726                        sizeof(seqno));
727
728        gettimeofday(&tv, NULL);
729        wandder_encode_next(encoder, WANDDER_TAG_GENERALTIME,
730                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 5, &tv,
731                        sizeof(struct timeval));
732
733        wandder_encode_endseq(encoder);
734
735        ENC_CSEQUENCE(encoder, 2);          // Payload
736        ENC_CSEQUENCE(encoder, 2);          // TRIPayload
737        wandder_encode_next(encoder, WANDDER_TAG_NULL,
738                        WANDDER_CLASS_CONTEXT_PRIMITIVE, 4, NULL, 0);
739        wandder_encode_endseq(encoder);     // End TRIPayload
740        wandder_encode_endseq(encoder);     // End Payload
741        wandder_encode_endseq(encoder);     // End Outermost Sequence
742
743        tosend = wandder_encode_finish(encoder);
744
745        if (tosend != NULL) {
746                /* Will block, but hopefully we shouldn't be doing much
747                 * sending.
748                 */
749                ret = send(fd, tosend->encoded, tosend->len, 0);
750        }
751
752        wandder_release_encoded_result(encoder, tosend);
753        free_wandder_encoder(encoder);
754        return ret;
755}
756
757
Note: See TracBrowser for help on using the repository browser.