/* * scamper_file.c * * $Id: scamper_file.c,v 1.32 2007/10/16 01:44:28 mjl Exp $ * * entry points to read/write scamper traceroute and warts files, and to * read skitter arts files. * * Copyright (C) 2004-2007 The University of Waikato * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include #if defined(__APPLE__) #include #endif #if defined(DMALLOC) #include #endif #include #include "scamper_addr.h" #include "scamper_list.h" #include "scamper_tlv.h" #include "scamper_trace.h" #include "scamper_ping.h" #include "scamper_file.h" #include "scamper_file_warts.h" #include "scamper_file_traceroute.h" #include "scamper_file_arts.h" #include "utils.h" #define SCAMPER_FILE_NONE (-1) #define SCAMPER_FILE_TRACEROUTE 0 #define SCAMPER_FILE_ARTS 1 #define SCAMPER_FILE_WARTS 2 struct scamper_file { char *filename; int fd; void *state; int type; char error_str[256]; uint32_t capability; int eof; }; struct scamper_file_filter { uint32_t *flags; uint16_t max; }; struct handler { char *type; int (*detect)(const scamper_file_t *sf); int (*init_read)(scamper_file_t *sf); int (*init_write)(scamper_file_t *sf); int (*init_append)(scamper_file_t *sf); int (*read)(scamper_file_t *sf, scamper_file_filter_t *filter, uint16_t *type, void **data); int (*write_trace)(const scamper_file_t *sf, const scamper_trace_t *trace); int (*write_cycle_start)(const scamper_file_t *sf, scamper_cycle_t *cycle); int (*write_cycle_stop)(const scamper_file_t *sf, scamper_cycle_t *cycle); int (*write_ping)(const scamper_file_t *sf, const scamper_ping_t *ping); void (*free_state)(scamper_file_t *sf); }; static struct handler handlers[] = { {"traceroute", /* type */ scamper_file_traceroute_is, /* detect */ scamper_file_traceroute_init_read, /* init_read */ NULL, /* init_write */ NULL, /* init_append */ NULL, /* read */ scamper_file_traceroute_write_trace, /* write_trace */ NULL, /* write_cycle_start */ NULL, /* write_cycle_stop */ scamper_file_traceroute_write_ping, /* write_ping */ scamper_file_traceroute_free_state, /* free_state */ }, {"arts", /* type */ scamper_file_arts_is, /* detect */ scamper_file_arts_init_read, /* init_read */ NULL, /* init_write */ NULL, /* init_append */ scamper_file_arts_read, /* read */ NULL, /* write_trace */ NULL, /* write_cycle_start */ NULL, /* write_cycle_stop */ NULL, /* write_ping */ scamper_file_arts_free_state, /* free_state */ }, {"warts", /* type */ scamper_file_warts_is, /* detect */ scamper_file_warts_init_read, /* init_read */ scamper_file_warts_init_write, /* init_write */ scamper_file_warts_init_append, /* init_append */ scamper_file_warts_read, /* read */ scamper_file_warts_write_trace, /* write_trace */ scamper_file_warts_write_cycle_start, /* write_cycle_start */ scamper_file_warts_write_cycle_stop, /* write_cycle_stop */ scamper_file_warts_write_ping, /* write_ping */ scamper_file_warts_free_state, /* free_state */ } }; static int handler_cnt = sizeof(handlers) / sizeof(struct handler); int scamper_file_getfd(const scamper_file_t *sf) { return sf->fd; } void *scamper_file_getstate(const scamper_file_t *sf) { return sf->state; } char *scamper_file_getfilename(scamper_file_t *sf) { return sf->filename; } void scamper_file_setstate(scamper_file_t *sf, void *state) { sf->state = state; return; } int scamper_file_write_trace(scamper_file_t *sf, const scamper_trace_t *trace) { int rc = -1; if(sf->type != SCAMPER_FILE_NONE && handlers[sf->type].write_trace != NULL) { rc = handlers[sf->type].write_trace(sf, trace); } return rc; } int scamper_file_write_ping(scamper_file_t *sf, const scamper_ping_t *ping) { if(sf->type != SCAMPER_FILE_NONE && handlers[sf->type].write_ping != NULL) { return handlers[sf->type].write_ping(sf, ping); } return -1; } /* * scamper_file_read * * */ int scamper_file_read(scamper_file_t *sf, scamper_file_filter_t *filter, uint16_t *type, void **object) { if(sf->type != SCAMPER_FILE_NONE && handlers[sf->type].read != NULL) { return handlers[sf->type].read(sf, filter, type, object); } return -1; } /* * scamper_file_filter_isset * * check to see if the particular type is set in the filter or not */ int scamper_file_filter_isset(scamper_file_filter_t *filter, uint16_t type) { if(filter == NULL || type > filter->max) { return 0; } if((filter->flags[type/32] & (0x1 << ((type%32)-1))) == 0) { return 0; } return 1; } /* * scamper_file_filter_alloc * * allocate a filter for reading data objects from scamper files based on an * array of types the caller is interested in. */ scamper_file_filter_t *scamper_file_filter_alloc(uint16_t *types, uint16_t num) { scamper_file_filter_t *filter = NULL; size_t size; int i, j, k; /* sanity checks */ if(types == NULL || num == 0) { goto err; } /* allocate filter structure which will be returned to caller */ if((filter = malloc_zero(sizeof(scamper_file_filter_t))) == NULL) { goto err; } /* first, figure out the maximum type value of interest */ for(i=0; i filter->max) { filter->max = types[i]; } } /* sanity check */ if(filter->max == 0) { goto err; } /* allocate the flags array */ size = sizeof(uint32_t) * filter->max / 32; if((filter->max % 32) != 0) size += sizeof(uint32_t); if((filter->flags = malloc_zero(size)) == NULL) { goto err; } /* go through each type and set the appropriate flag */ for(i=0; iflags[j] |= (0x1 << (k-1)); } return filter; err: if(filter != NULL) { if(filter->flags != NULL) free(filter->flags); free(filter); } return NULL; } void scamper_file_filter_free(scamper_file_filter_t *filter) { if(filter != NULL) { if(filter->flags != NULL) free(filter->flags); free(filter); } return; } int scamper_file_write_cycle_start(scamper_file_t *sf, scamper_cycle_t *cycle) { if(sf->type != SCAMPER_FILE_NONE && handlers[sf->type].write_cycle_start != NULL) { return handlers[sf->type].write_cycle_start(sf, cycle); } return -1; } int scamper_file_write_cycle_stop(scamper_file_t *sf, scamper_cycle_t *cycle) { if(sf->type != SCAMPER_FILE_NONE && handlers[sf->type].write_cycle_stop != NULL) { return handlers[sf->type].write_cycle_stop(sf, cycle); } return -1; } /* * scamper_file_geteof * */ int scamper_file_geteof(scamper_file_t *sf) { if(sf == NULL || sf->fd == -1) return -1; return sf->eof; } /* * scamper_file_seteof * */ void scamper_file_seteof(scamper_file_t *sf) { if(sf != NULL && sf->fd != -1) sf->eof = 1; return; } /* * scamper_file_free * */ void scamper_file_free(scamper_file_t *sf) { if(sf != NULL) { if(sf->filename) free(sf->filename); free(sf); } return; } /* * scamper_file_close * */ void scamper_file_close(scamper_file_t *sf) { /* free state associated with the type of scamper_file_t */ if(sf->type != SCAMPER_FILE_NONE && handlers[sf->type].free_state != NULL) { handlers[sf->type].free_state(sf); } /* close the file descriptor */ if(sf->fd != -1) { close(sf->fd); } /* free general state associated */ scamper_file_free(sf); return; } char *scamper_file_type_tostr(scamper_file_t *sf, char *buf, size_t len) { if(sf->type != SCAMPER_FILE_NONE && handlers[sf->type].type != NULL) { strncpy(buf, handlers[sf->type].type, len); return buf; } return NULL; } static int file_type_get(char *type) { int i; if(type != NULL) { for(i=0; ifd, &sb) != 0) { return -1; } if(sb.st_size != 0 && (sb.st_mode & S_IFIFO) == 0 && (sf->type = file_type_detect(sf)) == SCAMPER_FILE_NONE) { return -1; } if(handlers[sf->type].init_read != NULL) { return handlers[sf->type].init_read(sf); } return 0; } static int file_open_write(scamper_file_t *sf) { if(sf->type != SCAMPER_FILE_NONE && handlers[sf->type].init_write != NULL) { return handlers[sf->type].init_write(sf); } return 0; } static int file_open_append(scamper_file_t *sf) { struct stat sb; if(fstat(sf->fd, &sb) != 0) { return -1; } if(sb.st_size == 0) { /* can only write warts and ascii files */ if(sf->type == SCAMPER_FILE_WARTS) { return handlers[sf->type].init_write(sf); } else if(sf->type == SCAMPER_FILE_TRACEROUTE) { return 0; } return -1; } /* can't append to pipes */ if((sb.st_mode & S_IFIFO) != 0) { return -1; } sf->type = file_type_detect(sf); if(handlers[sf->type].init_append != NULL) { return handlers[sf->type].init_append(sf); } else if(sf->type != SCAMPER_FILE_WARTS && sf->type != SCAMPER_FILE_TRACEROUTE) { return -1; } return 0; } static scamper_file_t *file_open(int fd, char *fn, char mode, int type) { scamper_file_t *sf; int (*open_func)(scamper_file_t *); if(mode == 'r') open_func = file_open_read; else if(mode == 'w') open_func = file_open_write; else if(mode == 'a') open_func = file_open_append; else return NULL; if((sf = (scamper_file_t *)malloc_zero(sizeof(scamper_file_t))) == NULL) { return NULL; } sf->type = type; sf->fd = fd; if(fn != NULL && (sf->filename = strdup(fn)) == NULL) { return NULL; } if(open_func(sf) == -1) { scamper_file_close(sf); return NULL; } return sf; } scamper_file_t *scamper_file_openfd(int fd, char *fn, char mode, char *type) { return file_open(fd, fn, mode, file_type_get(type)); } /* * scamper_file_open * * open the file specified with the appropriate mode. * the modes that we know about are 'r' read-only, 'w' write-only on a * brand new file, and 'a' for appending. * * in 'w' mode [and conditionally for 'a'] an optional parameter may be * supplied that says what type of file should be written. * 'w' for warts * 't' for ascii traceroute * 'a' for arts [not implemented] * * when a file is opened for appending, this second parameter is only * used when the file is empty so that writes will be written in the * format expected. */ scamper_file_t *scamper_file_open(char *filename, char mode, char *type) { scamper_file_t *sf; int ft = file_type_get(type); int flags = 0; int fd = -1; if(mode == 'r') { if(strcmp(filename, "-") == 0) { fd = STDIN_FILENO; } else { flags = O_RDONLY; } } else if(mode == 'w' || mode == 'a') { /* sanity check the type of file to be written */ if(ft == SCAMPER_FILE_NONE || ft == SCAMPER_FILE_ARTS) { return NULL; } if(strcmp(filename, "-") == 0) { fd = STDIN_FILENO; } else { if(mode == 'w') flags = O_WRONLY | O_TRUNC | O_CREAT; else flags = O_RDWR | O_APPEND | O_CREAT; } } else { return NULL; } if(fd == -1) { if(mode == 'r') fd = open(filename, flags); else fd = open(filename, flags, S_IRUSR | S_IWUSR); if(fd == -1) { return NULL; } } sf = file_open(fd, filename, mode, ft); return sf; }