source: lib/format_etsilive.c @ 2725318

develop
Last change on this file since 2725318 was 2725318, checked in by Jacob Van Walraven <jcv9@…>, 2 years ago

Cleanup some of the assertions

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