[a79ddbe] | 1 | /* |
---|
[9636216] | 2 | * |
---|
[ee6e802] | 3 | * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand. |
---|
[a79ddbe] | 4 | * All rights reserved. |
---|
| 5 | * |
---|
[ee6e802] | 6 | * This file is part of libtrace. |
---|
| 7 | * |
---|
[9636216] | 8 | * This code has been developed by the University of Waikato WAND |
---|
[a79ddbe] | 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 |
---|
[ee6e802] | 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 |
---|
[a79ddbe] | 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 |
---|
[ee6e802] | 19 | * GNU Lesser General Public License for more details. |
---|
[a79ddbe] | 20 | * |
---|
[ee6e802] | 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/>. |
---|
[a79ddbe] | 23 | * |
---|
| 24 | * |
---|
| 25 | */ |
---|
| 26 | |
---|
[2c060e3] | 27 | #define _GNU_SOURCE |
---|
[6c05d2c] | 28 | #include "common.h" |
---|
[60fc8aa] | 29 | #include "config.h" |
---|
[2c060e3] | 30 | #include <assert.h> |
---|
| 31 | #include <errno.h> |
---|
| 32 | #include <fcntl.h> |
---|
| 33 | #include <stdio.h> |
---|
| 34 | #include <stdlib.h> |
---|
| 35 | #include <string.h> |
---|
| 36 | #include <sys/stat.h> |
---|
| 37 | #include <sys/types.h> |
---|
[6ed6c4a] | 38 | #ifndef WIN32 |
---|
[77285d9] | 39 | #include <sys/socket.h> |
---|
[6ed6c4a] | 40 | #endif |
---|
[3d4d52d] | 41 | #include <stdarg.h> |
---|
[11041eb] | 42 | #include <sys/param.h> |
---|
[e5d3718] | 43 | |
---|
| 44 | #ifdef HAVE_LIMITS_H |
---|
| 45 | # include <limits.h> |
---|
| 46 | #endif |
---|
| 47 | |
---|
[1f3696b] | 48 | #ifdef HAVE_SYS_LIMITS_H |
---|
| 49 | # include <sys/limits.h> |
---|
| 50 | #endif |
---|
[e5d3718] | 51 | |
---|
[808a478] | 52 | #ifdef HAVE_NET_IF_ARP_H |
---|
| 53 | # include <net/if_arp.h> |
---|
| 54 | #endif |
---|
| 55 | |
---|
| 56 | #ifdef HAVE_NET_IF_H |
---|
| 57 | # include <net/if.h> |
---|
| 58 | #endif |
---|
| 59 | |
---|
| 60 | #ifdef HAVE_NETINET_IN_H |
---|
| 61 | # include <netinet/in.h> |
---|
| 62 | #endif |
---|
| 63 | |
---|
| 64 | #ifdef HAVE_NET_ETHERNET_H |
---|
| 65 | # include <net/ethernet.h> |
---|
| 66 | #endif |
---|
| 67 | |
---|
| 68 | #ifdef HAVE_NETINET_IF_ETHER_H |
---|
| 69 | # include <netinet/if_ether.h> |
---|
| 70 | #endif |
---|
| 71 | |
---|
[2c060e3] | 72 | #include <time.h> |
---|
[6ed6c4a] | 73 | #ifdef WIN32 |
---|
| 74 | #include <sys/timeb.h> |
---|
| 75 | #endif |
---|
[dfef05d] | 76 | |
---|
[2c060e3] | 77 | #include "libtrace.h" |
---|
[9e2a109] | 78 | #include "libtrace_int.h" |
---|
[2c060e3] | 79 | |
---|
[e5c2bc4] | 80 | #ifdef HAVE_PCAP_BPF_H |
---|
[6c05d2c] | 81 | # include <pcap-bpf.h> |
---|
| 82 | #else |
---|
| 83 | # ifdef HAVE_NET_BPF_H |
---|
| 84 | # include <net/bpf.h> |
---|
| 85 | # endif |
---|
| 86 | #endif |
---|
[2137b49] | 87 | |
---|
[e5c2bc4] | 88 | |
---|
[9e2a109] | 89 | #include "libtrace_int.h" |
---|
[72bfe20] | 90 | #include "format_helper.h" |
---|
[6dbc47a] | 91 | #include "rt_protocol.h" |
---|
[2c060e3] | 92 | |
---|
[29bbef0] | 93 | #include <pthread.h> |
---|
| 94 | #include <signal.h> |
---|
| 95 | |
---|
[91ebc50] | 96 | #define MAXOPTS 1024 |
---|
| 97 | |
---|
[eda2def] | 98 | /* This file contains much of the implementation of the libtrace API itself. */ |
---|
[c5a22ec] | 99 | |
---|
[4dfa44e] | 100 | static struct libtrace_format_t *formats_list = NULL; |
---|
[a6badc2] | 101 | |
---|
[b73407f] | 102 | volatile int libtrace_halt = 0; |
---|
[60e8e86] | 103 | /* Set once pstart is called used for backwards compatibility reasons */ |
---|
[17a3dff] | 104 | int libtrace_parallel = 0; |
---|
[60e8e86] | 105 | |
---|
[6f75b9d] | 106 | /* strncpy is not assured to copy the final \0, so we |
---|
| 107 | * will use our own one that does |
---|
| 108 | */ |
---|
| 109 | static void xstrncpy(char *dest, const char *src, size_t n) |
---|
| 110 | { |
---|
| 111 | strncpy(dest,src,n); |
---|
| 112 | dest[n]='\0'; |
---|
| 113 | } |
---|
[9636216] | 114 | |
---|
[6f75b9d] | 115 | static char *xstrndup(const char *src,size_t n) |
---|
[9636216] | 116 | { |
---|
[e502f76] | 117 | char *ret=(char*)malloc(n+1); |
---|
[d694056] | 118 | if (ret==NULL) { |
---|
| 119 | fprintf(stderr,"Out of memory"); |
---|
| 120 | exit(EXIT_FAILURE); |
---|
| 121 | } |
---|
[6f75b9d] | 122 | xstrncpy(ret,src,n); |
---|
| 123 | return ret; |
---|
| 124 | } |
---|
| 125 | |
---|
[8dd1830] | 126 | |
---|
[dd2eaee] | 127 | /* call all the constructors if they haven't yet all been called */ |
---|
[33d83d4] | 128 | static void trace_init(void) |
---|
[dd2eaee] | 129 | { |
---|
[f0cb0d4] | 130 | struct timeval tv; |
---|
| 131 | gettimeofday(&tv, NULL); |
---|
| 132 | srand(tv.tv_sec); |
---|
| 133 | |
---|
[dd2eaee] | 134 | if (!formats_list) { |
---|
[cd7eec7] | 135 | duck_constructor(); |
---|
[dd2eaee] | 136 | erf_constructor(); |
---|
[e01a738] | 137 | tsh_constructor(); |
---|
[dd2eaee] | 138 | legacy_constructor(); |
---|
[e1fdc05] | 139 | atmhdr_constructor(); |
---|
[035f8a7] | 140 | linuxring_constructor(); |
---|
[dd2eaee] | 141 | linuxnative_constructor(); |
---|
[e5c2bc4] | 142 | #ifdef HAVE_LIBPCAP |
---|
[dd2eaee] | 143 | pcap_constructor(); |
---|
| 144 | #endif |
---|
[755e794] | 145 | bpf_constructor(); |
---|
[dd2eaee] | 146 | pcapfile_constructor(); |
---|
[ed5b2ce] | 147 | pcapng_constructor(); |
---|
| 148 | rt_constructor(); |
---|
[ea75ec2] | 149 | ndag_constructor(); |
---|
[b663d33] | 150 | #ifdef HAVE_WANDDER |
---|
[df87f00] | 151 | etsilive_constructor(); |
---|
[b663d33] | 152 | #endif |
---|
[5e85c23] | 153 | #ifdef HAVE_DAG |
---|
| 154 | dag_constructor(); |
---|
| 155 | #endif |
---|
[c04929c] | 156 | #ifdef HAVE_DPDK |
---|
[c7e547e] | 157 | dpdk_constructor(); |
---|
| 158 | dpdkndag_constructor(); |
---|
[c04929c] | 159 | #endif |
---|
[dd2eaee] | 160 | } |
---|
| 161 | } |
---|
| 162 | |
---|
[9636216] | 163 | /* Prints help information for libtrace |
---|
[40ba6ad] | 164 | * |
---|
| 165 | * Function prints out some basic help information regarding libtrace, |
---|
| 166 | * and then prints out the help() function registered with each input module |
---|
| 167 | */ |
---|
[e1868fb] | 168 | DLLEXPORT void trace_help(void) { |
---|
[eeab9832] | 169 | struct libtrace_format_t *tmp; |
---|
[dd2eaee] | 170 | trace_init(); |
---|
[47de0aa] | 171 | printf("libtrace %s\n\n",PACKAGE_VERSION); |
---|
| 172 | printf("Following this are a list of the format modules supported in this build of libtrace\n\n"); |
---|
[eeab9832] | 173 | for(tmp=formats_list;tmp;tmp=tmp->next) { |
---|
| 174 | if (tmp->help) |
---|
| 175 | tmp->help(); |
---|
[40ba6ad] | 176 | } |
---|
| 177 | } |
---|
| 178 | |
---|
[4bd8a5b] | 179 | #define URI_PROTO_LINE 16U |
---|
[2c060e3] | 180 | |
---|
[eda2def] | 181 | /* Try to guess which format module is appropriate for a given trace file or |
---|
| 182 | * device */ |
---|
[91b72d3] | 183 | static void guess_format(libtrace_t *libtrace, const char *filename) |
---|
| 184 | { |
---|
| 185 | struct libtrace_format_t *tmp; |
---|
[9636216] | 186 | |
---|
[91b72d3] | 187 | /* Try and guess based on filename */ |
---|
| 188 | for(tmp = formats_list; tmp; tmp=tmp->next) { |
---|
| 189 | if (tmp->probe_filename && tmp->probe_filename(filename)) { |
---|
| 190 | libtrace->format = tmp; |
---|
[23e1258] | 191 | libtrace->uridata = strdup(filename); |
---|
[91b72d3] | 192 | return; |
---|
| 193 | } |
---|
| 194 | } |
---|
| 195 | |
---|
| 196 | libtrace->io = wandio_create(filename); |
---|
| 197 | if (!libtrace->io) |
---|
| 198 | return; |
---|
| 199 | |
---|
| 200 | /* Try and guess based on file magic */ |
---|
| 201 | for(tmp = formats_list; tmp; tmp=tmp->next) { |
---|
| 202 | if (tmp->probe_magic && tmp->probe_magic(libtrace->io)) { |
---|
| 203 | libtrace->format = tmp; |
---|
[23e1258] | 204 | libtrace->uridata = strdup(filename); |
---|
[91b72d3] | 205 | return; |
---|
| 206 | } |
---|
| 207 | } |
---|
[9636216] | 208 | |
---|
[584d907] | 209 | /* No formats matched -- make sure we clean up the IO object we |
---|
| 210 | * used to probe the file magic */ |
---|
| 211 | wandio_destroy(libtrace->io); |
---|
[91b72d3] | 212 | return; |
---|
| 213 | } |
---|
[dd2eaee] | 214 | |
---|
[eda2def] | 215 | /* Creates an input trace from a URI |
---|
[fba4ca0] | 216 | * |
---|
| 217 | * @params char * containing a valid libtrace URI |
---|
[2c060e3] | 218 | * @returns opaque pointer to a libtrace_t |
---|
| 219 | * |
---|
[eda2def] | 220 | * Some valid URI's are: |
---|
[277442c] | 221 | * erf:/path/to/erf/file |
---|
| 222 | * erf:/path/to/erf/file.gz |
---|
[9636216] | 223 | * erf:- (stdin) |
---|
[fba4ca0] | 224 | * dag:/dev/dagcard |
---|
[9636216] | 225 | * pcapint:pcapinterface (eg: pcapint:eth0) |
---|
[eda2def] | 226 | * pcapfile:/path/to/pcap/file |
---|
| 227 | * pcapfile:- |
---|
| 228 | * int:interface (eg: int:eth0) only on Linux |
---|
| 229 | * rt:hostname |
---|
| 230 | * rt:hostname:port |
---|
[277442c] | 231 | * |
---|
| 232 | * If an error occured when attempting to open a trace, NULL is returned |
---|
| 233 | * and an error is output to stdout. |
---|
[2c060e3] | 234 | */ |
---|
[e6d963c] | 235 | DLLEXPORT libtrace_t *trace_create(const char *uri) { |
---|
[9636216] | 236 | libtrace_t *libtrace = |
---|
[e6d963c] | 237 | (libtrace_t *)malloc(sizeof(libtrace_t)); |
---|
[de8c420b] | 238 | char *scan = 0; |
---|
[9636216] | 239 | const char *uridata = 0; |
---|
[0c222cc] | 240 | |
---|
[dd2eaee] | 241 | trace_init(); |
---|
| 242 | |
---|
[0c222cc] | 243 | assert(uri && "Passing NULL to trace_create makes me a very sad program"); |
---|
[d694056] | 244 | |
---|
| 245 | if (!libtrace) { |
---|
| 246 | /* Out of memory */ |
---|
| 247 | return NULL; |
---|
| 248 | } |
---|
[9636216] | 249 | |
---|
[eea0f87] | 250 | libtrace->err.err_num = TRACE_ERR_NOERROR; |
---|
[0ea3526] | 251 | libtrace->format=NULL; |
---|
[9636216] | 252 | |
---|
[9e2a109] | 253 | libtrace->event.tdelta = 0.0; |
---|
[b9aa767] | 254 | libtrace->event.packet = NULL; |
---|
| 255 | libtrace->event.psize = 0; |
---|
| 256 | libtrace->event.trace_last_ts = 0.0; |
---|
[9cc1266] | 257 | libtrace->event.waiting = false; |
---|
[880aa58] | 258 | libtrace->filter = NULL; |
---|
| 259 | libtrace->snaplen = 0; |
---|
[d8f02df] | 260 | libtrace->started=false; |
---|
[670bbe5] | 261 | libtrace->uridata = NULL; |
---|
[91b72d3] | 262 | libtrace->io = NULL; |
---|
[670bbe5] | 263 | libtrace->filtered_packets = 0; |
---|
[5bd27a3] | 264 | libtrace->accepted_packets = 0; |
---|
[2fa43fa] | 265 | libtrace->last_packet = NULL; |
---|
[29bbef0] | 266 | |
---|
| 267 | /* Parallel inits */ |
---|
[04bf7c5] | 268 | ASSERT_RET(pthread_mutex_init(&libtrace->libtrace_lock, NULL), == 0); |
---|
[5e3f16c] | 269 | ASSERT_RET(pthread_mutex_init(&libtrace->read_packet_lock, NULL), == 0); |
---|
[04bf7c5] | 270 | ASSERT_RET(pthread_cond_init(&libtrace->perpkt_cond, NULL), == 0); |
---|
[fac8c46] | 271 | libtrace->state = STATE_NEW; |
---|
[17a3dff] | 272 | libtrace->perpkt_queue_full = false; |
---|
[29bbef0] | 273 | libtrace->global_blob = NULL; |
---|
| 274 | libtrace->hasher = NULL; |
---|
[ff12906] | 275 | libtrace->hasher_data = NULL; |
---|
[e375e0f] | 276 | libtrace->hasher_owner = HASH_OWNED_EXTERNAL; |
---|
[a49a9eb] | 277 | libtrace_zero_ocache(&libtrace->packet_freelist); |
---|
[29bbef0] | 278 | libtrace_zero_thread(&libtrace->hasher_thread); |
---|
[f051c1b] | 279 | libtrace_zero_thread(&libtrace->reporter_thread); |
---|
[82facc5] | 280 | libtrace_zero_thread(&libtrace->keepalive_thread); |
---|
[f051c1b] | 281 | libtrace->reporter_thread.type = THREAD_EMPTY; |
---|
[17a3dff] | 282 | libtrace->perpkt_thread_count = 0; |
---|
| 283 | libtrace->perpkt_threads = NULL; |
---|
[fac8c46] | 284 | libtrace->tracetime = 0; |
---|
[c99b1e5] | 285 | libtrace->first_packets.first = 0; |
---|
| 286 | libtrace->first_packets.count = 0; |
---|
| 287 | libtrace->first_packets.packets = NULL; |
---|
[5ab626a] | 288 | libtrace->stats = NULL; |
---|
[858ce90] | 289 | libtrace->pread = NULL; |
---|
[91e016c] | 290 | libtrace->sequence_number = 0; |
---|
[f051c1b] | 291 | ZERO_USER_CONFIG(libtrace->config); |
---|
[f50515e] | 292 | memset(&libtrace->combiner, 0, sizeof(libtrace->combiner)); |
---|
[f625817] | 293 | libtrace->perpkt_cbs = NULL; |
---|
| 294 | libtrace->reporter_cbs = NULL; |
---|
[9e2a109] | 295 | |
---|
[eda2def] | 296 | /* Parse the URI to determine what sort of trace we are dealing with */ |
---|
[984f7da] | 297 | if ((uridata = trace_parse_uri(uri, &scan)) == 0) { |
---|
[eda2def] | 298 | /* Could not parse the URI nicely */ |
---|
[91b72d3] | 299 | guess_format(libtrace,uri); |
---|
| 300 | if (!libtrace->format) { |
---|
| 301 | trace_set_err(libtrace,TRACE_ERR_BAD_FORMAT,"Unable to guess format (%s)",uri); |
---|
| 302 | return libtrace; |
---|
[6f75b9d] | 303 | } |
---|
[9e2a109] | 304 | } |
---|
[91b72d3] | 305 | else { |
---|
| 306 | struct libtrace_format_t *tmp; |
---|
| 307 | |
---|
[eda2def] | 308 | /* Find a format that matches the first part of the URI */ |
---|
[91b72d3] | 309 | for (tmp=formats_list;tmp;tmp=tmp->next) { |
---|
| 310 | if (strlen(scan) == strlen(tmp->name) && |
---|
| 311 | strncasecmp(scan, tmp->name, strlen(scan)) == 0 |
---|
| 312 | ) { |
---|
| 313 | libtrace->format=tmp; |
---|
| 314 | break; |
---|
| 315 | } |
---|
| 316 | } |
---|
[eda2def] | 317 | |
---|
[91b72d3] | 318 | if (libtrace->format == 0) { |
---|
| 319 | trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT, |
---|
| 320 | "Unknown format (%s)",scan); |
---|
| 321 | return libtrace; |
---|
| 322 | } |
---|
[9e2a109] | 323 | |
---|
[91b72d3] | 324 | libtrace->uridata = strdup(uridata); |
---|
| 325 | } |
---|
[7068467] | 326 | /* libtrace->format now contains the type of uri |
---|
| 327 | * libtrace->uridata contains the appropriate data for this |
---|
| 328 | */ |
---|
[9636216] | 329 | |
---|
| 330 | /* Call the init_input function for the matching capture format */ |
---|
[9e2a109] | 331 | if (libtrace->format->init_input) { |
---|
[d5879cc] | 332 | int err=libtrace->format->init_input(libtrace); |
---|
| 333 | assert (err==-1 || err==0); |
---|
| 334 | if (err==-1) { |
---|
[9636216] | 335 | /* init_input should call trace_set_err to set the |
---|
| 336 | * error message |
---|
[880aa58] | 337 | */ |
---|
[0ea3526] | 338 | return libtrace; |
---|
[ffc8c8d] | 339 | } |
---|
[9e2a109] | 340 | } else { |
---|
[91db67b] | 341 | trace_set_err(libtrace,TRACE_ERR_UNSUPPORTED, |
---|
[880aa58] | 342 | "Format does not support input (%s)",scan); |
---|
[0ea3526] | 343 | return libtrace; |
---|
[9e2a109] | 344 | } |
---|
[9636216] | 345 | |
---|
[dfbdd796] | 346 | if (scan) |
---|
| 347 | free(scan); |
---|
[ae66bde] | 348 | libtrace->err.err_num=TRACE_ERR_NOERROR; |
---|
| 349 | libtrace->err.problem[0]='\0'; |
---|
[2c060e3] | 350 | return libtrace; |
---|
| 351 | } |
---|
| 352 | |
---|
[fba4ca0] | 353 | /* Creates a "dummy" trace file that has only the format type set. |
---|
| 354 | * |
---|
| 355 | * @returns opaque pointer to a (sparsely initialised) libtrace_t |
---|
| 356 | * |
---|
[880aa58] | 357 | * IMPORTANT: Do not attempt to call trace_read_packet or other such functions |
---|
| 358 | * with the dummy trace. Its intended purpose is to act as a packet->trace for |
---|
| 359 | * libtrace_packet_t's that are not associated with a libtrace_t structure. |
---|
[fba4ca0] | 360 | */ |
---|
[e6d963c] | 361 | DLLEXPORT libtrace_t * trace_create_dead (const char *uri) { |
---|
| 362 | libtrace_t *libtrace = (libtrace_t *) malloc(sizeof(libtrace_t)); |
---|
[67a14d4] | 363 | char *scan = (char *)calloc(sizeof(char),URI_PROTO_LINE); |
---|
[084d95a] | 364 | char *uridata; |
---|
[eeab9832] | 365 | struct libtrace_format_t *tmp; |
---|
[0453ca8] | 366 | |
---|
| 367 | trace_init(); |
---|
[9636216] | 368 | |
---|
[eea0f87] | 369 | libtrace->err.err_num = TRACE_ERR_NOERROR; |
---|
[084d95a] | 370 | |
---|
| 371 | if((uridata = strchr(uri,':')) == NULL) { |
---|
[6f75b9d] | 372 | xstrncpy(scan, uri, strlen(uri)); |
---|
[084d95a] | 373 | } else { |
---|
[4bd8a5b] | 374 | xstrncpy(scan,uri, (size_t)(uridata - uri)); |
---|
[084d95a] | 375 | } |
---|
[9636216] | 376 | |
---|
[91b72d3] | 377 | libtrace->err.err_num = TRACE_ERR_NOERROR; |
---|
| 378 | libtrace->format=NULL; |
---|
[9636216] | 379 | |
---|
[91b72d3] | 380 | libtrace->event.tdelta = 0.0; |
---|
| 381 | libtrace->event.packet = NULL; |
---|
| 382 | libtrace->event.psize = 0; |
---|
| 383 | libtrace->event.trace_last_ts = 0.0; |
---|
| 384 | libtrace->filter = NULL; |
---|
| 385 | libtrace->snaplen = 0; |
---|
| 386 | libtrace->started=false; |
---|
| 387 | libtrace->uridata = NULL; |
---|
| 388 | libtrace->io = NULL; |
---|
| 389 | libtrace->filtered_packets = 0; |
---|
[2fa43fa] | 390 | libtrace->accepted_packets = 0; |
---|
| 391 | libtrace->last_packet = NULL; |
---|
[084d95a] | 392 | |
---|
[29bbef0] | 393 | /* Parallel inits */ |
---|
[04bf7c5] | 394 | ASSERT_RET(pthread_mutex_init(&libtrace->libtrace_lock, NULL), == 0); |
---|
[5e3f16c] | 395 | ASSERT_RET(pthread_mutex_init(&libtrace->read_packet_lock, NULL), == 0); |
---|
[04bf7c5] | 396 | ASSERT_RET(pthread_cond_init(&libtrace->perpkt_cond, NULL), == 0); |
---|
[fac8c46] | 397 | libtrace->state = STATE_NEW; // TODO MAYBE DEAD |
---|
[17a3dff] | 398 | libtrace->perpkt_queue_full = false; |
---|
[29bbef0] | 399 | libtrace->global_blob = NULL; |
---|
| 400 | libtrace->hasher = NULL; |
---|
[a49a9eb] | 401 | libtrace_zero_ocache(&libtrace->packet_freelist); |
---|
[29bbef0] | 402 | libtrace_zero_thread(&libtrace->hasher_thread); |
---|
[f051c1b] | 403 | libtrace_zero_thread(&libtrace->reporter_thread); |
---|
[82facc5] | 404 | libtrace_zero_thread(&libtrace->keepalive_thread); |
---|
[f051c1b] | 405 | libtrace->reporter_thread.type = THREAD_EMPTY; |
---|
[17a3dff] | 406 | libtrace->perpkt_thread_count = 0; |
---|
| 407 | libtrace->perpkt_threads = NULL; |
---|
[fac8c46] | 408 | libtrace->tracetime = 0; |
---|
[5ab626a] | 409 | libtrace->stats = NULL; |
---|
[858ce90] | 410 | libtrace->pread = NULL; |
---|
[91e016c] | 411 | libtrace->sequence_number = 0; |
---|
[f051c1b] | 412 | ZERO_USER_CONFIG(libtrace->config); |
---|
[f50515e] | 413 | memset(&libtrace->combiner, 0, sizeof(libtrace->combiner)); |
---|
[f625817] | 414 | libtrace->perpkt_cbs = NULL; |
---|
| 415 | libtrace->reporter_cbs = NULL; |
---|
[eeab9832] | 416 | for(tmp=formats_list;tmp;tmp=tmp->next) { |
---|
| 417 | if (strlen(scan) == strlen(tmp->name) && |
---|
[084d95a] | 418 | !strncasecmp(scan, |
---|
[eeab9832] | 419 | tmp->name, |
---|
[084d95a] | 420 | strlen(scan))) { |
---|
[eeab9832] | 421 | libtrace->format=tmp; |
---|
[084d95a] | 422 | break; |
---|
| 423 | } |
---|
| 424 | } |
---|
| 425 | if (libtrace->format == 0) { |
---|
[0ea3526] | 426 | trace_set_err(libtrace,TRACE_ERR_BAD_FORMAT, |
---|
[880aa58] | 427 | "Unknown format (%s)",scan); |
---|
[084d95a] | 428 | } |
---|
[7ac9705] | 429 | |
---|
| 430 | libtrace->format_data = NULL; |
---|
[ae8196e] | 431 | free(scan); |
---|
[084d95a] | 432 | return libtrace; |
---|
| 433 | |
---|
| 434 | } |
---|
[fba4ca0] | 435 | |
---|
[9636216] | 436 | /* Creates an output trace from a URI. |
---|
[5eae97a] | 437 | * |
---|
[fba4ca0] | 438 | * @param uri the uri string describing the output format and destination |
---|
[9636216] | 439 | * @returns opaque pointer to a libtrace_output_t |
---|
[fba4ca0] | 440 | * |
---|
[880aa58] | 441 | * If an error occured when attempting to open the output trace, NULL is |
---|
[9636216] | 442 | * returned and trace_errno is set. |
---|
[fba4ca0] | 443 | */ |
---|
[9636216] | 444 | |
---|
[39e141f] | 445 | DLLEXPORT libtrace_out_t *trace_create_output(const char *uri) { |
---|
[9636216] | 446 | libtrace_out_t *libtrace = |
---|
[e6d963c] | 447 | (libtrace_out_t*)malloc(sizeof(libtrace_out_t)); |
---|
[9636216] | 448 | |
---|
[de8c420b] | 449 | char *scan = 0; |
---|
[6f75b9d] | 450 | const char *uridata = 0; |
---|
[eeab9832] | 451 | struct libtrace_format_t *tmp; |
---|
[df2dff9] | 452 | |
---|
[dd2eaee] | 453 | trace_init(); |
---|
| 454 | |
---|
[eea0f87] | 455 | libtrace->err.err_num = TRACE_ERR_NOERROR; |
---|
[d97bbb2] | 456 | strcpy(libtrace->err.problem,"Error message set\n"); |
---|
[52cc59f] | 457 | libtrace->format = NULL; |
---|
| 458 | libtrace->uridata = NULL; |
---|
[9636216] | 459 | |
---|
[eda2def] | 460 | /* Parse the URI to determine what capture format we want to write */ |
---|
[df2dff9] | 461 | |
---|
[de8c420b] | 462 | if ((uridata = trace_parse_uri(uri, &scan)) == 0) { |
---|
[eeab9832] | 463 | trace_set_err_out(libtrace,TRACE_ERR_BAD_FORMAT, |
---|
| 464 | "Bad uri format (%s)",uri); |
---|
[0ea3526] | 465 | return libtrace; |
---|
[de8c420b] | 466 | } |
---|
[9636216] | 467 | |
---|
[eda2def] | 468 | /* Attempt to find the format in the list of supported formats */ |
---|
[eeab9832] | 469 | for(tmp=formats_list;tmp;tmp=tmp->next) { |
---|
| 470 | if (strlen(scan) == strlen(tmp->name) && |
---|
[df2dff9] | 471 | !strncasecmp(scan, |
---|
[eeab9832] | 472 | tmp->name, |
---|
[df2dff9] | 473 | strlen(scan))) { |
---|
[eeab9832] | 474 | libtrace->format=tmp; |
---|
[df2dff9] | 475 | break; |
---|
| 476 | } |
---|
| 477 | } |
---|
[52cc59f] | 478 | free(scan); |
---|
| 479 | |
---|
[eeab9832] | 480 | if (libtrace->format == NULL) { |
---|
[0ea3526] | 481 | trace_set_err_out(libtrace,TRACE_ERR_BAD_FORMAT, |
---|
[880aa58] | 482 | "Unknown output format (%s)",scan); |
---|
[eeab9832] | 483 | return libtrace; |
---|
[df2dff9] | 484 | } |
---|
| 485 | libtrace->uridata = strdup(uridata); |
---|
| 486 | |
---|
[7068467] | 487 | /* libtrace->format now contains the type of uri |
---|
| 488 | * libtrace->uridata contains the appropriate data for this |
---|
| 489 | */ |
---|
[df2dff9] | 490 | |
---|
| 491 | if (libtrace->format->init_output) { |
---|
[fe76c55] | 492 | /* 0 on success, -1 on failure */ |
---|
| 493 | switch(libtrace->format->init_output(libtrace)) { |
---|
| 494 | case -1: /* failure */ |
---|
[eeab9832] | 495 | return libtrace; |
---|
[fe76c55] | 496 | case 0: /* success */ |
---|
| 497 | break; |
---|
| 498 | default: |
---|
[8f18776] | 499 | assert(!"Internal error: init_output() should return -1 for failure, or 0 for success"); |
---|
[ffc8c8d] | 500 | } |
---|
[df2dff9] | 501 | } else { |
---|
[91db67b] | 502 | trace_set_err_out(libtrace,TRACE_ERR_UNSUPPORTED, |
---|
[880aa58] | 503 | "Format does not support writing (%s)",scan); |
---|
[0ea3526] | 504 | return libtrace; |
---|
[df2dff9] | 505 | } |
---|
| 506 | |
---|
| 507 | |
---|
[0a6638f] | 508 | libtrace->started=false; |
---|
[91ebc50] | 509 | return libtrace; |
---|
| 510 | } |
---|
[5eae97a] | 511 | |
---|
[eda2def] | 512 | /* Start an input trace |
---|
[37195b4] | 513 | * @param libtrace the input trace to start |
---|
| 514 | * @returns 0 on success |
---|
| 515 | * |
---|
| 516 | * This does the work associated with actually starting up |
---|
| 517 | * the trace. it may fail. |
---|
| 518 | */ |
---|
[e6d963c] | 519 | DLLEXPORT int trace_start(libtrace_t *libtrace) |
---|
[37195b4] | 520 | { |
---|
[df338b3] | 521 | assert(libtrace); |
---|
[8f18776] | 522 | if (trace_is_err(libtrace)) |
---|
| 523 | return -1; |
---|
[37195b4] | 524 | if (libtrace->format->start_input) { |
---|
| 525 | int ret=libtrace->format->start_input(libtrace); |
---|
[49babe0] | 526 | if (ret < 0) { |
---|
[37195b4] | 527 | return ret; |
---|
| 528 | } |
---|
| 529 | } |
---|
| 530 | |
---|
| 531 | libtrace->started=true; |
---|
| 532 | return 0; |
---|
| 533 | } |
---|
| 534 | |
---|
[eda2def] | 535 | /* Start an output trace */ |
---|
[9636216] | 536 | DLLEXPORT int trace_start_output(libtrace_out_t *libtrace) |
---|
[0a6638f] | 537 | { |
---|
| 538 | assert(libtrace); |
---|
| 539 | if (libtrace->format->start_output) { |
---|
| 540 | int ret=libtrace->format->start_output(libtrace); |
---|
| 541 | if (ret < 0) { |
---|
| 542 | return ret; |
---|
| 543 | } |
---|
| 544 | } |
---|
| 545 | |
---|
[eeab9832] | 546 | libtrace->started=true; |
---|
[0a6638f] | 547 | return 0; |
---|
| 548 | } |
---|
| 549 | |
---|
[39e141f] | 550 | DLLEXPORT int trace_pause(libtrace_t *libtrace) |
---|
[1fbd938] | 551 | { |
---|
| 552 | assert(libtrace); |
---|
[8f18776] | 553 | if (!libtrace->started) { |
---|
| 554 | trace_set_err(libtrace,TRACE_ERR_BAD_STATE, "You must call trace_start() before calling trace_pause()"); |
---|
| 555 | return -1; |
---|
| 556 | } |
---|
[2fa43fa] | 557 | |
---|
| 558 | /* Finish the last packet we read - for backwards compatibility */ |
---|
[adb2c4c] | 559 | if (!libtrace_parallel && libtrace->last_packet) |
---|
[2fa43fa] | 560 | trace_fin_packet(libtrace->last_packet); |
---|
| 561 | assert(libtrace->last_packet == NULL); |
---|
| 562 | |
---|
[1fbd938] | 563 | if (libtrace->format->pause_input) |
---|
| 564 | libtrace->format->pause_input(libtrace); |
---|
[2fa43fa] | 565 | |
---|
[1fbd938] | 566 | libtrace->started=false; |
---|
| 567 | return 0; |
---|
| 568 | } |
---|
| 569 | |
---|
[39e141f] | 570 | DLLEXPORT int trace_config(libtrace_t *libtrace, |
---|
[65a5900] | 571 | trace_option_t option, |
---|
| 572 | void *value) |
---|
| 573 | { |
---|
| 574 | int ret; |
---|
[8f18776] | 575 | |
---|
| 576 | if (trace_is_err(libtrace)) { |
---|
| 577 | return -1; |
---|
| 578 | } |
---|
[6b98325] | 579 | |
---|
| 580 | if (option == TRACE_OPTION_HASHER) |
---|
| 581 | return trace_set_hasher(libtrace, |
---|
| 582 | (enum hasher_types) *((int *) value), |
---|
| 583 | NULL, NULL); |
---|
| 584 | |
---|
[eda2def] | 585 | /* If the capture format supports configuration, try using their |
---|
| 586 | * native configuration first */ |
---|
[65a5900] | 587 | if (libtrace->format->config_input) { |
---|
| 588 | ret=libtrace->format->config_input(libtrace,option,value); |
---|
| 589 | if (ret==0) |
---|
| 590 | return 0; |
---|
| 591 | } |
---|
[eda2def] | 592 | |
---|
| 593 | /* If we get here, either the native configuration failed or the |
---|
[9636216] | 594 | * format did not support configuration. However, libtrace can |
---|
[eda2def] | 595 | * deal with some options itself, so give that a go */ |
---|
[65a5900] | 596 | switch(option) { |
---|
| 597 | case TRACE_OPTION_SNAPLEN: |
---|
[205809b] | 598 | /* Clear the error if there was one */ |
---|
| 599 | if (trace_is_err(libtrace)) { |
---|
[a3041a4] | 600 | trace_get_err(libtrace); |
---|
[205809b] | 601 | } |
---|
[9636216] | 602 | if (*(int*)value<0 |
---|
[cdcaef6] | 603 | || *(int*)value>LIBTRACE_PACKET_BUFSIZE) { |
---|
| 604 | trace_set_err(libtrace,TRACE_ERR_BAD_STATE, |
---|
| 605 | "Invalid snap length"); |
---|
| 606 | } |
---|
[65a5900] | 607 | libtrace->snaplen=*(int*)value; |
---|
[67a14d4] | 608 | return 0; |
---|
[65a5900] | 609 | case TRACE_OPTION_FILTER: |
---|
[205809b] | 610 | /* Clear the error if there was one */ |
---|
| 611 | if (trace_is_err(libtrace)) { |
---|
[a3041a4] | 612 | trace_get_err(libtrace); |
---|
[205809b] | 613 | } |
---|
[e6d963c] | 614 | libtrace->filter=(libtrace_filter_t *)value; |
---|
[67a14d4] | 615 | return 0; |
---|
[65a5900] | 616 | case TRACE_OPTION_PROMISC: |
---|
[205809b] | 617 | if (!trace_is_err(libtrace)) { |
---|
| 618 | trace_set_err(libtrace,TRACE_ERR_OPTION_UNAVAIL, |
---|
| 619 | "Promisc mode is not supported by this format module"); |
---|
| 620 | } |
---|
[65a5900] | 621 | return -1; |
---|
[646aca1] | 622 | case TRACE_OPTION_META_FREQ: |
---|
[205809b] | 623 | if (!trace_is_err(libtrace)) { |
---|
[9636216] | 624 | trace_set_err(libtrace, |
---|
[205809b] | 625 | TRACE_ERR_OPTION_UNAVAIL, |
---|
| 626 | "This format does not support meta-data gathering"); |
---|
| 627 | } |
---|
[cd7eec7] | 628 | return -1; |
---|
[646aca1] | 629 | case TRACE_OPTION_EVENT_REALTIME: |
---|
| 630 | if (!trace_is_err(libtrace)) { |
---|
[9636216] | 631 | trace_set_err(libtrace, |
---|
[646aca1] | 632 | TRACE_ERR_OPTION_UNAVAIL, |
---|
[f6e8d46] | 633 | "This format does not support realtime events"); |
---|
[646aca1] | 634 | } |
---|
| 635 | return -1; |
---|
[6b98325] | 636 | case TRACE_OPTION_HASHER: |
---|
| 637 | /* Dealt with earlier */ |
---|
| 638 | return -1; |
---|
[9636216] | 639 | |
---|
[65a5900] | 640 | } |
---|
[205809b] | 641 | if (!trace_is_err(libtrace)) { |
---|
| 642 | trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION, |
---|
| 643 | "Unknown option %i", option); |
---|
| 644 | } |
---|
[67a14d4] | 645 | return -1; |
---|
[65a5900] | 646 | } |
---|
| 647 | |
---|
[6b98325] | 648 | DLLEXPORT int trace_set_snaplen(libtrace_t *trace, int snaplen) { |
---|
| 649 | return trace_config(trace, TRACE_OPTION_SNAPLEN, &snaplen); |
---|
| 650 | } |
---|
| 651 | |
---|
| 652 | DLLEXPORT int trace_set_promisc(libtrace_t *trace, bool promisc) { |
---|
| 653 | int tmp = promisc; |
---|
| 654 | return trace_config(trace, TRACE_OPTION_PROMISC, &tmp); |
---|
| 655 | } |
---|
| 656 | |
---|
| 657 | DLLEXPORT int trace_set_filter(libtrace_t *trace, libtrace_filter_t *filter) { |
---|
| 658 | return trace_config(trace, TRACE_OPTION_FILTER, filter); |
---|
| 659 | } |
---|
| 660 | |
---|
| 661 | DLLEXPORT int trace_set_meta_freq(libtrace_t *trace, int freq) { |
---|
| 662 | return trace_config(trace, TRACE_OPTION_META_FREQ, &freq); |
---|
| 663 | } |
---|
| 664 | |
---|
| 665 | DLLEXPORT int trace_set_event_realtime(libtrace_t *trace, bool realtime) { |
---|
| 666 | int tmp = realtime; |
---|
| 667 | return trace_config(trace, TRACE_OPTION_EVENT_REALTIME, &tmp); |
---|
| 668 | } |
---|
| 669 | |
---|
[e6d963c] | 670 | DLLEXPORT int trace_config_output(libtrace_out_t *libtrace, |
---|
[7068467] | 671 | trace_option_output_t option, |
---|
| 672 | void *value) { |
---|
[9636216] | 673 | |
---|
[eda2def] | 674 | /* Unlike the input options, libtrace does not natively support any of |
---|
| 675 | * the output options - the format module must be able to deal with |
---|
| 676 | * them. */ |
---|
[9c6aa95] | 677 | if (libtrace->format->config_output) { |
---|
[7068467] | 678 | return libtrace->format->config_output(libtrace, option, value); |
---|
[9c6aa95] | 679 | } |
---|
| 680 | return -1; |
---|
[5eae97a] | 681 | } |
---|
| 682 | |
---|
[eda2def] | 683 | /* Close an input trace file, freeing up any resources it may have been using |
---|
[2c060e3] | 684 | * |
---|
| 685 | */ |
---|
[e6d963c] | 686 | DLLEXPORT void trace_destroy(libtrace_t *libtrace) { |
---|
[04bf7c5] | 687 | int i; |
---|
[9857d1c] | 688 | assert(libtrace); |
---|
| 689 | |
---|
[04bf7c5] | 690 | ASSERT_RET(pthread_mutex_destroy(&libtrace->libtrace_lock), == 0); |
---|
[5e3f16c] | 691 | ASSERT_RET(pthread_mutex_destroy(&libtrace->read_packet_lock), == 0); |
---|
[04bf7c5] | 692 | ASSERT_RET(pthread_cond_destroy(&libtrace->perpkt_cond), == 0); |
---|
| 693 | |
---|
| 694 | /* destroy any packets that are still around */ |
---|
[c99b1e5] | 695 | if (libtrace->state != STATE_NEW && libtrace->first_packets.packets) { |
---|
[9857d1c] | 696 | for (i = 0; i < libtrace->perpkt_thread_count; ++i) { |
---|
| 697 | if(libtrace->first_packets.packets[i].packet) { |
---|
| 698 | trace_destroy_packet(libtrace->first_packets.packets[i].packet); |
---|
| 699 | } |
---|
| 700 | } |
---|
| 701 | free(libtrace->first_packets.packets); |
---|
[a49a9eb] | 702 | ASSERT_RET(pthread_spin_destroy(&libtrace->first_packets.lock), == 0); |
---|
[9857d1c] | 703 | } |
---|
| 704 | |
---|
[2fa43fa] | 705 | /* Finish any the last packet we read - for backwards compatibility */ |
---|
[adb2c4c] | 706 | if (!libtrace_parallel && libtrace->last_packet) { |
---|
[2fa43fa] | 707 | trace_fin_packet(libtrace->last_packet); |
---|
[903f64d] | 708 | } |
---|
[2fa43fa] | 709 | assert(libtrace->last_packet == NULL); |
---|
| 710 | |
---|
[4e65f42] | 711 | if (libtrace->format) { |
---|
| 712 | if (libtrace->started && libtrace->format->pause_input) |
---|
| 713 | libtrace->format->pause_input(libtrace); |
---|
[528eb6e] | 714 | if (libtrace->format->fin_input) |
---|
| 715 | libtrace->format->fin_input(libtrace); |
---|
[4e65f42] | 716 | } |
---|
[29bbef0] | 717 | /* Need to free things! */ |
---|
| 718 | if (libtrace->uridata) |
---|
[4e65f42] | 719 | free(libtrace->uridata); |
---|
[5ab626a] | 720 | |
---|
| 721 | if (libtrace->stats) |
---|
| 722 | free(libtrace->stats); |
---|
[29bbef0] | 723 | |
---|
| 724 | /* Empty any packet memory */ |
---|
[c99b1e5] | 725 | if (libtrace->state != STATE_NEW) { |
---|
[a49a9eb] | 726 | // This has all of our packets |
---|
| 727 | libtrace_ocache_destroy(&libtrace->packet_freelist); |
---|
[92a2bf6] | 728 | for (i = 0; i < libtrace->perpkt_thread_count; ++i) { |
---|
[dc27de3] | 729 | libtrace_message_queue_destroy(&libtrace->perpkt_threads[i].messages); |
---|
| 730 | } |
---|
| 731 | if (libtrace->hasher_thread.type == THREAD_HASHER) |
---|
| 732 | libtrace_message_queue_destroy(&libtrace->hasher_thread.messages); |
---|
| 733 | if (libtrace->keepalive_thread.type == THREAD_KEEPALIVE) |
---|
| 734 | libtrace_message_queue_destroy(&libtrace->keepalive_thread.messages); |
---|
| 735 | if (libtrace->reporter_thread.type == THREAD_REPORTER) |
---|
| 736 | libtrace_message_queue_destroy(&libtrace->reporter_thread.messages); |
---|
[92a2bf6] | 737 | |
---|
| 738 | |
---|
[f625817] | 739 | if (libtrace->combiner.destroy && libtrace->reporter_cbs) |
---|
[2498008] | 740 | libtrace->combiner.destroy(libtrace, &libtrace->combiner); |
---|
[c99b1e5] | 741 | free(libtrace->perpkt_threads); |
---|
| 742 | libtrace->perpkt_threads = NULL; |
---|
| 743 | libtrace->perpkt_thread_count = 0; |
---|
[f625817] | 744 | |
---|
[29bbef0] | 745 | } |
---|
[f625817] | 746 | |
---|
[e375e0f] | 747 | if (libtrace->hasher_owner == HASH_OWNED_LIBTRACE) { |
---|
| 748 | if (libtrace->hasher_data) { |
---|
| 749 | free(libtrace->hasher_data); |
---|
| 750 | } |
---|
| 751 | } |
---|
| 752 | |
---|
| 753 | |
---|
[f625817] | 754 | if (libtrace->perpkt_cbs) |
---|
| 755 | trace_destroy_callback_set(libtrace->perpkt_cbs); |
---|
| 756 | if (libtrace->reporter_cbs) |
---|
| 757 | trace_destroy_callback_set(libtrace->reporter_cbs); |
---|
| 758 | |
---|
[1935565] | 759 | if (libtrace->event.packet) { |
---|
| 760 | /* Don't use trace_destroy_packet here - there is almost |
---|
| 761 | * certainly going to be another libtrace_packet_t that is |
---|
| 762 | * pointing to the buffer for this packet, so we don't want |
---|
| 763 | * to free it. Rather, it will get freed when the user calls |
---|
| 764 | * trace_destroy_packet on the libtrace_packet_t that they |
---|
| 765 | * own. |
---|
| 766 | * |
---|
| 767 | * All we need to do then is free our packet structure itself. |
---|
| 768 | */ |
---|
| 769 | free(libtrace->event.packet); |
---|
| 770 | } |
---|
[903f64d] | 771 | |
---|
[9857d1c] | 772 | free(libtrace); |
---|
[2c060e3] | 773 | } |
---|
| 774 | |
---|
[084d95a] | 775 | |
---|
[e6d963c] | 776 | DLLEXPORT void trace_destroy_dead(libtrace_t *libtrace) { |
---|
[084d95a] | 777 | assert(libtrace); |
---|
[eda2def] | 778 | |
---|
[04bf7c5] | 779 | ASSERT_RET(pthread_mutex_destroy(&libtrace->libtrace_lock), == 0); |
---|
[5e3f16c] | 780 | ASSERT_RET(pthread_mutex_destroy(&libtrace->read_packet_lock), == 0); |
---|
[04bf7c5] | 781 | ASSERT_RET(pthread_cond_destroy(&libtrace->perpkt_cond), == 0); |
---|
| 782 | |
---|
[eda2def] | 783 | /* Don't call pause_input or fin_input, because we should never have |
---|
| 784 | * used this trace to do any reading anyway. Do make sure we free |
---|
| 785 | * any format_data that has been created, though. */ |
---|
[f0fb38f] | 786 | if (libtrace->format_data) |
---|
| 787 | free(libtrace->format_data); |
---|
[084d95a] | 788 | free(libtrace); |
---|
| 789 | } |
---|
[fba4ca0] | 790 | /* Close an output trace file, freeing up any resources it may have been using |
---|
[5eae97a] | 791 | * |
---|
| 792 | * @param libtrace the output trace file to be destroyed |
---|
[eda2def] | 793 | */ |
---|
[9636216] | 794 | DLLEXPORT void trace_destroy_output(libtrace_out_t *libtrace) |
---|
[33d83d4] | 795 | { |
---|
[5eae97a] | 796 | assert(libtrace); |
---|
[9e6b38b] | 797 | if (libtrace->format && libtrace->format->fin_output) |
---|
[61b4543] | 798 | libtrace->format->fin_output(libtrace); |
---|
[52cc59f] | 799 | if (libtrace->uridata) |
---|
| 800 | free(libtrace->uridata); |
---|
[5eae97a] | 801 | free(libtrace); |
---|
| 802 | } |
---|
| 803 | |
---|
[a49a9eb] | 804 | DLLEXPORT libtrace_packet_t *trace_create_packet(void) |
---|
[33d83d4] | 805 | { |
---|
[a49a9eb] | 806 | libtrace_packet_t *packet = |
---|
[4bd8a5b] | 807 | (libtrace_packet_t*)calloc((size_t)1,sizeof(libtrace_packet_t)); |
---|
[7c72e4d] | 808 | |
---|
[fd4482d] | 809 | if (packet == NULL) |
---|
| 810 | return NULL; |
---|
| 811 | |
---|
[c1db742] | 812 | packet->buf_control=TRACE_CTRL_PACKET; |
---|
[c1205bd] | 813 | pthread_mutex_init(&(packet->ref_lock), NULL); |
---|
[9cc1266] | 814 | trace_clear_cache(packet); |
---|
[14d8a63] | 815 | return packet; |
---|
| 816 | } |
---|
| 817 | |
---|
[39e141f] | 818 | DLLEXPORT libtrace_packet_t *trace_copy_packet(const libtrace_packet_t *packet) { |
---|
[67a14d4] | 819 | libtrace_packet_t *dest = |
---|
[d391ce0] | 820 | (libtrace_packet_t *)calloc((size_t)1, sizeof(libtrace_packet_t)); |
---|
[ca1272c] | 821 | if (!dest) { |
---|
[eda2def] | 822 | printf("Out of memory constructing packet\n"); |
---|
[ca1272c] | 823 | abort(); |
---|
| 824 | } |
---|
[91c9552] | 825 | dest->trace=packet->trace; |
---|
[9bc4689] | 826 | dest->buffer=malloc(65536); |
---|
[ca1272c] | 827 | if (!dest->buffer) { |
---|
[eda2def] | 828 | printf("Out of memory allocating buffer memory\n"); |
---|
[ca1272c] | 829 | abort(); |
---|
| 830 | } |
---|
[91c9552] | 831 | dest->header=dest->buffer; |
---|
| 832 | dest->payload=(void*) |
---|
| 833 | ((char*)dest->buffer+trace_get_framing_length(packet)); |
---|
| 834 | dest->type=packet->type; |
---|
| 835 | dest->buf_control=TRACE_CTRL_PACKET; |
---|
[29bbef0] | 836 | dest->order = packet->order; |
---|
[d994324] | 837 | dest->hash = packet->hash; |
---|
| 838 | dest->error = packet->error; |
---|
[e1fdc05] | 839 | /* Reset the cache - better to recalculate than try to convert |
---|
| 840 | * the values over to the new packet */ |
---|
[9636216] | 841 | trace_clear_cache(dest); |
---|
[eda2def] | 842 | /* Ooooh nasty memcpys! This is why we want to avoid copying packets |
---|
| 843 | * as much as possible */ |
---|
[91c9552] | 844 | memcpy(dest->header,packet->header,trace_get_framing_length(packet)); |
---|
| 845 | memcpy(dest->payload,packet->payload,trace_get_capture_length(packet)); |
---|
[d8f02df] | 846 | |
---|
| 847 | return dest; |
---|
[91c9552] | 848 | } |
---|
| 849 | |
---|
[14d8a63] | 850 | /** Destroy a packet object |
---|
| 851 | */ |
---|
[e2aebe7] | 852 | DLLEXPORT void trace_destroy_packet(libtrace_packet_t *packet) { |
---|
[29bbef0] | 853 | /* Free any resources possibly associated with the packet */ |
---|
[60e8e86] | 854 | if (libtrace_parallel && packet->trace && packet->trace->format->fin_packet) { |
---|
[29bbef0] | 855 | packet->trace->format->fin_packet(packet); |
---|
| 856 | } |
---|
[adb2c4c] | 857 | if (!libtrace_parallel && packet->trace && |
---|
| 858 | packet->trace->last_packet == packet) { |
---|
[9a3a846] | 859 | packet->trace->last_packet = NULL; |
---|
[adb2c4c] | 860 | } |
---|
[29bbef0] | 861 | |
---|
[1935565] | 862 | if (packet->buf_control == TRACE_CTRL_PACKET && packet->buffer) { |
---|
[e2aebe7] | 863 | free(packet->buffer); |
---|
| 864 | } |
---|
[c1205bd] | 865 | pthread_mutex_destroy(&(packet->ref_lock)); |
---|
[9636216] | 866 | packet->buf_control=(buf_control_t)'\0'; |
---|
[eda2def] | 867 | /* A "bad" value to force an assert |
---|
[85a79b0] | 868 | * if this packet is ever reused |
---|
| 869 | */ |
---|
[e2aebe7] | 870 | free(packet); |
---|
[85e87b5] | 871 | } |
---|
[14d8a63] | 872 | |
---|
[29bbef0] | 873 | /** |
---|
| 874 | * Removes any possible data stored againt the trace and releases any data. |
---|
| 875 | * This will not destroy a reusable good malloc'd buffer (TRACE_CTRL_PACKET) |
---|
| 876 | * use trace_destroy_packet() for those diabolical purposes. |
---|
| 877 | */ |
---|
| 878 | void trace_fin_packet(libtrace_packet_t *packet) { |
---|
| 879 | if (packet) |
---|
| 880 | { |
---|
| 881 | if (packet->trace && packet->trace->format->fin_packet) { |
---|
| 882 | packet->trace->format->fin_packet(packet); |
---|
| 883 | } |
---|
[d391ce0] | 884 | |
---|
| 885 | if (packet->srcbucket && packet->internalid != 0) { |
---|
| 886 | libtrace_bucket_t *b = (libtrace_bucket_t *)packet->srcbucket; |
---|
| 887 | libtrace_release_bucket_id(b, packet->internalid); |
---|
| 888 | } |
---|
| 889 | |
---|
[348396b] | 890 | if (packet->trace) { |
---|
[adb2c4c] | 891 | if (!libtrace_parallel && packet->trace->last_packet == packet) |
---|
| 892 | packet->trace->last_packet = NULL; |
---|
[348396b] | 893 | } |
---|
[29bbef0] | 894 | |
---|
| 895 | // No matter what we remove the header and link pointers |
---|
| 896 | packet->trace = NULL; |
---|
| 897 | packet->header = NULL; |
---|
| 898 | packet->payload = NULL; |
---|
| 899 | |
---|
| 900 | if (packet->buf_control != TRACE_CTRL_PACKET) |
---|
| 901 | { |
---|
| 902 | packet->buffer = NULL; |
---|
| 903 | } |
---|
| 904 | |
---|
[bdc8b36] | 905 | trace_clear_cache(packet); |
---|
[29bbef0] | 906 | packet->hash = 0; |
---|
| 907 | packet->order = 0; |
---|
[348396b] | 908 | packet->srcbucket = NULL; |
---|
[29bbef0] | 909 | } |
---|
| 910 | } |
---|
| 911 | |
---|
[eda2def] | 912 | /* Read one packet from the trace into buffer. Note that this function will |
---|
| 913 | * block until a packet is read (or EOF is reached). |
---|
[2c060e3] | 914 | * |
---|
[9636216] | 915 | * @param libtrace the libtrace opaque pointer |
---|
| 916 | * @param packet the packet opaque pointer |
---|
[fba4ca0] | 917 | * @returns 0 on EOF, negative value on error |
---|
[2c060e3] | 918 | * |
---|
| 919 | */ |
---|
[39e141f] | 920 | DLLEXPORT int trace_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) { |
---|
[2137b49] | 921 | |
---|
[37195b4] | 922 | assert(libtrace && "You called trace_read_packet() with a NULL libtrace parameter!\n"); |
---|
[8f18776] | 923 | if (trace_is_err(libtrace)) |
---|
| 924 | return -1; |
---|
| 925 | if (!libtrace->started) { |
---|
| 926 | trace_set_err(libtrace,TRACE_ERR_BAD_STATE,"You must call libtrace_start() before trace_read_packet()\n"); |
---|
| 927 | return -1; |
---|
| 928 | } |
---|
[9636216] | 929 | if (!(packet->buf_control==TRACE_CTRL_PACKET |
---|
| 930 | || packet->buf_control==TRACE_CTRL_EXTERNAL)) { |
---|
[8f18776] | 931 | trace_set_err(libtrace,TRACE_ERR_BAD_STATE,"Packet passed to trace_read_packet() is invalid\n"); |
---|
| 932 | return -1; |
---|
| 933 | } |
---|
[37195b4] | 934 | assert(packet); |
---|
[7c72e4d] | 935 | |
---|
[4dedc28] | 936 | if (libtrace->format->read_packet) { |
---|
[348396b] | 937 | /* Finalise the packet, freeing any resources the format module |
---|
| 938 | * may have allocated it and zeroing all data associated with it. |
---|
| 939 | */ |
---|
[903f64d] | 940 | if (packet->trace == libtrace) { |
---|
[348396b] | 941 | trace_fin_packet(packet); |
---|
[903f64d] | 942 | } |
---|
[880aa58] | 943 | do { |
---|
[a7d1914] | 944 | size_t ret; |
---|
[9e429e8] | 945 | int filtret; |
---|
[5e3f16c] | 946 | if ((ret=is_halted(libtrace)) != (size_t)-1) |
---|
| 947 | return ret; |
---|
[29bbef0] | 948 | /* Store the trace we are reading from into the packet opaque |
---|
| 949 | * structure */ |
---|
| 950 | packet->trace = libtrace; |
---|
[a7d1914] | 951 | ret=libtrace->format->read_packet(libtrace,packet); |
---|
[5e3f16c] | 952 | if (ret==(size_t)READ_MESSAGE || |
---|
| 953 | ret==(size_t)-1 || ret==0) { |
---|
[903f64d] | 954 | packet->trace = NULL; |
---|
[a7d1914] | 955 | return ret; |
---|
[222d8f5] | 956 | } |
---|
[348396b] | 957 | if (libtrace->filter) { |
---|
[880aa58] | 958 | /* If the filter doesn't match, read another |
---|
| 959 | * packet |
---|
| 960 | */ |
---|
[b8d8186] | 961 | filtret = trace_apply_filter(libtrace->filter, packet); |
---|
| 962 | if (filtret == -1) { |
---|
| 963 | /* Error compiling filter, probably */ |
---|
| 964 | return ~0U; |
---|
| 965 | } |
---|
[348396b] | 966 | |
---|
[b8d8186] | 967 | if (filtret == 0) { |
---|
[9d3c721] | 968 | ++libtrace->filtered_packets; |
---|
[348396b] | 969 | trace_fin_packet(packet); |
---|
| 970 | continue; |
---|
[880aa58] | 971 | } |
---|
| 972 | } |
---|
| 973 | if (libtrace->snaplen>0) { |
---|
| 974 | /* Snap the packet */ |
---|
| 975 | trace_set_capture_length(packet, |
---|
| 976 | libtrace->snaplen); |
---|
| 977 | } |
---|
[ed5b2ce] | 978 | if (!IS_LIBTRACE_META_PACKET(packet)) { |
---|
| 979 | ++libtrace->accepted_packets; |
---|
| 980 | } |
---|
[91e016c] | 981 | trace_packet_set_order(packet, libtrace->sequence_number); |
---|
[ed5b2ce] | 982 | ++libtrace->sequence_number; |
---|
[adb2c4c] | 983 | if (!libtrace_parallel && packet->trace == libtrace) |
---|
[0a368ae] | 984 | libtrace->last_packet = packet; |
---|
[348396b] | 985 | |
---|
[a7d1914] | 986 | return ret; |
---|
[880aa58] | 987 | } while(1); |
---|
[a22c979] | 988 | } |
---|
[91db67b] | 989 | trace_set_err(libtrace,TRACE_ERR_UNSUPPORTED,"This format does not support reading packets\n"); |
---|
[85a79b0] | 990 | return ~0U; |
---|
[2c060e3] | 991 | } |
---|
| 992 | |
---|
[eda2def] | 993 | /* Converts the provided buffer into a libtrace packet of the given type. |
---|
| 994 | * |
---|
| 995 | * Unlike trace_construct_packet, the buffer is expected to begin with the |
---|
| 996 | * appropriate capture format header for the format type that the packet is |
---|
| 997 | * being converted to. This also allows for a packet to be converted into |
---|
[9636216] | 998 | * just about capture format that is supported by libtrace, provided the |
---|
[eda2def] | 999 | * format header is present in the buffer. |
---|
| 1000 | * |
---|
| 1001 | * This function is primarily used to convert packets received via the RT |
---|
| 1002 | * protocol back into their original capture format. The RT header encapsulates |
---|
[9636216] | 1003 | * the original capture format header, so after removing it the packet must |
---|
[eda2def] | 1004 | * have it's header and payload pointers updated and the packet format and type |
---|
| 1005 | * changed, amongst other things. |
---|
| 1006 | * |
---|
[9636216] | 1007 | * Intended only for internal use at this point - this function is not |
---|
[eda2def] | 1008 | * available through the external libtrace API. |
---|
| 1009 | */ |
---|
[f0fb38f] | 1010 | int trace_prepare_packet(libtrace_t *trace, libtrace_packet_t *packet, |
---|
| 1011 | void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) { |
---|
| 1012 | |
---|
| 1013 | assert(packet); |
---|
| 1014 | assert(trace); |
---|
[9636216] | 1015 | |
---|
[f0fb38f] | 1016 | /* XXX Proper error handling?? */ |
---|
| 1017 | if (buffer == NULL) |
---|
| 1018 | return -1; |
---|
| 1019 | |
---|
| 1020 | if (!(packet->buf_control==TRACE_CTRL_PACKET || packet->buf_control==TRACE_CTRL_EXTERNAL)) { |
---|
| 1021 | trace_set_err(trace,TRACE_ERR_BAD_STATE,"Packet passed to trace_read_packet() is invalid\n"); |
---|
| 1022 | return -1; |
---|
| 1023 | } |
---|
[9636216] | 1024 | |
---|
[f0fb38f] | 1025 | packet->trace = trace; |
---|
[adb2c4c] | 1026 | if (!libtrace_parallel) |
---|
| 1027 | trace->last_packet = packet; |
---|
[f0fb38f] | 1028 | /* Clear packet cache */ |
---|
[9cc1266] | 1029 | trace_clear_cache(packet); |
---|
[f0fb38f] | 1030 | |
---|
| 1031 | if (trace->format->prepare_packet) { |
---|
| 1032 | return trace->format->prepare_packet(trace, packet, |
---|
| 1033 | buffer, rt_type, flags); |
---|
| 1034 | } |
---|
[9636216] | 1035 | trace_set_err(trace, TRACE_ERR_UNSUPPORTED, |
---|
[f0fb38f] | 1036 | "This format does not support preparing packets\n"); |
---|
| 1037 | return -1; |
---|
| 1038 | |
---|
| 1039 | } |
---|
| 1040 | |
---|
[eda2def] | 1041 | /* Writes a packet to the specified output trace |
---|
[5eae97a] | 1042 | * |
---|
| 1043 | * @param libtrace describes the output format, destination, etc. |
---|
| 1044 | * @param packet the packet to be written out |
---|
| 1045 | * @returns the number of bytes written, -1 if write failed |
---|
[eda2def] | 1046 | */ |
---|
[3a169d7] | 1047 | DLLEXPORT int trace_write_packet(libtrace_out_t *libtrace, libtrace_packet_t *packet) { |
---|
[5eae97a] | 1048 | assert(libtrace); |
---|
[5b4d121] | 1049 | assert(packet); |
---|
[a8a9355] | 1050 | /* Verify the packet is valid */ |
---|
[8f18776] | 1051 | if (!libtrace->started) { |
---|
| 1052 | trace_set_err_out(libtrace,TRACE_ERR_BAD_STATE, |
---|
| 1053 | "Trace is not started before trace_write_packet"); |
---|
| 1054 | return -1; |
---|
| 1055 | } |
---|
[5eae97a] | 1056 | |
---|
[ed5b2ce] | 1057 | /* Don't try to convert meta-packets across formats */ |
---|
| 1058 | if (strcmp(libtrace->format->name, packet->trace->format->name) != 0 && |
---|
| 1059 | IS_LIBTRACE_META_PACKET(packet)) { |
---|
| 1060 | return 0; |
---|
| 1061 | } |
---|
| 1062 | |
---|
[1fc2f6a] | 1063 | if (libtrace->format->write_packet) { |
---|
| 1064 | return libtrace->format->write_packet(libtrace, packet); |
---|
[5eae97a] | 1065 | } |
---|
[8a1fb3c] | 1066 | trace_set_err_out(libtrace,TRACE_ERR_UNSUPPORTED, |
---|
| 1067 | "This format does not support writing packets"); |
---|
[9c6aa95] | 1068 | return -1; |
---|
[5eae97a] | 1069 | } |
---|
[2c060e3] | 1070 | |
---|
[eda2def] | 1071 | /* Get a pointer to the first byte of the packet payload */ |
---|
[180f095] | 1072 | DLLEXPORT void *trace_get_packet_buffer(const libtrace_packet_t *packet, |
---|
| 1073 | libtrace_linktype_t *linktype, uint32_t *remaining) { |
---|
[b185327] | 1074 | int cap_len; |
---|
| 1075 | int wire_len; |
---|
| 1076 | |
---|
[180f095] | 1077 | assert(packet != NULL); |
---|
| 1078 | if (linktype) *linktype = trace_get_link_type(packet); |
---|
[b185327] | 1079 | if (remaining) { |
---|
| 1080 | /* I think we should choose the minimum of the capture and |
---|
| 1081 | * wire lengths to be the "remaining" value. If the packet has |
---|
| 1082 | * been padded to increase the capture length, we don't want |
---|
[9636216] | 1083 | * to allow subsequent protocol decoders to consider the |
---|
[b185327] | 1084 | * padding as part of the packet. |
---|
| 1085 | * |
---|
| 1086 | * For example, in Auck 4 there is a trace where the IP header |
---|
| 1087 | * length is incorrect (24 bytes) followed by a 20 byte TCP |
---|
| 1088 | * header. Total IP length is 40 bytes. As a result, the |
---|
| 1089 | * legacyatm padding gets treated as the "missing" bytes of |
---|
| 1090 | * the TCP header, which isn't the greatest. We're probably |
---|
| 1091 | * better off returning an incomplete TCP header in that case. |
---|
| 1092 | */ |
---|
[9636216] | 1093 | |
---|
[b185327] | 1094 | cap_len = trace_get_capture_length(packet); |
---|
| 1095 | wire_len = trace_get_wire_length(packet); |
---|
| 1096 | |
---|
[d3320d1] | 1097 | assert(cap_len >= 0); |
---|
| 1098 | |
---|
| 1099 | /* There is the odd corrupt packet, e.g. in IPLS II, that have |
---|
| 1100 | * massively negative wire lens. We could assert fail here on |
---|
| 1101 | * them, but we could at least try the capture length instead. |
---|
[9636216] | 1102 | * |
---|
[d3320d1] | 1103 | * You may still run into problems if you try to write that |
---|
| 1104 | * packet, but at least reading should work OK. |
---|
| 1105 | */ |
---|
| 1106 | if (wire_len < 0) |
---|
| 1107 | *remaining = cap_len; |
---|
| 1108 | else if (wire_len < cap_len) |
---|
[b185327] | 1109 | *remaining = wire_len; |
---|
| 1110 | else |
---|
| 1111 | *remaining = cap_len; |
---|
| 1112 | /* *remaining = trace_get_capture_length(packet); */ |
---|
| 1113 | } |
---|
[180f095] | 1114 | return (void *) packet->payload; |
---|
| 1115 | } |
---|
| 1116 | |
---|
[eda2def] | 1117 | |
---|
[9636216] | 1118 | /* Get a pointer to the first byte of the packet payload |
---|
[eda2def] | 1119 | * |
---|
| 1120 | * DEPRECATED - use trace_get_packet_buffer() instead */ |
---|
[e6d963c] | 1121 | DLLEXPORT void *trace_get_link(const libtrace_packet_t *packet) { |
---|
[14d8a63] | 1122 | return (void *)packet->payload; |
---|
[2c060e3] | 1123 | } |
---|
| 1124 | |
---|
[9636216] | 1125 | /* Get the current time in DAG time format |
---|
| 1126 | * @param packet a pointer to a libtrace_packet structure |
---|
[2c060e3] | 1127 | * @returns a 64 bit timestamp in DAG ERF format (upper 32 bits are the seconds |
---|
| 1128 | * past 1970-01-01, the lower 32bits are partial seconds) |
---|
[9636216] | 1129 | */ |
---|
[39e141f] | 1130 | DLLEXPORT uint64_t trace_get_erf_timestamp(const libtrace_packet_t *packet) { |
---|
[4dedc28] | 1131 | if (packet->trace->format->get_erf_timestamp) { |
---|
[7068467] | 1132 | /* timestamp -> timestamp */ |
---|
[1aa4bf7] | 1133 | return packet->trace->format->get_erf_timestamp(packet); |
---|
| 1134 | } else if (packet->trace->format->get_timespec) { |
---|
| 1135 | /* timespec -> timestamp */ |
---|
| 1136 | struct timespec ts; |
---|
| 1137 | ts = packet->trace->format->get_timespec(packet); |
---|
| 1138 | return ((((uint64_t)ts.tv_sec) << 32) + |
---|
| 1139 | (((uint64_t)ts.tv_nsec << 32)/1000000000)); |
---|
[4dedc28] | 1140 | } else if (packet->trace->format->get_timeval) { |
---|
[7068467] | 1141 | /* timeval -> timestamp */ |
---|
[1aa4bf7] | 1142 | struct timeval tv; |
---|
| 1143 | tv = packet->trace->format->get_timeval(packet); |
---|
| 1144 | return ((((uint64_t)tv.tv_sec) << 32) + |
---|
| 1145 | (((uint64_t)tv.tv_usec << 32)/1000000)); |
---|
[ca87bcd] | 1146 | } else if (packet->trace->format->get_seconds) { |
---|
[7068467] | 1147 | /* seconds -> timestamp */ |
---|
[1aa4bf7] | 1148 | double seconds = packet->trace->format->get_seconds(packet); |
---|
| 1149 | return (((uint64_t)seconds)<<32) |
---|
[4569c93] | 1150 | + (uint64_t)((seconds-(uint64_t)seconds)*UINT_MAX); |
---|
[ca87bcd] | 1151 | } |
---|
[1aa4bf7] | 1152 | else { |
---|
| 1153 | return (uint64_t)0; |
---|
| 1154 | } |
---|
[2c060e3] | 1155 | } |
---|
| 1156 | |
---|
[fba4ca0] | 1157 | /* Get the current time in struct timeval |
---|
[850630f] | 1158 | * @param packet a pointer to a libtrace_packet structure |
---|
| 1159 | * |
---|
[2c060e3] | 1160 | * @returns time that this packet was seen in a struct timeval |
---|
| 1161 | * @author Daniel Lawson |
---|
| 1162 | * @author Perry Lorier |
---|
[9636216] | 1163 | */ |
---|
[39e141f] | 1164 | DLLEXPORT struct timeval trace_get_timeval(const libtrace_packet_t *packet) { |
---|
[2c060e3] | 1165 | struct timeval tv; |
---|
[4dedc28] | 1166 | uint64_t ts = 0; |
---|
| 1167 | if (packet->trace->format->get_timeval) { |
---|
[7068467] | 1168 | /* timeval -> timeval */ |
---|
[4dedc28] | 1169 | tv = packet->trace->format->get_timeval(packet); |
---|
| 1170 | } else if (packet->trace->format->get_erf_timestamp) { |
---|
[7068467] | 1171 | /* timestamp -> timeval */ |
---|
[4dedc28] | 1172 | ts = packet->trace->format->get_erf_timestamp(packet); |
---|
| 1173 | tv.tv_sec = ts >> 32; |
---|
[11041eb] | 1174 | tv.tv_usec = ((ts&0xFFFFFFFF)*1000000)>>32; |
---|
[9636216] | 1175 | if (tv.tv_usec >= 1000000) { |
---|
| 1176 | tv.tv_usec -= 1000000; |
---|
| 1177 | tv.tv_sec += 1; |
---|
| 1178 | } |
---|
[1aa4bf7] | 1179 | } else if (packet->trace->format->get_timespec) { |
---|
| 1180 | struct timespec ts = packet->trace->format->get_timespec(packet); |
---|
| 1181 | tv.tv_sec = ts.tv_sec; |
---|
| 1182 | tv.tv_usec = ts.tv_nsec/1000; |
---|
[ca87bcd] | 1183 | } else if (packet->trace->format->get_seconds) { |
---|
[7068467] | 1184 | /* seconds -> timeval */ |
---|
[1aa4bf7] | 1185 | double seconds = packet->trace->format->get_seconds(packet); |
---|
[ca87bcd] | 1186 | tv.tv_sec = (uint32_t)seconds; |
---|
| 1187 | tv.tv_usec = (uint32_t)(((seconds - tv.tv_sec) * 1000000)/UINT_MAX); |
---|
[4dedc28] | 1188 | } |
---|
[302714f] | 1189 | else { |
---|
| 1190 | tv.tv_sec=-1; |
---|
| 1191 | tv.tv_usec=-1; |
---|
| 1192 | } |
---|
[4dedc28] | 1193 | |
---|
[29bbef0] | 1194 | return tv; |
---|
[2c060e3] | 1195 | } |
---|
| 1196 | |
---|
[1aa4bf7] | 1197 | DLLEXPORT struct timespec trace_get_timespec(const libtrace_packet_t *packet) { |
---|
| 1198 | struct timespec ts; |
---|
| 1199 | |
---|
| 1200 | if (packet->trace->format->get_timespec) { |
---|
| 1201 | return packet->trace->format->get_timespec(packet); |
---|
| 1202 | } else if (packet->trace->format->get_erf_timestamp) { |
---|
| 1203 | /* timestamp -> timeval */ |
---|
| 1204 | uint64_t erfts = packet->trace->format->get_erf_timestamp(packet); |
---|
| 1205 | ts.tv_sec = erfts >> 32; |
---|
[11041eb] | 1206 | ts.tv_nsec = ((erfts&0xFFFFFFFF)*1000000000)>>32; |
---|
[9636216] | 1207 | if (ts.tv_nsec >= 1000000000) { |
---|
| 1208 | ts.tv_nsec -= 1000000000; |
---|
| 1209 | ts.tv_sec += 1; |
---|
| 1210 | } |
---|
[1aa4bf7] | 1211 | return ts; |
---|
| 1212 | } else if (packet->trace->format->get_timeval) { |
---|
| 1213 | /* timeval -> timespec */ |
---|
| 1214 | struct timeval tv = packet->trace->format->get_timeval(packet); |
---|
| 1215 | ts.tv_sec = tv.tv_sec; |
---|
| 1216 | ts.tv_nsec = tv.tv_usec*1000; |
---|
| 1217 | return ts; |
---|
| 1218 | } else if (packet->trace->format->get_seconds) { |
---|
| 1219 | /* seconds -> timespec */ |
---|
| 1220 | double seconds = packet->trace->format->get_seconds(packet); |
---|
| 1221 | ts.tv_sec = (uint32_t)seconds; |
---|
| 1222 | ts.tv_nsec = (long)(((seconds - ts.tv_sec) * 1000000000)/UINT_MAX); |
---|
| 1223 | return ts; |
---|
| 1224 | } |
---|
| 1225 | else { |
---|
| 1226 | ts.tv_sec=-1; |
---|
| 1227 | ts.tv_nsec=-1; |
---|
| 1228 | return ts; |
---|
| 1229 | } |
---|
| 1230 | } |
---|
| 1231 | |
---|
| 1232 | |
---|
[fba4ca0] | 1233 | /* Get the current time in floating point seconds |
---|
[9636216] | 1234 | * @param packet a pointer to a libtrace_packet structure |
---|
[2c060e3] | 1235 | * @returns time that this packet was seen in 64bit floating point seconds |
---|
[9636216] | 1236 | */ |
---|
[e6d963c] | 1237 | DLLEXPORT double trace_get_seconds(const libtrace_packet_t *packet) { |
---|
[9c6aa95] | 1238 | double seconds = 0.0; |
---|
[a8a9355] | 1239 | |
---|
[4dedc28] | 1240 | if (packet->trace->format->get_seconds) { |
---|
[7068467] | 1241 | /* seconds->seconds */ |
---|
[4dedc28] | 1242 | seconds = packet->trace->format->get_seconds(packet); |
---|
| 1243 | } else if (packet->trace->format->get_erf_timestamp) { |
---|
[7068467] | 1244 | /* timestamp -> seconds */ |
---|
[1aa4bf7] | 1245 | uint64_t ts = 0; |
---|
[4dedc28] | 1246 | ts = packet->trace->format->get_erf_timestamp(packet); |
---|
| 1247 | seconds = (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX); |
---|
[1aa4bf7] | 1248 | } else if (packet->trace->format->get_timespec) { |
---|
| 1249 | /* timespec -> seconds */ |
---|
| 1250 | struct timespec ts; |
---|
| 1251 | ts = packet->trace->format->get_timespec(packet); |
---|
| 1252 | seconds = ts.tv_sec + ((ts.tv_nsec * 1.0) / 1000000000); |
---|
[ca87bcd] | 1253 | } else if (packet->trace->format->get_timeval) { |
---|
[7068467] | 1254 | /* timeval -> seconds */ |
---|
[1aa4bf7] | 1255 | struct timeval tv; |
---|
[ca87bcd] | 1256 | tv = packet->trace->format->get_timeval(packet); |
---|
[b51edf5] | 1257 | seconds = tv.tv_sec + ((tv.tv_usec * 1.0) / 1000000); |
---|
[ca87bcd] | 1258 | } |
---|
| 1259 | |
---|
[4dedc28] | 1260 | return seconds; |
---|
[2c060e3] | 1261 | } |
---|
| 1262 | |
---|
[9636216] | 1263 | DLLEXPORT size_t trace_get_capture_length(const libtrace_packet_t *packet) |
---|
[a7d1914] | 1264 | { |
---|
[7c72e4d] | 1265 | /* Cache the capture length */ |
---|
| 1266 | if (packet->capture_length == -1) { |
---|
| 1267 | if (!packet->trace->format->get_capture_length) |
---|
| 1268 | return ~0U; |
---|
[9bc4689] | 1269 | /* Cast away constness because this is "just" a cache */ |
---|
[9636216] | 1270 | ((libtrace_packet_t*)packet)->capture_length = |
---|
[7c72e4d] | 1271 | packet->trace->format->get_capture_length(packet); |
---|
[2c060e3] | 1272 | } |
---|
[7c72e4d] | 1273 | |
---|
[182d043] | 1274 | assert(packet->capture_length < LIBTRACE_PACKET_BUFSIZE); |
---|
| 1275 | |
---|
[7c72e4d] | 1276 | return packet->capture_length; |
---|
[2c060e3] | 1277 | } |
---|
[9636216] | 1278 | |
---|
[fba4ca0] | 1279 | /* Get the size of the packet as it was seen on the wire. |
---|
[850630f] | 1280 | * @param packet a pointer to a libtrace_packet structure |
---|
| 1281 | * |
---|
[2c060e3] | 1282 | * @returns the size of the packet as it was on the wire. |
---|
| 1283 | * @note Due to the trace being a header capture, or anonymisation this may |
---|
| 1284 | * not be the same as the Capture Len. |
---|
[9636216] | 1285 | */ |
---|
[39e141f] | 1286 | DLLEXPORT size_t trace_get_wire_length(const libtrace_packet_t *packet){ |
---|
[9636216] | 1287 | |
---|
[979a84f4] | 1288 | if (packet->wire_length == -1) { |
---|
[9636216] | 1289 | if (!packet->trace->format->get_wire_length) |
---|
[979a84f4] | 1290 | return ~0U; |
---|
[9636216] | 1291 | ((libtrace_packet_t *)packet)->wire_length = |
---|
[979a84f4] | 1292 | packet->trace->format->get_wire_length(packet); |
---|
[2c060e3] | 1293 | } |
---|
[979a84f4] | 1294 | |
---|
| 1295 | assert(packet->wire_length < LIBTRACE_PACKET_BUFSIZE); |
---|
| 1296 | return packet->wire_length; |
---|
[2c060e3] | 1297 | |
---|
| 1298 | } |
---|
| 1299 | |
---|
[7c8eacf] | 1300 | /* Get the length of the capture framing headers. |
---|
[9636216] | 1301 | * @param packet the packet opaque pointer |
---|
[7c8eacf] | 1302 | * @returns the size of the packet as it was on the wire. |
---|
[9636216] | 1303 | * @note this length corresponds to the difference between the size of a |
---|
[7c8eacf] | 1304 | * captured packet in memory, and the captured length of the packet |
---|
[9636216] | 1305 | */ |
---|
[39e141f] | 1306 | DLLEXPORT SIMPLE_FUNCTION |
---|
[d8f02df] | 1307 | size_t trace_get_framing_length(const libtrace_packet_t *packet) { |
---|
[7c8eacf] | 1308 | if (packet->trace->format->get_framing_length) { |
---|
| 1309 | return packet->trace->format->get_framing_length(packet); |
---|
| 1310 | } |
---|
[85a79b0] | 1311 | return ~0U; |
---|
[7c8eacf] | 1312 | } |
---|
| 1313 | |
---|
| 1314 | |
---|
[fba4ca0] | 1315 | /* Get the type of the link layer |
---|
[9636216] | 1316 | * @param packet a pointer to a libtrace_packet structure |
---|
[2c060e3] | 1317 | * @returns libtrace_linktype_t |
---|
| 1318 | */ |
---|
[39e141f] | 1319 | DLLEXPORT libtrace_linktype_t trace_get_link_type(const libtrace_packet_t *packet ) { |
---|
[979a84f4] | 1320 | |
---|
| 1321 | if (packet->link_type == 0) { |
---|
| 1322 | if (!packet->trace->format->get_link_type) |
---|
[f7bcbfb] | 1323 | return TRACE_TYPE_UNKNOWN; |
---|
[979a84f4] | 1324 | ((libtrace_packet_t *)packet)->link_type = |
---|
| 1325 | packet->trace->format->get_link_type(packet); |
---|
[2c060e3] | 1326 | } |
---|
[979a84f4] | 1327 | |
---|
| 1328 | return packet->link_type; |
---|
[2c060e3] | 1329 | } |
---|
| 1330 | |
---|
[fba4ca0] | 1331 | /* process a libtrace event |
---|
[ef36351d] | 1332 | * @param trace the libtrace opaque pointer |
---|
| 1333 | * @param packet the libtrace_packet opaque pointer |
---|
[2c060e3] | 1334 | * @returns |
---|
[68667ee] | 1335 | * TRACE_EVENT_IOWAIT Waiting on I/O on fd |
---|
| 1336 | * TRACE_EVENT_SLEEP Next event in seconds |
---|
| 1337 | * TRACE_EVENT_PACKET Packet arrived in buffer with size size |
---|
[7bb7dda] | 1338 | * TRACE_EVENT_TERMINATE Trace terminated (perhaps with an error condition) |
---|
[2137b49] | 1339 | * FIXME currently keeps a copy of the packet inside the trace pointer, |
---|
| 1340 | * which in turn is stored inside the new packet object... |
---|
[2c060e3] | 1341 | */ |
---|
[9636216] | 1342 | DLLEXPORT libtrace_eventobj_t trace_event(libtrace_t *trace, |
---|
[e6d963c] | 1343 | libtrace_packet_t *packet) { |
---|
| 1344 | libtrace_eventobj_t event = {TRACE_EVENT_IOWAIT,0,0.0,0}; |
---|
[4fd12ac] | 1345 | |
---|
| 1346 | if (!trace) { |
---|
| 1347 | fprintf(stderr,"You called trace_event() with a NULL trace object!\n"); |
---|
| 1348 | } |
---|
| 1349 | assert(trace); |
---|
| 1350 | assert(packet); |
---|
| 1351 | |
---|
[7718e54] | 1352 | /* Free the last packet */ |
---|
| 1353 | trace_fin_packet(packet); |
---|
[4fd12ac] | 1354 | /* Store the trace we are reading from into the packet opaque |
---|
| 1355 | * structure */ |
---|
| 1356 | packet->trace = trace; |
---|
| 1357 | |
---|
[72bfe20] | 1358 | if (packet->trace->format->trace_event) { |
---|
[c70f59f] | 1359 | /* Note: incrementing accepted, filtered etc. packet |
---|
[9636216] | 1360 | * counters is handled by the format-specific |
---|
[c70f59f] | 1361 | * function so don't increment them here. |
---|
| 1362 | */ |
---|
[9d3c721] | 1363 | event=packet->trace->format->trace_event(trace,packet); |
---|
| 1364 | } |
---|
| 1365 | return event; |
---|
[72bfe20] | 1366 | |
---|
[2c060e3] | 1367 | } |
---|
[c681e86] | 1368 | |
---|
[3a14f3b] | 1369 | /** Setup a BPF filter based on pre-compiled byte-code. |
---|
| 1370 | * @param bf_insns A pointer to the start of the byte-code |
---|
| 1371 | * @param bf_len The number of BPF instructions |
---|
| 1372 | * @returns an opaque pointer to a libtrace_filter_t object |
---|
| 1373 | * @note The supplied byte-code is not checked for correctness. |
---|
| 1374 | * @author Scott Raynel |
---|
| 1375 | */ |
---|
| 1376 | DLLEXPORT libtrace_filter_t * |
---|
| 1377 | trace_create_filter_from_bytecode(void *bf_insns, unsigned int bf_len) |
---|
| 1378 | { |
---|
[d47ca18] | 1379 | #ifndef HAVE_BPF |
---|
[3a14f3b] | 1380 | fprintf(stderr, "This version of libtrace does not have BPF support\n"); |
---|
| 1381 | return NULL; |
---|
| 1382 | #else |
---|
| 1383 | struct libtrace_filter_t *filter = (struct libtrace_filter_t *) |
---|
| 1384 | malloc(sizeof(struct libtrace_filter_t)); |
---|
| 1385 | filter->filter.bf_insns = (struct bpf_insn *) |
---|
| 1386 | malloc(sizeof(struct bpf_insn) * bf_len); |
---|
[9636216] | 1387 | |
---|
[3a14f3b] | 1388 | memcpy(filter->filter.bf_insns, bf_insns, |
---|
| 1389 | bf_len * sizeof(struct bpf_insn)); |
---|
[9636216] | 1390 | |
---|
[3a14f3b] | 1391 | filter->filter.bf_len = bf_len; |
---|
| 1392 | filter->filterstring = NULL; |
---|
[d48008d] | 1393 | filter->jitfilter = NULL; |
---|
[3a14f3b] | 1394 | /* "flag" indicates that the filter member is valid */ |
---|
[9636216] | 1395 | filter->flag = 1; |
---|
| 1396 | |
---|
[3a14f3b] | 1397 | return filter; |
---|
| 1398 | #endif |
---|
| 1399 | } |
---|
| 1400 | |
---|
[eda2def] | 1401 | /* Create a BPF filter |
---|
[c681e86] | 1402 | * @param filterstring a char * containing the bpf filter string |
---|
[c5a22ec] | 1403 | * @returns opaque pointer pointer to a libtrace_filter_t object |
---|
[c681e86] | 1404 | */ |
---|
[e2aebe7] | 1405 | DLLEXPORT libtrace_filter_t *trace_create_filter(const char *filterstring) { |
---|
[d47ca18] | 1406 | #ifdef HAVE_BPF |
---|
[e6d963c] | 1407 | libtrace_filter_t *filter = (libtrace_filter_t*) |
---|
| 1408 | malloc(sizeof(libtrace_filter_t)); |
---|
[c5a22ec] | 1409 | filter->filterstring = strdup(filterstring); |
---|
[d48008d] | 1410 | filter->jitfilter = NULL; |
---|
[df338b3] | 1411 | filter->flag = 0; |
---|
[c5a22ec] | 1412 | return filter; |
---|
[9580a74] | 1413 | #else |
---|
| 1414 | fprintf(stderr,"This version of libtrace does not have bpf filter support\n"); |
---|
[516a90d] | 1415 | return NULL; |
---|
[9580a74] | 1416 | #endif |
---|
[c681e86] | 1417 | } |
---|
| 1418 | |
---|
[e2aebe7] | 1419 | DLLEXPORT void trace_destroy_filter(libtrace_filter_t *filter) |
---|
[747c501] | 1420 | { |
---|
[d47ca18] | 1421 | #ifdef HAVE_BPF |
---|
[747c501] | 1422 | free(filter->filterstring); |
---|
| 1423 | if (filter->flag) |
---|
| 1424 | pcap_freecode(&filter->filter); |
---|
[d48008d] | 1425 | #ifdef HAVE_LLVM |
---|
[9636216] | 1426 | if (filter->jitfilter) |
---|
[d48008d] | 1427 | destroy_program(filter->jitfilter); |
---|
| 1428 | #endif |
---|
[747c501] | 1429 | free(filter); |
---|
[516a90d] | 1430 | #else |
---|
| 1431 | |
---|
| 1432 | #endif |
---|
[747c501] | 1433 | } |
---|
| 1434 | |
---|
[eda2def] | 1435 | /* Compile a bpf filter, now we know the link type for the trace that we're |
---|
| 1436 | * applying it to. |
---|
| 1437 | * |
---|
[df338b3] | 1438 | * @internal |
---|
| 1439 | * |
---|
| 1440 | * @returns -1 on error, 0 on success |
---|
| 1441 | */ |
---|
[0bb3004] | 1442 | static int trace_bpf_compile(libtrace_filter_t *filter, |
---|
[c0506ea] | 1443 | const libtrace_packet_t *packet, |
---|
[9636216] | 1444 | void *linkptr, |
---|
[c0506ea] | 1445 | libtrace_linktype_t linktype ) { |
---|
[d47ca18] | 1446 | #ifdef HAVE_BPF |
---|
[29bbef0] | 1447 | /* It just so happens that the underlying libs used by pthread arn't |
---|
| 1448 | * thread safe, namely lex/flex thingys, so single threaded compile |
---|
| 1449 | * multi threaded running should be safe. |
---|
| 1450 | */ |
---|
| 1451 | static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
---|
[df338b3] | 1452 | assert(filter); |
---|
| 1453 | |
---|
| 1454 | /* If this isn't a real packet, then fail */ |
---|
| 1455 | if (!linkptr) { |
---|
[0ea3526] | 1456 | trace_set_err(packet->trace, |
---|
[e90d5a8] | 1457 | TRACE_ERR_BAD_FILTER,"Packet has no payload"); |
---|
[df338b3] | 1458 | return -1; |
---|
| 1459 | } |
---|
[9636216] | 1460 | |
---|
[df338b3] | 1461 | if (filter->filterstring && ! filter->flag) { |
---|
[d242ea8] | 1462 | pcap_t *pcap = NULL; |
---|
[d5879cc] | 1463 | if (linktype==(libtrace_linktype_t)-1) { |
---|
[302714f] | 1464 | trace_set_err(packet->trace, |
---|
[e90d5a8] | 1465 | TRACE_ERR_BAD_FILTER, |
---|
[d5879cc] | 1466 | "Packet has an unknown linktype"); |
---|
| 1467 | return -1; |
---|
| 1468 | } |
---|
[f7bcbfb] | 1469 | if (libtrace_to_pcap_dlt(linktype) == TRACE_DLT_ERROR) { |
---|
[e90d5a8] | 1470 | trace_set_err(packet->trace,TRACE_ERR_BAD_FILTER, |
---|
[d242ea8] | 1471 | "Unknown pcap equivalent linktype"); |
---|
[d5879cc] | 1472 | return -1; |
---|
| 1473 | } |
---|
[29bbef0] | 1474 | assert (pthread_mutex_lock(&mutex) == 0); |
---|
| 1475 | /* Make sure not one bet us to this */ |
---|
| 1476 | if (filter->flag) { |
---|
| 1477 | assert (pthread_mutex_unlock(&mutex) == 0); |
---|
| 1478 | return 1; |
---|
| 1479 | } |
---|
[df338b3] | 1480 | pcap=(pcap_t *)pcap_open_dead( |
---|
[4bd8a5b] | 1481 | (int)libtrace_to_pcap_dlt(linktype), |
---|
| 1482 | 1500U); |
---|
[df338b3] | 1483 | /* build filter */ |
---|
[d242ea8] | 1484 | assert(pcap); |
---|
[9636216] | 1485 | if (pcap_compile( pcap, &filter->filter, filter->filterstring, |
---|
[df338b3] | 1486 | 1, 0)) { |
---|
[e90d5a8] | 1487 | trace_set_err(packet->trace,TRACE_ERR_BAD_FILTER, |
---|
[9636216] | 1488 | "Unable to compile the filter \"%s\": %s", |
---|
[d242ea8] | 1489 | filter->filterstring, |
---|
| 1490 | pcap_geterr(pcap)); |
---|
| 1491 | pcap_close(pcap); |
---|
[29bbef0] | 1492 | assert (pthread_mutex_unlock(&mutex) == 0); |
---|
[df338b3] | 1493 | return -1; |
---|
| 1494 | } |
---|
| 1495 | pcap_close(pcap); |
---|
| 1496 | filter->flag=1; |
---|
[29bbef0] | 1497 | assert (pthread_mutex_unlock(&mutex) == 0); |
---|
[df338b3] | 1498 | } |
---|
| 1499 | return 0; |
---|
| 1500 | #else |
---|
[eda2def] | 1501 | assert(!"Internal bug: This should never be called when BPF not enabled"); |
---|
[abc8e94] | 1502 | trace_set_err(packet->trace,TRACE_ERR_OPTION_UNAVAIL, |
---|
| 1503 | "Feature unavailable"); |
---|
| 1504 | return -1; |
---|
[df338b3] | 1505 | #endif |
---|
| 1506 | } |
---|
| 1507 | |
---|
[e2aebe7] | 1508 | DLLEXPORT int trace_apply_filter(libtrace_filter_t *filter, |
---|
[e6d963c] | 1509 | const libtrace_packet_t *packet) { |
---|
[d47ca18] | 1510 | #ifdef HAVE_BPF |
---|
[2137b49] | 1511 | void *linkptr = 0; |
---|
[9bc4689] | 1512 | uint32_t clen = 0; |
---|
[76eeca0] | 1513 | bool free_packet_needed = false; |
---|
| 1514 | int ret; |
---|
[c0506ea] | 1515 | libtrace_linktype_t linktype; |
---|
[778d459] | 1516 | libtrace_packet_t *packet_copy = (libtrace_packet_t*)packet; |
---|
[29bbef0] | 1517 | #ifdef HAVE_LLVM |
---|
| 1518 | static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
---|
| 1519 | #endif |
---|
[33d83d4] | 1520 | |
---|
[c5a22ec] | 1521 | assert(filter); |
---|
[2137b49] | 1522 | assert(packet); |
---|
[1352066] | 1523 | |
---|
[b6664e8] | 1524 | /* Match all non-data packets as we probably want them to pass |
---|
| 1525 | * through to the caller */ |
---|
[c0506ea] | 1526 | linktype = trace_get_link_type(packet); |
---|
| 1527 | |
---|
[9375d2e] | 1528 | if (linktype == TRACE_TYPE_NONDATA || linktype == TRACE_TYPE_ERF_META) |
---|
[9636216] | 1529 | return 1; |
---|
[b6664e8] | 1530 | |
---|
[f7bcbfb] | 1531 | if (libtrace_to_pcap_dlt(linktype)==TRACE_DLT_ERROR) { |
---|
[9636216] | 1532 | |
---|
[eda2def] | 1533 | /* If we cannot get a suitable DLT for the packet, it may |
---|
| 1534 | * be because the packet is encapsulated in a link type that |
---|
| 1535 | * does not correspond to a DLT. Therefore, we should try |
---|
| 1536 | * popping off headers until we either can find a suitable |
---|
| 1537 | * link type or we can't do any more sensible decapsulation. */ |
---|
[9636216] | 1538 | |
---|
[1352066] | 1539 | /* Copy the packet, as we don't want to trash the one we |
---|
[eda2def] | 1540 | * were passed in */ |
---|
[7ca2c7d] | 1541 | packet_copy=trace_copy_packet(packet); |
---|
[76eeca0] | 1542 | free_packet_needed=true; |
---|
[eda2def] | 1543 | |
---|
[f7bcbfb] | 1544 | while (libtrace_to_pcap_dlt(linktype) == TRACE_DLT_ERROR) { |
---|
[7ca2c7d] | 1545 | if (!demote_packet(packet_copy)) { |
---|
[9636216] | 1546 | trace_set_err(packet->trace, |
---|
[1352066] | 1547 | TRACE_ERR_NO_CONVERSION, |
---|
| 1548 | "pcap does not support this format"); |
---|
[76eeca0] | 1549 | if (free_packet_needed) { |
---|
[7ca2c7d] | 1550 | trace_destroy_packet(packet_copy); |
---|
[76eeca0] | 1551 | } |
---|
[1352066] | 1552 | return -1; |
---|
| 1553 | } |
---|
[c0506ea] | 1554 | linktype = trace_get_link_type(packet_copy); |
---|
[1352066] | 1555 | } |
---|
[c0506ea] | 1556 | |
---|
[1352066] | 1557 | } |
---|
[9636216] | 1558 | |
---|
[9bc4689] | 1559 | linkptr = trace_get_packet_buffer(packet_copy,NULL,&clen); |
---|
[76eeca0] | 1560 | if (!linkptr) { |
---|
| 1561 | if (free_packet_needed) { |
---|
[7ca2c7d] | 1562 | trace_destroy_packet(packet_copy); |
---|
[76eeca0] | 1563 | } |
---|
| 1564 | return 0; |
---|
| 1565 | } |
---|
| 1566 | |
---|
[9636216] | 1567 | /* We need to compile the filter now, because before we didn't know |
---|
[eda2def] | 1568 | * what the link type was |
---|
[76eeca0] | 1569 | */ |
---|
[29bbef0] | 1570 | // Note internal mutex locking used here |
---|
[c0506ea] | 1571 | if (trace_bpf_compile(filter,packet_copy,linkptr,linktype)==-1) { |
---|
[76eeca0] | 1572 | if (free_packet_needed) { |
---|
[7ca2c7d] | 1573 | trace_destroy_packet(packet_copy); |
---|
[76eeca0] | 1574 | } |
---|
| 1575 | return -1; |
---|
| 1576 | } |
---|
| 1577 | |
---|
[d48008d] | 1578 | /* If we're jitting, we may need to JIT the BPF code now too */ |
---|
| 1579 | #if HAVE_LLVM |
---|
| 1580 | if (!filter->jitfilter) { |
---|
[a49a9eb] | 1581 | ASSERT_RET(pthread_mutex_lock(&mutex), == 0); |
---|
[29bbef0] | 1582 | /* Again double check here like the bpf filter */ |
---|
[d3849c7] | 1583 | if(!filter->jitfilter) |
---|
[29bbef0] | 1584 | /* Looking at compile_program source this appears to be thread safe |
---|
| 1585 | * however if this gets called twice we will leak this memory :( |
---|
| 1586 | * as such lock here anyways */ |
---|
| 1587 | filter->jitfilter = compile_program(filter->filter.bf_insns, filter->filter.bf_len); |
---|
[a49a9eb] | 1588 | ASSERT_RET(pthread_mutex_unlock(&mutex), == 0); |
---|
[d48008d] | 1589 | } |
---|
| 1590 | #endif |
---|
| 1591 | |
---|
[df338b3] | 1592 | assert(filter->flag); |
---|
[d48008d] | 1593 | /* Now execute the filter */ |
---|
| 1594 | #if HAVE_LLVM |
---|
| 1595 | ret=filter->jitfilter->bpf_run((unsigned char *)linkptr, clen); |
---|
| 1596 | #else |
---|
[9bc4689] | 1597 | ret=bpf_filter(filter->filter.bf_insns,(u_char*)linkptr,(unsigned int)clen,(unsigned int)clen); |
---|
[d48008d] | 1598 | #endif |
---|
[eda2def] | 1599 | |
---|
| 1600 | /* If we copied the packet earlier, make sure that we free it */ |
---|
[76eeca0] | 1601 | if (free_packet_needed) { |
---|
[7ca2c7d] | 1602 | trace_destroy_packet(packet_copy); |
---|
[76eeca0] | 1603 | } |
---|
| 1604 | return ret; |
---|
[9580a74] | 1605 | #else |
---|
| 1606 | fprintf(stderr,"This version of libtrace does not have bpf filter support\n"); |
---|
| 1607 | return 0; |
---|
| 1608 | #endif |
---|
[c681e86] | 1609 | } |
---|
| 1610 | |
---|
[fba4ca0] | 1611 | /* Set the direction flag, if it has one |
---|
[80a2e99] | 1612 | * @param packet the packet opaque pointer |
---|
| 1613 | * @param direction the new direction (0,1,2,3) |
---|
| 1614 | * @returns a signed value containing the direction flag, or -1 if this is not supported |
---|
| 1615 | */ |
---|
[9636216] | 1616 | DLLEXPORT libtrace_direction_t trace_set_direction(libtrace_packet_t *packet, |
---|
| 1617 | libtrace_direction_t direction) |
---|
[c37ab9f] | 1618 | { |
---|
[9a36e6d] | 1619 | assert(packet); |
---|
[4dedc28] | 1620 | if (packet->trace->format->set_direction) { |
---|
| 1621 | return packet->trace->format->set_direction(packet,direction); |
---|
[80a2e99] | 1622 | } |
---|
[85a79b0] | 1623 | return (libtrace_direction_t)~0U; |
---|
[80a2e99] | 1624 | } |
---|
| 1625 | |
---|
[fba4ca0] | 1626 | /* Get the direction flag, if it has one |
---|
[850630f] | 1627 | * @param packet a pointer to a libtrace_packet structure |
---|
[14a9d05] | 1628 | * @returns a signed value containing the direction flag, or -1 if this is not supported |
---|
[9075d49] | 1629 | * The direction is defined as 0 for packets originating locally (ie, outbound) |
---|
| 1630 | * and 1 for packets originating remotely (ie, inbound). |
---|
| 1631 | * Other values are possible, which might be overloaded to mean special things |
---|
| 1632 | * for a special trace. |
---|
[14a9d05] | 1633 | */ |
---|
[9636216] | 1634 | DLLEXPORT libtrace_direction_t trace_get_direction(const libtrace_packet_t *packet) |
---|
[c37ab9f] | 1635 | { |
---|
[2137b49] | 1636 | assert(packet); |
---|
[4dedc28] | 1637 | if (packet->trace->format->get_direction) { |
---|
| 1638 | return packet->trace->format->get_direction(packet); |
---|
[14a9d05] | 1639 | } |
---|
[85a79b0] | 1640 | return (libtrace_direction_t)~0U; |
---|
[14a9d05] | 1641 | } |
---|
[c681e86] | 1642 | |
---|
[5c25d3a] | 1643 | #define ROOT_SERVER(x) ((x) < 512) |
---|
| 1644 | #define ROOT_CLIENT(x) ((512 <= (x)) && ((x) < 1024)) |
---|
| 1645 | #define NONROOT_SERVER(x) ((x) >= 5000) |
---|
| 1646 | #define NONROOT_CLIENT(x) ((1024 <= (x)) && ((x) < 5000)) |
---|
| 1647 | #define DYNAMIC(x) ((49152 < (x)) && ((x) < 65535)) |
---|
[83e0a25] | 1648 | #define SERVER(x) ROOT_SERVER(x) || NONROOT_SERVER(x) |
---|
[9636216] | 1649 | #define CLIENT(x) ROOT_CLIENT(x) || NONROOT_CLIENT(x) |
---|
[83e0a25] | 1650 | |
---|
[d66fbf0] | 1651 | /* Attempt to deduce the 'server' port |
---|
[1cea750] | 1652 | * @param protocol the IP protocol (eg, 6 or 17 for TCP or UDP) |
---|
| 1653 | * @param source the TCP or UDP source port |
---|
| 1654 | * @param dest the TCP or UDP destination port |
---|
| 1655 | * @returns a hint as to which port is the server port |
---|
| 1656 | */ |
---|
[9636216] | 1657 | DLLEXPORT int8_t trace_get_server_port(UNUSED uint8_t protocol, |
---|
| 1658 | uint16_t source, uint16_t dest) |
---|
[85a79b0] | 1659 | { |
---|
[83e0a25] | 1660 | /* |
---|
| 1661 | * * If the ports are equal, return DEST |
---|
| 1662 | * * Check for well-known ports in the given protocol |
---|
| 1663 | * * Root server ports: 0 - 511 |
---|
| 1664 | * * Root client ports: 512 - 1023 |
---|
| 1665 | * * non-root client ports: 1024 - 4999 |
---|
| 1666 | * * non-root server ports: 5000+ |
---|
| 1667 | * * Check for static ranges: 1024 - 49151 |
---|
| 1668 | * * Check for dynamic ranges: 49152 - 65535 |
---|
| 1669 | * * flip a coin. |
---|
| 1670 | */ |
---|
[9636216] | 1671 | |
---|
[b007afc] | 1672 | /* equal */ |
---|
[9c6aa95] | 1673 | if (source == dest) |
---|
[b007afc] | 1674 | return USE_DEST; |
---|
| 1675 | |
---|
| 1676 | /* root server port, 0 - 511 */ |
---|
[5c25d3a] | 1677 | if (ROOT_SERVER(source) && ROOT_SERVER(dest)) { |
---|
| 1678 | if (source < dest) |
---|
| 1679 | return USE_SOURCE; |
---|
[b007afc] | 1680 | return USE_DEST; |
---|
[5c25d3a] | 1681 | } |
---|
[b007afc] | 1682 | |
---|
| 1683 | if (ROOT_SERVER(source) && !ROOT_SERVER(dest)) |
---|
[83e0a25] | 1684 | return USE_SOURCE; |
---|
[b007afc] | 1685 | if (!ROOT_SERVER(source) && ROOT_SERVER(dest)) |
---|
| 1686 | return USE_DEST; |
---|
| 1687 | |
---|
| 1688 | /* non-root server */ |
---|
[5c25d3a] | 1689 | if (NONROOT_SERVER(source) && NONROOT_SERVER(dest)) { |
---|
| 1690 | if (source < dest) |
---|
| 1691 | return USE_SOURCE; |
---|
[83e0a25] | 1692 | return USE_DEST; |
---|
[5c25d3a] | 1693 | } |
---|
[b007afc] | 1694 | if (NONROOT_SERVER(source) && !NONROOT_SERVER(dest)) |
---|
[83e0a25] | 1695 | return USE_SOURCE; |
---|
[b007afc] | 1696 | if (!NONROOT_SERVER(source) && NONROOT_SERVER(dest)) |
---|
[83e0a25] | 1697 | return USE_DEST; |
---|
[b007afc] | 1698 | |
---|
| 1699 | /* root client */ |
---|
[5c25d3a] | 1700 | if (ROOT_CLIENT(source) && ROOT_CLIENT(dest)) { |
---|
| 1701 | if (source < dest) |
---|
| 1702 | return USE_SOURCE; |
---|
[b007afc] | 1703 | return USE_DEST; |
---|
[5c25d3a] | 1704 | } |
---|
[f0a2f98] | 1705 | if (ROOT_CLIENT(source) && !ROOT_CLIENT(dest)) { |
---|
| 1706 | /* prefer root-client over nonroot-client */ |
---|
| 1707 | if (NONROOT_CLIENT(dest)) |
---|
| 1708 | return USE_SOURCE; |
---|
[b007afc] | 1709 | return USE_DEST; |
---|
[f0a2f98] | 1710 | } |
---|
| 1711 | if (!ROOT_CLIENT(source) && ROOT_CLIENT(dest)) { |
---|
| 1712 | /* prefer root-client over nonroot-client */ |
---|
| 1713 | if (NONROOT_CLIENT(source)) |
---|
| 1714 | return USE_DEST; |
---|
[b007afc] | 1715 | return USE_SOURCE; |
---|
[f0a2f98] | 1716 | } |
---|
[9636216] | 1717 | |
---|
[b007afc] | 1718 | /* nonroot client */ |
---|
[5c25d3a] | 1719 | if (NONROOT_CLIENT(source) && NONROOT_CLIENT(dest)) { |
---|
[9636216] | 1720 | if (source < dest) |
---|
[5c25d3a] | 1721 | return USE_SOURCE; |
---|
[b007afc] | 1722 | return USE_DEST; |
---|
[5c25d3a] | 1723 | } |
---|
[b007afc] | 1724 | if (NONROOT_CLIENT(source) && !NONROOT_CLIENT(dest)) |
---|
| 1725 | return USE_DEST; |
---|
| 1726 | if (!NONROOT_CLIENT(source) && NONROOT_CLIENT(dest)) |
---|
| 1727 | return USE_SOURCE; |
---|
| 1728 | |
---|
[5c25d3a] | 1729 | /* dynamic range */ |
---|
[e1868fb] | 1730 | if (DYNAMIC(source) && DYNAMIC(dest)) { |
---|
[f9bb6c5] | 1731 | if (source < dest) |
---|
| 1732 | return USE_SOURCE; |
---|
[b007afc] | 1733 | return USE_DEST; |
---|
[e1868fb] | 1734 | } |
---|
[b007afc] | 1735 | if (DYNAMIC(source) && !DYNAMIC(dest)) |
---|
| 1736 | return USE_DEST; |
---|
| 1737 | if (!DYNAMIC(source) && DYNAMIC(dest)) |
---|
| 1738 | return USE_SOURCE; |
---|
| 1739 | /* |
---|
[9636216] | 1740 | if (SERVER(source) && CLIENT(dest)) |
---|
[b007afc] | 1741 | return USE_SOURCE; |
---|
[9636216] | 1742 | |
---|
| 1743 | if (SERVER(dest) && CLIENT(source)) |
---|
[b007afc] | 1744 | return USE_DEST; |
---|
[9636216] | 1745 | if (ROOT_SERVER(source) && !ROOT_SERVER(dest)) |
---|
[b007afc] | 1746 | return USE_SOURCE; |
---|
[9636216] | 1747 | if (ROOT_SERVER(dest) && !ROOT_SERVER(source)) |
---|
[b007afc] | 1748 | return USE_DEST; |
---|
| 1749 | */ |
---|
[7068467] | 1750 | /* failing that test... */ |
---|
[83e0a25] | 1751 | if (source < dest) { |
---|
| 1752 | return USE_SOURCE; |
---|
[9636216] | 1753 | } |
---|
[83e0a25] | 1754 | return USE_DEST; |
---|
[9636216] | 1755 | |
---|
[83e0a25] | 1756 | } |
---|
[80a2e99] | 1757 | |
---|
[fba4ca0] | 1758 | /* Truncate the packet at the suggested length |
---|
[80a2e99] | 1759 | * @param packet the packet opaque pointer |
---|
[850630f] | 1760 | * @param size the new length of the packet |
---|
[fe7b292] | 1761 | * @returns the new size of the packet |
---|
[c95b923] | 1762 | * @note size and the return size refer to the network-level payload of the |
---|
| 1763 | * packet, and do not include any capture headers. For example, to truncate a |
---|
| 1764 | * packet after the IP header, set size to sizeof(ethernet_header) + |
---|
| 1765 | * sizeof(ip_header) |
---|
| 1766 | * @note If the original network-level payload is smaller than size, then the |
---|
| 1767 | * original size is returned and the packet is left unchanged. |
---|
[80a2e99] | 1768 | */ |
---|
[e6d963c] | 1769 | DLLEXPORT size_t trace_set_capture_length(libtrace_packet_t *packet, size_t size) { |
---|
[80a2e99] | 1770 | assert(packet); |
---|
| 1771 | |
---|
[c95b923] | 1772 | if (packet->trace->format->set_capture_length) { |
---|
[66e6d16] | 1773 | packet->capture_length = packet->trace->format->set_capture_length(packet,size); |
---|
| 1774 | return packet->capture_length; |
---|
[80a2e99] | 1775 | } |
---|
[fe7b292] | 1776 | |
---|
[85a79b0] | 1777 | return ~0U; |
---|
[80a2e99] | 1778 | } |
---|
| 1779 | |
---|
[eda2def] | 1780 | /* Splits a URI into two components - the format component which is seen before |
---|
| 1781 | * the ':', and the uridata which follows the ':'. |
---|
| 1782 | * |
---|
| 1783 | * Returns a pointer to the URI data, but updates the format parameter to |
---|
[9636216] | 1784 | * point to a copy of the format component. |
---|
[eda2def] | 1785 | */ |
---|
| 1786 | |
---|
[39e141f] | 1787 | DLLEXPORT const char * trace_parse_uri(const char *uri, char **format) { |
---|
[6f75b9d] | 1788 | const char *uridata = 0; |
---|
[9636216] | 1789 | |
---|
[de8c420b] | 1790 | if((uridata = strchr(uri,':')) == NULL) { |
---|
[eda2def] | 1791 | /* Badly formed URI - needs a : */ |
---|
[de8c420b] | 1792 | return 0; |
---|
| 1793 | } |
---|
| 1794 | |
---|
[36d51c8] | 1795 | if ((unsigned)(uridata - uri) > URI_PROTO_LINE) { |
---|
[eda2def] | 1796 | /* Badly formed URI - uri type is too long */ |
---|
[de8c420b] | 1797 | return 0; |
---|
| 1798 | } |
---|
| 1799 | |
---|
[eda2def] | 1800 | /* NOTE: this is allocated memory - it should be freed by the caller |
---|
| 1801 | * once they are done with it */ |
---|
[4bd8a5b] | 1802 | *format=xstrndup(uri, (size_t)(uridata - uri)); |
---|
[6f75b9d] | 1803 | |
---|
[eda2def] | 1804 | /* Push uridata past the delimiter */ |
---|
[de8c420b] | 1805 | uridata++; |
---|
[9636216] | 1806 | |
---|
[de8c420b] | 1807 | return uridata; |
---|
| 1808 | } |
---|
[6dbc47a] | 1809 | |
---|
[9636216] | 1810 | enum base_format_t trace_get_format(libtrace_packet_t *packet) |
---|
[0ea3526] | 1811 | { |
---|
[6dbc47a] | 1812 | assert(packet); |
---|
| 1813 | |
---|
| 1814 | return packet->trace->format->type; |
---|
| 1815 | } |
---|
[9636216] | 1816 | |
---|
[39e141f] | 1817 | DLLEXPORT libtrace_err_t trace_get_err(libtrace_t *trace) |
---|
[880aa58] | 1818 | { |
---|
[0ea3526] | 1819 | libtrace_err_t err = trace->err; |
---|
| 1820 | trace->err.err_num = 0; /* "OK" */ |
---|
| 1821 | trace->err.problem[0]='\0'; |
---|
| 1822 | return err; |
---|
| 1823 | } |
---|
| 1824 | |
---|
[39e141f] | 1825 | DLLEXPORT bool trace_is_err(libtrace_t *trace) |
---|
[eeab9832] | 1826 | { |
---|
| 1827 | return trace->err.err_num != 0; |
---|
| 1828 | } |
---|
| 1829 | |
---|
[eda2def] | 1830 | /* Prints the input error status to standard error and clears the error state */ |
---|
[39e141f] | 1831 | DLLEXPORT void trace_perror(libtrace_t *trace,const char *msg,...) |
---|
[eeab9832] | 1832 | { |
---|
| 1833 | char buf[256]; |
---|
| 1834 | va_list va; |
---|
| 1835 | va_start(va,msg); |
---|
| 1836 | vsnprintf(buf,sizeof(buf),msg,va); |
---|
| 1837 | va_end(va); |
---|
| 1838 | if(trace->err.err_num) { |
---|
[670bbe5] | 1839 | if (trace->uridata) { |
---|
| 1840 | fprintf(stderr,"%s(%s): %s\n", |
---|
| 1841 | buf,trace->uridata,trace->err.problem); |
---|
| 1842 | } else { |
---|
| 1843 | fprintf(stderr,"%s: %s\n", buf, trace->err.problem); |
---|
| 1844 | } |
---|
[eeab9832] | 1845 | } else { |
---|
[670bbe5] | 1846 | if (trace->uridata) { |
---|
| 1847 | fprintf(stderr,"%s(%s): No error\n",buf,trace->uridata); |
---|
| 1848 | } else { |
---|
[b4a17c7] | 1849 | fprintf(stderr,"%s: No error\n", buf); |
---|
[670bbe5] | 1850 | } |
---|
[eeab9832] | 1851 | } |
---|
[114b8d6] | 1852 | trace->err.err_num = 0; /* "OK" */ |
---|
| 1853 | trace->err.problem[0]='\0'; |
---|
[eeab9832] | 1854 | } |
---|
| 1855 | |
---|
[39e141f] | 1856 | DLLEXPORT libtrace_err_t trace_get_err_output(libtrace_out_t *trace) |
---|
[0ea3526] | 1857 | { |
---|
| 1858 | libtrace_err_t err = trace->err; |
---|
[ae66bde] | 1859 | trace->err.err_num = TRACE_ERR_NOERROR; /* "OK" */ |
---|
[0ea3526] | 1860 | trace->err.problem[0]='\0'; |
---|
| 1861 | return err; |
---|
[880aa58] | 1862 | } |
---|
[0d57541] | 1863 | |
---|
[39e141f] | 1864 | DLLEXPORT bool trace_is_err_output(libtrace_out_t *trace) |
---|
[eeab9832] | 1865 | { |
---|
| 1866 | return trace->err.err_num != 0; |
---|
| 1867 | } |
---|
| 1868 | |
---|
[eda2def] | 1869 | /* Prints the output error status to standard error and clears the error state |
---|
| 1870 | */ |
---|
[39e141f] | 1871 | DLLEXPORT void trace_perror_output(libtrace_out_t *trace,const char *msg,...) |
---|
[eeab9832] | 1872 | { |
---|
| 1873 | char buf[256]; |
---|
| 1874 | va_list va; |
---|
| 1875 | va_start(va,msg); |
---|
| 1876 | vsnprintf(buf,sizeof(buf),msg,va); |
---|
| 1877 | va_end(va); |
---|
| 1878 | if(trace->err.err_num) { |
---|
| 1879 | fprintf(stderr,"%s(%s): %s\n", |
---|
[61b4543] | 1880 | buf, |
---|
| 1881 | trace->uridata?trace->uridata:"no uri", |
---|
| 1882 | trace->err.problem); |
---|
[eeab9832] | 1883 | } else { |
---|
| 1884 | fprintf(stderr,"%s(%s): No error\n",buf,trace->uridata); |
---|
| 1885 | } |
---|
[e4976e1] | 1886 | trace->err.err_num = TRACE_ERR_NOERROR; /* "OK" */ |
---|
| 1887 | trace->err.problem[0]='\0'; |
---|
[eeab9832] | 1888 | } |
---|
| 1889 | |
---|
[39e141f] | 1890 | DLLEXPORT int trace_seek_erf_timestamp(libtrace_t *trace, uint64_t ts) |
---|
[0d57541] | 1891 | { |
---|
| 1892 | if (trace->format->seek_erf) { |
---|
| 1893 | return trace->format->seek_erf(trace,ts); |
---|
| 1894 | } |
---|
| 1895 | else { |
---|
[6c248a9] | 1896 | if (trace->format->seek_timeval) { |
---|
| 1897 | struct timeval tv; |
---|
| 1898 | #if __BYTE_ORDER == __BIG_ENDIAN |
---|
| 1899 | tv.tv_sec = ts & 0xFFFFFFFF; |
---|
[11041eb] | 1900 | tv.tv_usec = ((ts >> 32) * 1000000) & 0xFFFFFFFF; |
---|
[6c248a9] | 1901 | #elif __BYTE_ORDER == __LITTLE_ENDIAN |
---|
| 1902 | tv.tv_sec = ts >> 32; |
---|
[11041eb] | 1903 | tv.tv_usec = ((ts&0xFFFFFFFF)*1000000)>>32; |
---|
[6c248a9] | 1904 | #else |
---|
| 1905 | #error "What on earth are you running this on?" |
---|
| 1906 | #endif |
---|
| 1907 | if (tv.tv_usec >= 1000000) { |
---|
| 1908 | tv.tv_usec -= 1000000; |
---|
| 1909 | tv.tv_sec += 1; |
---|
| 1910 | } |
---|
| 1911 | return trace->format->seek_timeval(trace,tv); |
---|
| 1912 | } |
---|
| 1913 | if (trace->format->seek_seconds) { |
---|
[9636216] | 1914 | double seconds = |
---|
[6c248a9] | 1915 | (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX); |
---|
| 1916 | return trace->format->seek_seconds(trace,seconds); |
---|
| 1917 | } |
---|
| 1918 | trace_set_err(trace, |
---|
| 1919 | TRACE_ERR_OPTION_UNAVAIL, |
---|
| 1920 | "Feature unimplemented"); |
---|
| 1921 | return -1; |
---|
| 1922 | } |
---|
| 1923 | } |
---|
| 1924 | |
---|
[39e141f] | 1925 | DLLEXPORT int trace_seek_seconds(libtrace_t *trace, double seconds) |
---|
[6c248a9] | 1926 | { |
---|
| 1927 | if (trace->format->seek_seconds) { |
---|
| 1928 | return trace->format->seek_seconds(trace,seconds); |
---|
| 1929 | } |
---|
| 1930 | else { |
---|
| 1931 | if (trace->format->seek_timeval) { |
---|
| 1932 | struct timeval tv; |
---|
| 1933 | tv.tv_sec = (uint32_t)seconds; |
---|
| 1934 | tv.tv_usec = (uint32_t)(((seconds - tv.tv_sec) * 1000000)/UINT_MAX); |
---|
| 1935 | return trace->format->seek_timeval(trace,tv); |
---|
| 1936 | } |
---|
| 1937 | if (trace->format->seek_erf) { |
---|
[9636216] | 1938 | uint64_t timestamp = |
---|
[6c248a9] | 1939 | ((uint64_t)((uint32_t)seconds) << 32) + \ |
---|
[67a14d4] | 1940 | (uint64_t)(( seconds - (uint32_t)seconds ) * UINT_MAX); |
---|
[6c248a9] | 1941 | return trace->format->seek_erf(trace,timestamp); |
---|
| 1942 | } |
---|
| 1943 | trace_set_err(trace, |
---|
| 1944 | TRACE_ERR_OPTION_UNAVAIL, |
---|
| 1945 | "Feature unimplemented"); |
---|
| 1946 | return -1; |
---|
| 1947 | } |
---|
| 1948 | } |
---|
| 1949 | |
---|
[39e141f] | 1950 | DLLEXPORT int trace_seek_timeval(libtrace_t *trace, struct timeval tv) |
---|
[6c248a9] | 1951 | { |
---|
| 1952 | if (trace->format->seek_timeval) { |
---|
| 1953 | return trace->format->seek_timeval(trace,tv); |
---|
| 1954 | } |
---|
| 1955 | else { |
---|
| 1956 | if (trace->format->seek_erf) { |
---|
| 1957 | uint64_t timestamp = ((((uint64_t)tv.tv_sec) << 32) + \ |
---|
| 1958 | (((uint64_t)tv.tv_usec * UINT_MAX)/1000000)); |
---|
| 1959 | return trace->format->seek_erf(trace,timestamp); |
---|
| 1960 | } |
---|
| 1961 | if (trace->format->seek_seconds) { |
---|
[e4e1635] | 1962 | double seconds = tv.tv_sec + ((tv.tv_usec * 1.0)/1000000); |
---|
[6c248a9] | 1963 | return trace->format->seek_seconds(trace,seconds); |
---|
| 1964 | } |
---|
[0d57541] | 1965 | trace_set_err(trace, |
---|
| 1966 | TRACE_ERR_OPTION_UNAVAIL, |
---|
| 1967 | "Feature unimplemented"); |
---|
| 1968 | return -1; |
---|
| 1969 | } |
---|
| 1970 | } |
---|
| 1971 | |
---|
[eda2def] | 1972 | /* Converts a binary ethernet MAC address into a printable string */ |
---|
[39e141f] | 1973 | DLLEXPORT char *trace_ether_ntoa(const uint8_t *addr, char *buf) |
---|
[752709f] | 1974 | { |
---|
[21ab138] | 1975 | static char staticbuf[18]={0,}; |
---|
| 1976 | if (!buf) |
---|
| 1977 | buf=staticbuf; |
---|
| 1978 | snprintf(buf,(size_t)18,"%02x:%02x:%02x:%02x:%02x:%02x", |
---|
[752709f] | 1979 | addr[0],addr[1],addr[2], |
---|
| 1980 | addr[3],addr[4],addr[5]); |
---|
[21ab138] | 1981 | return buf; |
---|
[752709f] | 1982 | } |
---|
| 1983 | |
---|
[eda2def] | 1984 | /* Converts a printable ethernet MAC address into a binary format */ |
---|
[39e141f] | 1985 | DLLEXPORT uint8_t *trace_ether_aton(const char *buf, uint8_t *addr) |
---|
[752709f] | 1986 | { |
---|
| 1987 | uint8_t *buf2 = addr; |
---|
| 1988 | unsigned int tmp[6]; |
---|
| 1989 | static uint8_t staticaddr[6]; |
---|
| 1990 | if (!buf2) |
---|
| 1991 | buf2=staticaddr; |
---|
| 1992 | sscanf(buf,"%x:%x:%x:%x:%x:%x", |
---|
| 1993 | &tmp[0],&tmp[1],&tmp[2], |
---|
| 1994 | &tmp[3],&tmp[4],&tmp[5]); |
---|
| 1995 | buf2[0]=tmp[0]; buf2[1]=tmp[1]; buf2[2]=tmp[2]; |
---|
| 1996 | buf2[3]=tmp[3]; buf2[4]=tmp[4]; buf2[5]=tmp[5]; |
---|
| 1997 | return buf2; |
---|
| 1998 | } |
---|
[4af54d1] | 1999 | |
---|
[eda2def] | 2000 | |
---|
[9636216] | 2001 | /* Creates a libtrace packet from scratch using the contents of the provided |
---|
[eda2def] | 2002 | * buffer as the packet payload. |
---|
| 2003 | * |
---|
| 2004 | * Unlike trace_prepare_packet(), the buffer should not contain any capture |
---|
[9636216] | 2005 | * format headers; instead this function will add the PCAP header to the |
---|
[eda2def] | 2006 | * packet record. This also means only PCAP packets can be constructed using |
---|
| 2007 | * this function. |
---|
| 2008 | * |
---|
| 2009 | */ |
---|
[c5ebbaa] | 2010 | DLLEXPORT |
---|
| 2011 | void trace_construct_packet(libtrace_packet_t *packet, |
---|
| 2012 | libtrace_linktype_t linktype, |
---|
| 2013 | const void *data, |
---|
| 2014 | uint16_t len) |
---|
| 2015 | { |
---|
[a7d1914] | 2016 | size_t size; |
---|
[0a62bba] | 2017 | static libtrace_t *deadtrace=NULL; |
---|
[c5ebbaa] | 2018 | libtrace_pcapfile_pkt_hdr_t hdr; |
---|
[6ed6c4a] | 2019 | #ifdef WIN32 |
---|
| 2020 | struct _timeb tstruct; |
---|
| 2021 | #else |
---|
[c5ebbaa] | 2022 | struct timeval tv; |
---|
[6ed6c4a] | 2023 | #endif |
---|
| 2024 | |
---|
[eda2def] | 2025 | /* We need a trace to attach the constructed packet to (and it needs |
---|
| 2026 | * to be PCAP) */ |
---|
[9636216] | 2027 | if (NULL == deadtrace) |
---|
[6ed6c4a] | 2028 | deadtrace=trace_create_dead("pcapfile"); |
---|
| 2029 | |
---|
[eda2def] | 2030 | /* Fill in the new PCAP header */ |
---|
[6ed6c4a] | 2031 | #ifdef WIN32 |
---|
| 2032 | _ftime(&tstruct); |
---|
| 2033 | hdr.ts_sec=tstruct.time; |
---|
| 2034 | hdr.ts_usec=tstruct.millitm * 1000; |
---|
| 2035 | #else |
---|
[c5ebbaa] | 2036 | gettimeofday(&tv,NULL); |
---|
| 2037 | hdr.ts_sec=tv.tv_sec; |
---|
| 2038 | hdr.ts_usec=tv.tv_usec; |
---|
[6ed6c4a] | 2039 | #endif |
---|
| 2040 | |
---|
[c5ebbaa] | 2041 | hdr.caplen=len; |
---|
| 2042 | hdr.wirelen=len; |
---|
| 2043 | |
---|
[eda2def] | 2044 | /* Now fill in the libtrace packet itself */ |
---|
[7d1ada1] | 2045 | assert(deadtrace); |
---|
[c5ebbaa] | 2046 | packet->trace=deadtrace; |
---|
[a7d1914] | 2047 | size=len+sizeof(hdr); |
---|
[7d1ada1] | 2048 | if (size < LIBTRACE_PACKET_BUFSIZE) |
---|
| 2049 | size = LIBTRACE_PACKET_BUFSIZE; |
---|
[c5ebbaa] | 2050 | if (packet->buf_control==TRACE_CTRL_PACKET) { |
---|
[7d1ada1] | 2051 | packet->buffer = realloc(packet->buffer, size); |
---|
[c5ebbaa] | 2052 | } |
---|
| 2053 | else { |
---|
[7d1ada1] | 2054 | packet->buffer = malloc(size); |
---|
[c5ebbaa] | 2055 | } |
---|
| 2056 | packet->buf_control=TRACE_CTRL_PACKET; |
---|
| 2057 | packet->header=packet->buffer; |
---|
| 2058 | packet->payload=(void*)((char*)packet->buffer+sizeof(hdr)); |
---|
[7d1ada1] | 2059 | |
---|
| 2060 | /* Ugh, memmove - sadly necessary, also beware that we might be |
---|
| 2061 | * moving data around within this packet, so ordering is important. |
---|
| 2062 | */ |
---|
| 2063 | memmove(packet->payload, data, (size_t)len); |
---|
| 2064 | memmove(packet->header, &hdr, sizeof(hdr)); |
---|
[73dd29f] | 2065 | packet->type=pcap_linktype_to_rt(libtrace_to_pcap_linktype(linktype)); |
---|
[eff6d8c] | 2066 | |
---|
| 2067 | trace_clear_cache(packet); |
---|
[c5ebbaa] | 2068 | } |
---|
[f2fae49] | 2069 | |
---|
[f0fb38f] | 2070 | |
---|
[50bbce8] | 2071 | uint64_t trace_get_received_packets(libtrace_t *trace) |
---|
[f2fae49] | 2072 | { |
---|
| 2073 | assert(trace); |
---|
[be3f75b] | 2074 | uint64_t ret; |
---|
| 2075 | |
---|
[f2fae49] | 2076 | if (trace->format->get_received_packets) { |
---|
[be3f75b] | 2077 | if ((ret = trace->format->get_received_packets(trace)) != UINT64_MAX) |
---|
| 2078 | return ret; |
---|
[5ab626a] | 2079 | } else if (trace->format->get_statistics) { |
---|
| 2080 | struct libtrace_stat_t stat; |
---|
| 2081 | stat.magic = LIBTRACE_STAT_MAGIC; |
---|
| 2082 | trace_get_statistics(trace, &stat); |
---|
| 2083 | if (stat.received_valid) |
---|
| 2084 | return stat.received; |
---|
| 2085 | } |
---|
| 2086 | |
---|
| 2087 | // Read the cached value taken before the trace was paused/closed |
---|
| 2088 | if(trace->stats && trace->stats->received_valid) |
---|
| 2089 | return trace->stats->received; |
---|
| 2090 | else |
---|
| 2091 | return UINT64_MAX; |
---|
[f2fae49] | 2092 | } |
---|
| 2093 | |
---|
[50bbce8] | 2094 | uint64_t trace_get_filtered_packets(libtrace_t *trace) |
---|
[f2fae49] | 2095 | { |
---|
| 2096 | assert(trace); |
---|
[368a1ae] | 2097 | int i = 0; |
---|
[5ab626a] | 2098 | uint64_t lib_filtered = trace->filtered_packets; |
---|
[368a1ae] | 2099 | for (i = 0; i < trace->perpkt_thread_count; i++) { |
---|
[5ab626a] | 2100 | lib_filtered += trace->perpkt_threads[i].filtered_packets; |
---|
[368a1ae] | 2101 | } |
---|
[f2fae49] | 2102 | if (trace->format->get_filtered_packets) { |
---|
[5ab626a] | 2103 | uint64_t trace_filtered = trace->format->get_filtered_packets(trace); |
---|
| 2104 | if (trace_filtered == UINT64_MAX) |
---|
| 2105 | return UINT64_MAX; |
---|
| 2106 | else |
---|
| 2107 | return trace_filtered + lib_filtered; |
---|
| 2108 | } else if (trace->format->get_statistics) { |
---|
| 2109 | struct libtrace_stat_t stat; |
---|
| 2110 | stat.magic = LIBTRACE_STAT_MAGIC; |
---|
| 2111 | trace_get_statistics(trace, &stat); |
---|
| 2112 | if (stat.filtered_valid) |
---|
| 2113 | return lib_filtered + stat.filtered; |
---|
| 2114 | else |
---|
| 2115 | return UINT64_MAX; |
---|
[f2fae49] | 2116 | } |
---|
[5ab626a] | 2117 | |
---|
| 2118 | // Read the cached value taken before the trace was paused/closed |
---|
| 2119 | if(trace->stats && trace->stats->filtered_valid) |
---|
| 2120 | return trace->stats->filtered + lib_filtered; |
---|
| 2121 | else |
---|
| 2122 | return lib_filtered; |
---|
[f2fae49] | 2123 | } |
---|
| 2124 | |
---|
[50bbce8] | 2125 | uint64_t trace_get_dropped_packets(libtrace_t *trace) |
---|
[f2fae49] | 2126 | { |
---|
| 2127 | assert(trace); |
---|
[be3f75b] | 2128 | uint64_t ret; |
---|
| 2129 | |
---|
[f2fae49] | 2130 | if (trace->format->get_dropped_packets) { |
---|
[be3f75b] | 2131 | if ((ret = trace->format->get_dropped_packets(trace)) != UINT64_MAX) |
---|
| 2132 | return ret; |
---|
[5ab626a] | 2133 | } else if (trace->format->get_statistics) { |
---|
| 2134 | struct libtrace_stat_t stat; |
---|
| 2135 | stat.magic = LIBTRACE_STAT_MAGIC; |
---|
| 2136 | trace_get_statistics(trace, &stat); |
---|
| 2137 | if (stat.dropped_valid) |
---|
| 2138 | return stat.dropped; |
---|
| 2139 | } |
---|
| 2140 | |
---|
| 2141 | // Read the cached value taken before the trace was paused/closed |
---|
| 2142 | if(trace->stats && trace->stats->dropped_valid) |
---|
| 2143 | return trace->stats->dropped; |
---|
| 2144 | else |
---|
| 2145 | return UINT64_MAX; |
---|
[f2fae49] | 2146 | } |
---|
| 2147 | |
---|
[50bbce8] | 2148 | uint64_t trace_get_accepted_packets(libtrace_t *trace) |
---|
[f2fae49] | 2149 | { |
---|
| 2150 | assert(trace); |
---|
[be3f75b] | 2151 | int i = 0; |
---|
[526d9d0] | 2152 | uint64_t ret = 0; |
---|
| 2153 | /* We always add to a thread's accepted count before dispatching the |
---|
| 2154 | * packet to the user. However if the underlying trace is single |
---|
| 2155 | * threaded it will also be increasing the global count. So if we |
---|
| 2156 | * find perpkt ignore the global count. |
---|
| 2157 | */ |
---|
[be3f75b] | 2158 | for (i = 0; i < trace->perpkt_thread_count; i++) { |
---|
| 2159 | ret += trace->perpkt_threads[i].accepted_packets; |
---|
| 2160 | } |
---|
[526d9d0] | 2161 | return ret ? ret : trace->accepted_packets; |
---|
[f2fae49] | 2162 | } |
---|
| 2163 | |
---|
[5ab626a] | 2164 | libtrace_stat_t *trace_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) |
---|
| 2165 | { |
---|
[5478d3d] | 2166 | uint64_t ret = 0; |
---|
[5ab626a] | 2167 | int i; |
---|
| 2168 | assert(trace); |
---|
| 2169 | if (stat == NULL) { |
---|
| 2170 | if (trace->stats == NULL) |
---|
| 2171 | trace->stats = trace_create_statistics(); |
---|
| 2172 | stat = trace->stats; |
---|
| 2173 | } |
---|
| 2174 | assert(stat->magic == LIBTRACE_STAT_MAGIC && "Please use" |
---|
| 2175 | "trace_create_statistics() to allocate statistics"); |
---|
[694823f] | 2176 | |
---|
| 2177 | /* If the trace has paused or finished get the cached results */ |
---|
[5ab626a] | 2178 | if (trace->state == STATE_PAUSED || |
---|
[ac65c9f] | 2179 | trace->state == STATE_FINISHED || |
---|
| 2180 | trace->state == STATE_FINISHING || |
---|
[5ab626a] | 2181 | trace->state == STATE_JOINED) { |
---|
| 2182 | if (trace->stats && trace->stats != stat) |
---|
| 2183 | *stat = *trace->stats; |
---|
| 2184 | return stat; |
---|
[694823f] | 2185 | } |
---|
| 2186 | |
---|
| 2187 | stat->reserved1 = 0; |
---|
| 2188 | stat->reserved2 = 0; |
---|
| 2189 | #define X(x) stat->x ##_valid = 0; |
---|
| 2190 | LIBTRACE_STAT_FIELDS; |
---|
| 2191 | #undef X |
---|
[526d9d0] | 2192 | /* Both accepted and filtered are stored against in the library */ |
---|
[5478d3d] | 2193 | |
---|
| 2194 | /* We always add to a thread's accepted count before dispatching the |
---|
| 2195 | * packet to the user. However if the underlying trace is single |
---|
| 2196 | * threaded it will also be increasing the global count. So if we |
---|
| 2197 | * find perpkt ignore the global count. |
---|
| 2198 | */ |
---|
| 2199 | for (i = 0; i < trace->perpkt_thread_count; i++) { |
---|
| 2200 | ret += trace->perpkt_threads[i].accepted_packets; |
---|
[5ab626a] | 2201 | } |
---|
[526d9d0] | 2202 | |
---|
[5478d3d] | 2203 | stat->accepted_valid = 1; |
---|
| 2204 | stat->accepted = ret ? ret : trace->accepted_packets; |
---|
| 2205 | |
---|
[526d9d0] | 2206 | stat->filtered_valid = 1; |
---|
| 2207 | stat->filtered = trace->filtered_packets; |
---|
| 2208 | for (i = 0; i < trace->perpkt_thread_count; i++) { |
---|
| 2209 | stat->filtered += trace->perpkt_threads[i].filtered_packets; |
---|
[5ab626a] | 2210 | } |
---|
[526d9d0] | 2211 | |
---|
| 2212 | if (trace->format->get_statistics) { |
---|
| 2213 | trace->format->get_statistics(trace, stat); |
---|
[5ab626a] | 2214 | } |
---|
| 2215 | return stat; |
---|
| 2216 | } |
---|
| 2217 | |
---|
| 2218 | void trace_get_thread_statistics(libtrace_t *trace, libtrace_thread_t *t, |
---|
| 2219 | libtrace_stat_t *stat) |
---|
| 2220 | { |
---|
| 2221 | assert(trace && stat); |
---|
| 2222 | assert(stat->magic == LIBTRACE_STAT_MAGIC && "Please use" |
---|
| 2223 | "trace_create_statistics() to allocate statistics"); |
---|
| 2224 | stat->reserved1 = 0; |
---|
| 2225 | stat->reserved2 = 0; |
---|
| 2226 | #define X(x) stat->x ##_valid= 0; |
---|
| 2227 | LIBTRACE_STAT_FIELDS; |
---|
| 2228 | #undef X |
---|
[526d9d0] | 2229 | stat->accepted_valid = 1; |
---|
| 2230 | stat->accepted = t->accepted_packets; |
---|
| 2231 | stat->filtered_valid = 1; |
---|
| 2232 | stat->filtered = t->filtered_packets; |
---|
| 2233 | if (!trace_has_dedicated_hasher(trace) && trace->format->get_thread_statistics) { |
---|
[5ab626a] | 2234 | trace->format->get_thread_statistics(trace, t, stat); |
---|
| 2235 | } |
---|
| 2236 | return; |
---|
| 2237 | } |
---|
| 2238 | |
---|
| 2239 | libtrace_stat_t *trace_create_statistics(void) { |
---|
| 2240 | libtrace_stat_t *ret; |
---|
| 2241 | ret = malloc(sizeof(libtrace_stat_t)); |
---|
| 2242 | if (ret) { |
---|
| 2243 | memset(ret, 0, sizeof(libtrace_stat_t)); |
---|
| 2244 | ret->magic = LIBTRACE_STAT_MAGIC; |
---|
| 2245 | } |
---|
| 2246 | return ret; |
---|
| 2247 | } |
---|
| 2248 | |
---|
[0cdd231] | 2249 | void trace_clear_statistics(libtrace_stat_t *s) { |
---|
| 2250 | memset(s, 0, sizeof(libtrace_stat_t)); |
---|
| 2251 | s->magic = LIBTRACE_STAT_MAGIC; |
---|
| 2252 | } |
---|
| 2253 | |
---|
[5ab626a] | 2254 | void trace_subtract_statistics(const libtrace_stat_t *a, const libtrace_stat_t *b, |
---|
| 2255 | libtrace_stat_t *c) { |
---|
| 2256 | assert(a->magic == LIBTRACE_STAT_MAGIC && "Please use" |
---|
| 2257 | "trace_create_statistics() to allocate statistics"); |
---|
| 2258 | assert(b->magic == LIBTRACE_STAT_MAGIC && "Please use" |
---|
| 2259 | "trace_create_statistics() to allocate statistics"); |
---|
| 2260 | assert(c->magic == LIBTRACE_STAT_MAGIC && "Please use" |
---|
| 2261 | "trace_create_statistics() to allocate statistics"); |
---|
| 2262 | |
---|
| 2263 | #define X(x) \ |
---|
| 2264 | if (a->x ##_valid && b->x ##_valid) { \ |
---|
| 2265 | c->x ##_valid = 1; \ |
---|
| 2266 | c->x = a->x - b->x; \ |
---|
| 2267 | } else {\ |
---|
| 2268 | c->x ##_valid = 0;\ |
---|
| 2269 | } |
---|
| 2270 | LIBTRACE_STAT_FIELDS |
---|
| 2271 | #undef X |
---|
| 2272 | } |
---|
| 2273 | |
---|
| 2274 | void trace_add_statistics(const libtrace_stat_t *a, const libtrace_stat_t *b, |
---|
| 2275 | libtrace_stat_t *c) { |
---|
| 2276 | assert(a->magic == LIBTRACE_STAT_MAGIC && "Please use" |
---|
| 2277 | "trace_create_statistics() to allocate statistics"); |
---|
| 2278 | assert(b->magic == LIBTRACE_STAT_MAGIC && "Please use" |
---|
| 2279 | "trace_create_statistics() to allocate statistics"); |
---|
| 2280 | assert(c->magic == LIBTRACE_STAT_MAGIC && "Please use" |
---|
| 2281 | "trace_create_statistics() to allocate statistics"); |
---|
| 2282 | |
---|
| 2283 | #define X(x) \ |
---|
| 2284 | if (a->x ##_valid&& b->x ##_valid) { \ |
---|
| 2285 | c->x ##_valid = 1; \ |
---|
| 2286 | c->x = a->x + b->x; \ |
---|
| 2287 | } else {\ |
---|
| 2288 | c->x ##_valid = 0;\ |
---|
| 2289 | } |
---|
| 2290 | LIBTRACE_STAT_FIELDS |
---|
| 2291 | #undef X |
---|
| 2292 | } |
---|
| 2293 | |
---|
| 2294 | int trace_print_statistics(const libtrace_stat_t *s, FILE *f, const char *format) { |
---|
| 2295 | assert(s->magic == LIBTRACE_STAT_MAGIC && "Please use" |
---|
| 2296 | "trace_create_statistics() to allocate statistics"); |
---|
| 2297 | if (format == NULL) |
---|
| 2298 | format = "%s: %"PRIu64"\n"; |
---|
| 2299 | #define xstr(s) str(s) |
---|
| 2300 | #define str(s) #s |
---|
| 2301 | #define X(x) \ |
---|
| 2302 | if (s->x ##_valid) { \ |
---|
| 2303 | if (fprintf(f, format, xstr(x), s->x) < 0) \ |
---|
| 2304 | return -1; \ |
---|
| 2305 | } |
---|
| 2306 | LIBTRACE_STAT_FIELDS |
---|
| 2307 | #undef X |
---|
| 2308 | return 0; |
---|
| 2309 | } |
---|
| 2310 | |
---|
| 2311 | |
---|
[9cc1266] | 2312 | void trace_clear_cache(libtrace_packet_t *packet) { |
---|
| 2313 | |
---|
[ee58d0d] | 2314 | packet->l2_header = NULL; |
---|
[9cc1266] | 2315 | packet->l3_header = NULL; |
---|
| 2316 | packet->l4_header = NULL; |
---|
[ee58d0d] | 2317 | packet->link_type = 0; |
---|
[9cc1266] | 2318 | packet->l3_ethertype = 0; |
---|
| 2319 | packet->transport_proto = 0; |
---|
| 2320 | packet->capture_length = -1; |
---|
[979a84f4] | 2321 | packet->wire_length = -1; |
---|
[9cc1266] | 2322 | packet->payload_length = -1; |
---|
[ee58d0d] | 2323 | packet->l2_remaining = 0; |
---|
| 2324 | packet->l3_remaining = 0; |
---|
| 2325 | packet->l4_remaining = 0; |
---|
[c1205bd] | 2326 | packet->refcount = 0; |
---|
[9cc1266] | 2327 | |
---|
| 2328 | } |
---|
| 2329 | |
---|
[c0506ea] | 2330 | void trace_interrupt(void) { |
---|
| 2331 | libtrace_halt = 1; |
---|
| 2332 | } |
---|
| 2333 | |
---|
[eda2def] | 2334 | void register_format(struct libtrace_format_t *f) { |
---|
| 2335 | assert(f->next==NULL); /* Can't register a format twice */ |
---|
| 2336 | f->next=formats_list; |
---|
| 2337 | formats_list=f; |
---|
| 2338 | |
---|
| 2339 | /* Now, verify that the format has at least the minimum functionality. |
---|
[9636216] | 2340 | * |
---|
[eda2def] | 2341 | * This #if can be changed to a 1 to output warnings about inconsistent |
---|
| 2342 | * functions being provided by format modules. This generally is very |
---|
| 2343 | * noisy, as almost all modules don't implement one or more functions |
---|
[9636216] | 2344 | * for various reasons. This is very useful when checking a new |
---|
[eda2def] | 2345 | * format module is sane. |
---|
[9636216] | 2346 | */ |
---|
[eda2def] | 2347 | #if 0 |
---|
| 2348 | if (f->init_input) { |
---|
| 2349 | #define REQUIRE(x) \ |
---|
| 2350 | if (!f->x) \ |
---|
| 2351 | fprintf(stderr,"%s: Input format should provide " #x "\n",f->name) |
---|
| 2352 | REQUIRE(read_packet); |
---|
| 2353 | REQUIRE(start_input); |
---|
| 2354 | REQUIRE(fin_input); |
---|
| 2355 | REQUIRE(get_link_type); |
---|
| 2356 | REQUIRE(get_capture_length); |
---|
| 2357 | REQUIRE(get_wire_length); |
---|
| 2358 | REQUIRE(get_framing_length); |
---|
| 2359 | REQUIRE(trace_event); |
---|
[9636216] | 2360 | if (!f->get_erf_timestamp |
---|
[eda2def] | 2361 | && !f->get_seconds |
---|
| 2362 | && !f->get_timeval) { |
---|
| 2363 | fprintf(stderr,"%s: A trace format capable of input, should provide at least one of\n" |
---|
| 2364 | "get_erf_timestamp, get_seconds or trace_timeval\n",f->name); |
---|
| 2365 | } |
---|
| 2366 | if (f->trace_event!=trace_event_trace) { |
---|
| 2367 | /* Theres nothing that a trace file could optimise with |
---|
| 2368 | * config_input |
---|
| 2369 | */ |
---|
| 2370 | REQUIRE(pause_input); |
---|
| 2371 | REQUIRE(config_input); |
---|
| 2372 | REQUIRE(get_fd); |
---|
| 2373 | } |
---|
| 2374 | else { |
---|
| 2375 | if (f->get_fd) { |
---|
| 2376 | fprintf(stderr,"%s: Unnecessary get_fd\n", |
---|
| 2377 | f->name); |
---|
| 2378 | } |
---|
| 2379 | } |
---|
| 2380 | #undef REQUIRE |
---|
| 2381 | } |
---|
| 2382 | else { |
---|
| 2383 | #define REQUIRE(x) \ |
---|
| 2384 | if (f->x) \ |
---|
| 2385 | fprintf(stderr,"%s: Non Input format shouldn't need " #x "\n",f->name) |
---|
| 2386 | REQUIRE(read_packet); |
---|
| 2387 | REQUIRE(start_input); |
---|
| 2388 | REQUIRE(pause_input); |
---|
| 2389 | REQUIRE(fin_input); |
---|
| 2390 | REQUIRE(get_link_type); |
---|
| 2391 | REQUIRE(get_capture_length); |
---|
| 2392 | REQUIRE(get_wire_length); |
---|
| 2393 | REQUIRE(get_framing_length); |
---|
| 2394 | REQUIRE(trace_event); |
---|
| 2395 | REQUIRE(get_seconds); |
---|
| 2396 | REQUIRE(get_timeval); |
---|
| 2397 | REQUIRE(get_erf_timestamp); |
---|
| 2398 | #undef REQUIRE |
---|
| 2399 | } |
---|
| 2400 | if (f->init_output) { |
---|
| 2401 | #define REQUIRE(x) \ |
---|
| 2402 | if (!f->x) \ |
---|
| 2403 | fprintf(stderr,"%s: Output format should provide " #x "\n",f->name) |
---|
| 2404 | REQUIRE(write_packet); |
---|
| 2405 | REQUIRE(start_output); |
---|
| 2406 | REQUIRE(config_output); |
---|
| 2407 | REQUIRE(fin_output); |
---|
| 2408 | #undef REQUIRE |
---|
| 2409 | } |
---|
| 2410 | else { |
---|
| 2411 | #define REQUIRE(x) \ |
---|
| 2412 | if (f->x) \ |
---|
| 2413 | fprintf(stderr,"%s: Non Output format shouldn't need " #x "\n",f->name) |
---|
| 2414 | REQUIRE(write_packet); |
---|
| 2415 | REQUIRE(start_output); |
---|
| 2416 | REQUIRE(config_output); |
---|
| 2417 | REQUIRE(fin_output); |
---|
| 2418 | #undef REQUIRE |
---|
| 2419 | } |
---|
| 2420 | #endif |
---|
| 2421 | } |
---|
| 2422 | |
---|