source: lib/format_etsilive.c @ 2193905

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

Apply changes required for pull request #81

  • Property mode set to 100644
File size: 25.6 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2017 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26
27#define _GNU_SOURCE
28
29#include "config.h"
30#include "common.h"
31#include "libtrace.h"
32#include "libtrace_int.h"
33#include "format_helper.h"
34#include "data-struct/simple_circular_buffer.h"
35
36#include <libwandder.h>
37#include <libwandder_etsili.h>
38
39#include <errno.h>
40#include <fcntl.h>
41#include <stdio.h>
42#include <string.h>
43#include <stdlib.h>
44#include <unistd.h>
45#include <sys/socket.h>
46#include <sys/types.h>
47#include <netdb.h>
48
49#define ETSI_RECVBUF_SIZE (64 * 1024 * 1024)
50
51#define FORMAT_DATA ((etsilive_format_data_t *)libtrace->format_data)
52
53typedef struct etsipktcache {
54
55        uint64_t timestamp;
56        uint16_t length;
57
58} etsi_packet_cache_t;
59
60typedef struct etsisocket {
61        int sock;
62        struct sockaddr *srcaddr;
63
64        libtrace_scb_t recvbuffer;
65        etsi_packet_cache_t cached;
66
67} etsisocket_t;
68
69typedef struct etsithread {
70        libtrace_message_queue_t mqueue;
71        etsisocket_t *sources;
72        uint16_t sourcecount;
73        int threadindex;
74        wandder_etsispec_t *etsidec;
75} etsithread_t;
76
77typedef struct etsilive_format_data {
78        char *listenport;
79        char *listenaddr;
80
81        pthread_t listenthread;
82        etsithread_t *receivers;
83        int nextthreadid;
84        wandder_etsispec_t *shareddec;
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        if (!libtrace->format) {
215                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
216                        "format data inside 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        if (!libtrace) {
598                fprintf(stderr, "Packet is not associated with a trace in etsilive_get_pdu_length()\n");
599                return TRACE_ERR_NULL_TRACE;
600        }
601        if (!FORMAT_DATA->shareddec) {
602                trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT, "Etsilive format data shareddec is NULL in etsilive_get_pdu_length()\n");
603                return -1;
604        }
605
606        /* 0 should be ok here for quickly evaluating the first length
607         * field... */
608        wandder_attach_etsili_buffer(FORMAT_DATA->shareddec, packet->buffer,
609                        0, false);
610        reclen = (size_t)wandder_etsili_get_pdu_length(
611                        FORMAT_DATA->shareddec);
612
613        return reclen;
614}
615
616static int etsilive_get_framing_length(const libtrace_packet_t *packet UNUSED) {
617
618        return 0;
619}
620
621static uint64_t etsilive_get_erf_timestamp(const libtrace_packet_t *packet) {
622        return packet->order;
623}
624
625static libtrace_linktype_t etsilive_get_link_type(
626                const libtrace_packet_t *packet UNUSED) {
627        return TRACE_TYPE_ETSILI;
628}
629
630static struct libtrace_format_t etsilive = {
631        "etsilive",
632        "$Id$",
633        TRACE_FORMAT_ETSILIVE,
634        NULL,                           /* probe filename */
635        NULL,                           /* probe magic */
636        etsilive_init_input,            /* init_input */
637        NULL,                           /* config_input */
638        etsilive_start_input,           /* start_input */
639        etsilive_pause_input,           /* pause */
640        NULL,                           /* init_output */
641        NULL,                           /* config_output */
642        NULL,                           /* start_output */
643        etsilive_fin_input,             /* fin_input */
644        NULL,                           /* fin_output */
645        etsilive_read_packet,           /* read_packet */
646        etsilive_prepare_packet,        /* prepare_packet */
647        NULL,                           /* fin_packet */
648        NULL,                           /* write_packet */
649        NULL,                           /* flush_output */
650        etsilive_get_link_type,         /* get_link_type */
651        NULL,                           /* get_direction */
652        NULL,                           /* set_direction */
653        etsilive_get_erf_timestamp,     /* get_erf_timestamp */
654        NULL,                           /* 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.