source: lib/format_etsilive.c @ ef5ba20

develop
Last change on this file since ef5ba20 was ef5ba20, checked in by Jacob Van Walraven <jcv9@…>, 22 months ago

add abilty to get custom option from meta packets, add abilty to get entire section from meta packet, meta api now returns libtrace_meta_t structure

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