/* * utils.c * * $Id: utils.c,v 1.69 2007/05/18 03:35:23 mjl Exp $ * * Copyright (C) 2003-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 * */ #if defined(__APPLE__) #define _BSD_SOCKLEN_T_ #define HAVE_SOCKADDR_SA_LEN #define HAVE_OSSWAPINT16 #include #include #endif #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) #define HAVE_SOCKADDR_SA_LEN #endif #include #include #include #include #include #include #include #if !defined(__sun__) #include #endif #include #include #if defined(AF_LINK) #include #endif #include #include #include #include #include #include #include #include #include #include #include #if defined(DMALLOC) #include #endif #if defined(__sun__) # define s6_addr32 _S6_un._S6_u32 #elif !defined(s6_addr32) # define s6_addr32 __u6_addr.__u6_addr32 #endif #if defined(__linux__) #include #endif #include "utils.h" #if defined(HAVE_SOCKADDR_SA_LEN) int sockaddr_len(const struct sockaddr *sa) { return sa->sa_len; } #else int sockaddr_len(const struct sockaddr *sa) { if(sa->sa_family == AF_INET) return sizeof(struct sockaddr_in); if(sa->sa_family == AF_INET6) return sizeof(struct sockaddr_in6); #if defined(AF_LINK) if(sa->sa_family == AF_LINK) return sizeof(struct sockaddr_dl); #endif return -1; } #endif void *addr_dup(const int af, const void *addr_in) { void *addr; size_t size; if(af == AF_INET) { size = sizeof(struct in_addr); } else if(af == AF_INET6) { size = sizeof(struct in6_addr); } else return NULL; if((addr = malloc(size)) != NULL) { memcpy(addr, addr_in, size); } return addr; } struct sockaddr *sockaddr_dup(const struct sockaddr *sa) { struct sockaddr *addr; int len; if((len = sockaddr_len(sa)) <= 0) { return NULL; } if((addr = malloc((size_t)len)) != NULL) { memcpy(addr, sa, (size_t)len); } return addr; } int sockaddr_compose(struct sockaddr *sa, const int af, const void *addr, const int port) { socklen_t len; struct sockaddr_in *sin4; struct sockaddr_in6 *sin6; assert(port >= 0); assert(port <= 65535); if(af == AF_INET) { len = sizeof(struct sockaddr_in); memset(sa, 0, len); sin4 = (struct sockaddr_in *)sa; if(addr != NULL) memcpy(&sin4->sin_addr, addr, sizeof(struct in_addr)); sin4->sin_port = htons(port); } else if(af == AF_INET6) { len = sizeof(struct sockaddr_in6); memset(sa, 0, len); sin6 = (struct sockaddr_in6 *)sa; if(addr != NULL) memcpy(&sin6->sin6_addr, addr, sizeof(struct in6_addr)); sin6->sin6_port = htons(port); } else return -1; #if defined(HAVE_SOCKADDR_SA_LEN) sa->sa_len = len; #endif sa->sa_family = af; return 0; } char *sockaddr_tostr(const struct sockaddr *sa, char *buf, const size_t len) { char addr[128]; if(sa->sa_family == AF_INET) { if(inet_ntop(AF_INET, &((const struct sockaddr_in *)sa)->sin_addr, addr, sizeof(addr)) == NULL) { return NULL; } snprintf(buf, len, "%s:%d", addr, ((const struct sockaddr_in *)sa)->sin_port); } else if(sa->sa_family == AF_INET6) { if(inet_ntop(AF_INET6, &((const struct sockaddr_in6 *)sa)->sin6_addr, addr, sizeof(addr)) == NULL) { return NULL; } snprintf(buf, len, "%s.%d", addr, ((const struct sockaddr_in6 *)sa)->sin6_port); } else { return NULL; } return buf; } int addr4_cmp(const void *va, const void *vb) { const struct in_addr *a = (const struct in_addr *)va; const struct in_addr *b = (const struct in_addr *)vb; if(a->s_addr < b->s_addr) return -1; if(a->s_addr > b->s_addr) return 1; return 0; } int addr6_cmp(const void *va, const void *vb) { const struct in6_addr *a = (const struct in6_addr *)va; const struct in6_addr *b = (const struct in6_addr *)vb; int i; for(i=0; i<4; i++) { if(a->s6_addr32[i] < b->s6_addr32[i]) return -1; if(a->s6_addr32[i] > b->s6_addr32[i]) return 1; } return 0; } /* * addr_cmp: * this function is used to provide a sorting order, not for advising the * numerical order of the addresses passed in. */ int addr_cmp(int af, const void *a, const void *b) { if(af == AF_INET) return addr4_cmp(a, b); if(af == AF_INET6) return addr6_cmp(a, b); return 0; } /* * memdup * * duplicate some memory. */ #ifndef DMALLOC void *memdup(const void *ptr, const size_t len) { void *d; if((d = malloc(len)) != NULL) { memcpy(d, ptr, len); } return d; } #endif /* * malloc_zero * * allocate some memory, zero it, and return a pointer to it. */ #if !defined(DMALLOC) void *malloc_zero(const size_t size) { void *ptr; if((ptr = malloc(size)) != NULL) { memset(ptr, 0, size); } return ptr; } #endif int gettimeofday_wrap(struct timeval *tv) { struct timezone tz; return gettimeofday(tv, &tz); } int timeval_cmp(const struct timeval *a, const struct timeval *b) { if(a->tv_sec < b->tv_sec) return -1; if(a->tv_sec > b->tv_sec) return 1; if(a->tv_usec < b->tv_usec) return -1; if(a->tv_usec > b->tv_usec) return 1; return 0; } void timeval_add_msec(struct timeval *tv, const int msec) { tv->tv_sec += (msec / 1000); tv->tv_usec += ((msec % 1000) * 1000); /* check for overflow of usec's */ if(tv->tv_usec >= 1000000) { tv->tv_sec++; tv->tv_usec -= 1000000; } else if(tv->tv_usec < 0) { tv->tv_sec--; tv->tv_usec += 1000000; } return; } /* * timeval_diff_msec * return the millisecond difference between the two timevals. * a - b */ int64_t timeval_diff_msec(const struct timeval *a, const struct timeval *b) { int64_t temp, a_sec, a_usec, b_sec, b_usec; a_sec = (int64_t)a->tv_sec * (int64_t)1000; a_usec = (int64_t)a->tv_usec / (int64_t)1000; b_sec = (int64_t)b->tv_sec * (int64_t)1000; b_usec = (int64_t)b->tv_usec / (int64_t)1000; temp = a_sec - b_sec + a_usec - b_usec; return temp; } void timeval_add_usec(struct timeval *tv, const int64_t usec) { tv->tv_sec += (usec / 1000000); tv->tv_usec += (usec % 1000000); /* check for underflow */ if(tv->tv_usec < 0) { tv->tv_sec--; tv->tv_usec += 1000000; } /* check for overflow */ else if(tv->tv_usec >= 1000000) { tv->tv_sec++; tv->tv_usec -= 1000000; } return; } /* * timeval_add_tv * * given a timeval struct, add the time in the second timeval struct to * it. */ void timeval_add_tv(struct timeval *tv, const struct timeval *add) { assert(add->tv_sec >= 0); assert(add->tv_usec >= 0); tv->tv_usec += add->tv_usec; /* check for overflow */ if(tv->tv_usec > 1000000) { tv->tv_sec++; tv->tv_usec -= 1000000; } tv->tv_sec += add->tv_sec; return; } /* * timeval_diff_usec * return the microsecond difference between the two timevals. * a - b */ int64_t timeval_diff_usec(const struct timeval *a, const struct timeval *b) { int64_t temp, a_sec, b_sec; a_sec = (int64_t)a->tv_sec * (int64_t)1000000; b_sec = (int64_t)b->tv_sec * (int64_t)1000000; temp = a_sec - b_sec + a->tv_usec - b->tv_usec; return temp; } void timeval_rtt(struct timeval *rtt, const struct timeval *from, const struct timeval *to) { rtt->tv_sec = to->tv_sec - from->tv_sec; rtt->tv_usec = to->tv_usec - from->tv_usec; if(rtt->tv_usec < 0) { rtt->tv_sec--; rtt->tv_usec += 1000000; } return; } void timeval_cpy(struct timeval *dst, const struct timeval *src) { memcpy(dst, src, sizeof(struct timeval)); return; } int fcntl_unset(const int fd, const int flags) { int i; if((i = fcntl(fd, F_GETFL, 0)) == -1) { return -1; } if(fcntl(fd, F_SETFL, i & (~flags)) == -1) { return -1; } return 0; } int fcntl_set(const int fd, const int flags) { int i; if((i = fcntl(fd, F_GETFL, 0)) == -1) { return -1; } if(fcntl(fd, F_SETFL, i | flags) == -1) { return -1; } return 0; } int string_isprint(const char *str, const size_t len) { size_t i = 0; for(i=0; i= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { return 1; } return 0; } int read_wrap(const int fd, void *ptr, size_t *rc_out, const size_t rt) { uint8_t *buf; int ret = 0; ssize_t r; size_t rc; assert(rt > 0); assert(ptr != NULL); buf = (uint8_t *)ptr; for(rc = 0; rc < rt; rc += r) { if((r = read(fd, buf+rc, rt-rc)) < 0) { if(errno == EINTR) { r = 0; continue; } ret = -1; break; } else if(r == 0) { ret = -2; break; } } if(rc_out != NULL) { *rc_out = rc; } return ret; } int write_wrap(const int fd, const void *ptr, size_t *wc_out, const size_t wt) { int ret = 0; ssize_t w; size_t wc; assert(wt > 0); assert(ptr != NULL); for(wc = 0; wc < wt; wc += w) { if((w = write(fd, ((const uint8_t *)ptr)+wc, wt-wc)) < 0) { if(errno == EINTR) { w = 0; continue; } ret = -1; break; } } if(wc_out != NULL) { *wc_out = wc; } return ret; } /* * mkdir_wrap * * iteratively call mkdir until the full path has been created */ int mkdir_wrap(const char *path, mode_t mode) { char *d = NULL; char *ptr; /* ensure there is actually a path to create ... */ if(path[0] == '\0' || (path[0] == '/' && path[1] == '\0')) { return 0; } /* make a duplicate copy of the path that we are going to create */ if((d = strdup(path)) == NULL) { goto err; } ptr = d; /* don't need to create the root directory ... */ if(ptr[0] == '/') ptr++; while(ptr[0] != '\0') { if(ptr[0] == '/') { /* temporarily replace the path delimeter */ ptr[0] = '\0'; if(mkdir(d, mode) != 0 && errno != EEXIST) { goto err; } ptr[0] = '/'; } ptr++; } /* create the last directory in the path */ if(ptr[-1] != '/') { if(mkdir(d, mode) != 0 && errno != EEXIST) { goto err; } } free(d); return 0; err: if(d != NULL) free(d); return -1; } /* * fstat_mtime * * simple utility function that gets the mtime field from * a fstat call as a time_t. */ int fstat_mtime(int fd, time_t *mtime) { struct stat sb; if(fstat(fd, &sb) != 0) { return -1; } *mtime = sb.st_mtime; return 0; } /* * stat_mtime * * simple utility function that gets the mtime field from * a stat call as a time_t. */ int stat_mtime(const char *filename, time_t *mtime) { struct stat sb; if(stat(filename, &sb) != 0) { return -1; } *mtime = sb.st_mtime; return 0; } #if !defined(__sun__) int sysctl_wrap(int *mib, u_int len, void **buf, size_t *size) { if(sysctl(mib, len, NULL, size, NULL, 0) != 0) { return -1; } if(*size == 0) { *buf = NULL; return 0; } if((*buf = malloc(*size)) == NULL) { return -1; } if(sysctl(mib, len, *buf, size, NULL, 0) != 0) { free(*buf); return -1; } return 0; } #endif uint16_t in_cksum(const void *buf, const size_t len) { uint16_t *w = (uint16_t *)buf; size_t l = len; int sum = 0; while(l > 1) { sum += *w++; l -= 2; } if(l != 0) { sum += ((uint8_t *)w)[0]; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return ~sum; } static void uuencode_3(uint8_t *out, uint8_t a, uint8_t b, uint8_t c) { uint8_t t; out[0] = (t = ((a >> 2) & 0x3f)) != 0 ? t + 32 : '`'; out[1] = (t = (((a << 4) | ((b >> 4) & 0xf)) & 0x3f)) != 0 ? t + 32 : '`'; out[2] = (t = (((b << 2) | ((c >> 6) & 0x3)) & 0x3f)) != 0 ? t + 32 : '`'; out[3] = (t = (c & 0x3f)) != 0 ? t + 32 : '`'; return; } int uuencode(const uint8_t *in, size_t ilen, uint8_t **out, size_t *olen) { uint8_t *ptr; size_t len; size_t complete_lines; size_t leftover_bytes; size_t i, j; if(ilen == 0) { return -1; } /* * figure out how many complete lines there are, * and then how many leftover bytes there are */ complete_lines = ilen / 45; leftover_bytes = ilen % 45; /* * an input line of 45 characters is transformed into an 60 character * sequence, with the length encoded as a character at the start, and * a new-line character at the end of the line */ len = (complete_lines * 62); /* * if there are leftover bytes, then each group of three characters * will take four output bytes. if the number of leftover bytes is not * a multiple of three, then they are encoded in a 4 character sequence. * finally, there's a length character at the start and a new line at the * end. */ if(leftover_bytes != 0) { len += ((leftover_bytes / 3) * 4); if((leftover_bytes % 3) > 0) { len += 4; } len += 2; } /* allocate the end-of-data bytes */ len += 2; /* allocate memory to encode the data to */ if((ptr = malloc(len)) == NULL) { return -1; } *out = ptr; *olen = len; /* encode all complete lines */ for(i=0; i 0) { uuencode_3(ptr, in[0], (leftover_bytes % 3) == 2 ? in[1] : 0, 0); ptr += 4; } *ptr = '\n'; ptr++; } /* this line has no data -- uuencode EOF */ *ptr = '`'; ptr++; *ptr = '\n'; return 0; } uint16_t byteswap16(const uint16_t word) { #if defined(HAVE_BSWAP16) return bswap(word); #elif defined(HAVE___BSWAP16) return __bswap16(word); #elif defined(HAVE___BSWAP_16) return __bswap_16(word); #elif defined(HAVE_OSSWAPINT16) return OSSwapInt16(word); #else return (((word & 0xff00) >> 8) | ((word & 0xff) << 8)); #endif } /* * uname_wrap * * do some basic parsing on the output from uname */ scamper_osinfo_t *uname_wrap(void) { struct utsname utsname; scamper_osinfo_t *osinfo; int i; char *str; /* call uname to get the information */ if(uname(&utsname) != 0) { return NULL; } /* allocate our wrapping struct */ if((osinfo = malloc(sizeof(scamper_osinfo_t))) == NULL) { return NULL; } memset(osinfo, 0, sizeof(scamper_osinfo_t)); /* copy sysname in */ if((osinfo->os = strdup(utsname.sysname)) == NULL) { goto err; } /* parse the OS name */ if(strcasecmp(osinfo->os, "FreeBSD") == 0) osinfo->os_id = SCAMPER_OSINFO_OS_FREEBSD; else if(strcasecmp(osinfo->os, "OpenBSD") == 0) osinfo->os_id = SCAMPER_OSINFO_OS_OPENBSD; else if(strcasecmp(osinfo->os, "NetBSD") == 0) osinfo->os_id = SCAMPER_OSINFO_OS_NETBSD; else if(strcasecmp(osinfo->os, "SunOS") == 0) osinfo->os_id = SCAMPER_OSINFO_OS_SUNOS; else if(strcasecmp(osinfo->os, "Linux") == 0) osinfo->os_id = SCAMPER_OSINFO_OS_LINUX; else if(strcasecmp(osinfo->os, "Darwin") == 0) osinfo->os_id = SCAMPER_OSINFO_OS_DARWIN; /* parse the release integer string */ i = 0; str = utsname.release; while(*str != '\0') { if(*str == '.') { *str = '\0'; osinfo->os_rel_dots++; } else if(isdigit((int)*str) == 0) { *str = '\0'; break; } str++; } if((osinfo->os_rel = malloc(osinfo->os_rel_dots * sizeof(int))) == NULL) { goto err; } i = 0; str = utsname.release; while(i < osinfo->os_rel_dots) { if(string_tolong(str, &osinfo->os_rel[i]) != 0) { goto err; } while(*str != '\0') str++; str++; i++; } return osinfo; err: if(osinfo->os != NULL) free(osinfo->os); if(osinfo->os_rel != NULL) free(osinfo->os_rel); free(osinfo); return NULL; } void scamper_osinfo_free(scamper_osinfo_t *osinfo) { if(osinfo != NULL) { if(osinfo->os != NULL) free(osinfo->os); if(osinfo->os_rel != NULL) free(osinfo->os_rel); free(osinfo); } return; }