source: lib/format_etsilive.c @ d24b1df

develop
Last change on this file since d24b1df was d24b1df, checked in by Shane Alcock <salcock@…>, 3 years ago

Tidy up source tracking in etsilive: input format

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