/* * General utility functions which don't have better places to live. * */ #include #include #include #include #include #include #include #include "common.h" #include "notify.h" /** timeval_diff * Calculate the difference between two timevals. * Lifted wholesale from the GNU libc manual. **/ int timeval_diff(struct timeval *result, struct timeval *x, struct timeval *y) { /* Perform the carry for the later subtraction by updating y. */ if (x->tv_usec < y->tv_usec) { int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; y->tv_usec -= 1000000 * nsec; y->tv_sec += nsec; } if (x->tv_usec - y->tv_usec > 1000000) { int nsec = (x->tv_usec - y->tv_usec) / 1000000; y->tv_usec += 1000000 * nsec; y->tv_sec -= nsec; } /* Compute the time remaining to wait. tv_usec is certainly positive. */ result->tv_sec = x->tv_sec - y->tv_sec; result->tv_usec = x->tv_usec - y->tv_usec; /* Return 1 if result is negative. */ return x->tv_sec < y->tv_sec; } /** timeval_increment * Increment one timeval by another. **/ void timeval_increment(struct timeval *result, struct timeval *diff) { const long u_factor = 1000000; result->tv_sec += diff->tv_sec; result->tv_usec += diff->tv_usec; if (result->tv_usec < 0) { result->tv_usec += u_factor; result->tv_sec--; } else if (result->tv_usec > u_factor) { result->tv_usec -= u_factor; result->tv_sec++; } } /** string_to_addrinfo_call * Attempt to parse a sockaddr ip and port out of a string, * calls ai_cb function with result (until one success, or * for all results depending on flag values). * * IPv6 addresses must be [bracketed]. (Because of colons.) * Accepts: * [ipv6]:port * ipv4:port * Returns: * 0 on valid parse * -1 on error **/ #define _CB_ITER_ALL (1<<0) int string_to_addrinfo_call(char *in, unsigned int flags, int (*ai_cb)(struct addrinfo *, void *), void *cb_data) { char *full_string, *port_start, *addr_start, *tmp; struct addrinfo hints, *res=NULL, *res_iter; int r; full_string = strdup(in); if (!full_string) { NOTIFY_ERROR("%s:%s", "strdup", strerror(errno) ); return -1; } addr_start = strchr(full_string, '['); if (addr_start) { *addr_start++ = '\0'; tmp = strchr(addr_start, ']'); if (!tmp) { NOTIFY_ERROR("invalid %saddress '%s': %s", "IPv6 ", in, "unmatched brackets"); free(full_string); return -1; } *tmp++ = '\0'; port_start = tmp; } else { addr_start = full_string; port_start = addr_start; } tmp = strrchr(port_start, ':'); if (!tmp) { NOTIFY_ERROR("invalid %saddress '%s': %s", "", in, "no port specified"); free(full_string); return -1; } *tmp++ = '\0'; port_start = tmp; /* We now have address and port as separate strings */ memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; /* bind to equiv of INADDR_ANY for any AF, if address is specified as '*' */ if (strcmp(addr_start, "*") == 0) { hints.ai_flags |= AI_PASSIVE; addr_start = NULL; } r = getaddrinfo(addr_start, port_start, &hints, &res); if (r) { NOTIFY_ERROR("%s:%s", "getaddrinfo", gai_strerror(r)); free(full_string); return -1; } for (res_iter = res; res_iter; res_iter = res_iter->ai_next) { r = ai_cb(res_iter, cb_data); if (r) { NOTIFY_DEBUG("%s:%d", "(ai_cb)", r); continue; } if (! (flags & _CB_ITER_ALL)) { break; } } freeaddrinfo(res); free(full_string); return 0; }