/*
* 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 <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#if defined(__APPLE__)
#include <stdint.h>
#endif
#if defined(DMALLOC)
#include <dmalloc.h>
#endif
#include <assert.h>
#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<num; i++)
{
/* sanity check */
if(types[i] == 0)
{
goto err;
}
if(types[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; i<num; i++)
{
if(types[i] % 32 == 0)
{
j = ((types[i]) / 32) - 1;
k = 32;
}
else
{
j = types[i] / 32;
k = types[i] % 32;
}
filter->flags[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; i<handler_cnt; i++)
{
if(strcasecmp(type, handlers[i].type) == 0)
{
return i;
}
}
}
return SCAMPER_FILE_NONE;
}
static int file_type_detect(scamper_file_t *sf)
{
int i;
for(i=0; i<handler_cnt; i++)
{
if(handlers[i].detect(sf) == 1)
{
return i;
}
}
return SCAMPER_FILE_NONE;
}
static int file_open_read(scamper_file_t *sf)
{
struct stat sb;
if(fstat(sf->fd, &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;
}
syntax highlighted by Code2HTML, v. 0.9.1