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