--- /dev/null
+/*
+ * General utility functions which don't have better places to live.
+ *
+ */
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <string.h>
+#include <errno.h>
+
+#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;
+}