X-Git-Url: http://git.thejh.net/?p=detour.git;a=blobdiff_plain;f=common.c;h=a2a4ca0950ef9f8c83ca02038998f70f6cfb6753;hp=d45457bf5295424e9c904b6caa8aa3d702a358fa;hb=3182add0e964daa8e7a5b4b8fbf35c389fd0de89;hpb=99743142a6ff0f0c8ea2acdf8863cede4689d7eb;ds=inline diff --git a/common.c b/common.c index d45457b..a2a4ca0 100644 --- a/common.c +++ b/common.c @@ -1,9 +1,116 @@ +// This file is basically utility functions from various places mashed together, including +// from my helper library libjh. + #include #include -#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define JH_TCP_HINTS (&libjh_tcp_hints) +const struct addrinfo libjh_tcp_hints = { + .ai_flags = AI_ADDRCONFIG, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = 0 +}; + +int netopen_server(const char *node /*NULL for ANY*/, const char *service, const struct addrinfo *hints) { + struct addrinfo hints_; + if (hints == &libjh_tcp_hints) { + hints_ = *hints; + hints_.ai_flags |= AI_PASSIVE; + hints_.ai_flags &= ~AI_ADDRCONFIG; + hints = &hints_; + } + + struct addrinfo *addrs; + int gai_res = getaddrinfo(node, service, hints, &addrs); + if (gai_res) return gai_res; + + int s = socket(addrs[0].ai_family, addrs[0].ai_socktype, addrs[0].ai_protocol); + if (s == -1) goto err_socket; + + if (bind(s, addrs[0].ai_addr, addrs[0].ai_addrlen)) goto err_bind_n_listen; + if (listen(s, 16)) goto err_bind_n_listen; + + freeaddrinfo(addrs); + return s; + +err_bind_n_listen:; + int errno_ = errno; + close(s); + errno = errno_; +err_socket: + freeaddrinfo(addrs); + return EAI_SYSTEM; +} + +ssize_t read_nointr(int fd, void *buf, size_t count, int *last_res) { + errno = 0; + size_t done = 0; + while (done < count) { + ssize_t part_res = read(fd, buf+done, count-done); + if (part_res == -1 && errno == EINTR) continue; + if (part_res <= 0) { + if (last_res) *last_res = part_res; + if (done) return done; + return part_res; + } + done += part_res; + } + if (last_res) *last_res = 1; + return done; +} + +void *slurp_fd(int fd, size_t *len_out) { + int errno_; + + size_t size_guess; + + struct stat st; + if (fstat(fd, &st) == 0) { + if (st.st_size > 0) { + size_guess = st.st_size; + } + } + + char *buf = NULL; + int done = 0; + + while (1) { + buf = realloc(buf, size_guess); + if (buf == NULL) return NULL; + int last_res; + ssize_t read_res = read_nointr(fd, buf+done, size_guess-done, &last_res); + if (last_res == -1) { errno_=errno; free(buf); errno=errno_; return NULL; } + done += read_res; + if (len_out) *len_out = done; + return buf; + } +} + +void *slurp_file(char *path, size_t *len_out) { + int fd = open(path, O_RDONLY|O_CLOEXEC); + if (fd == -1) return NULL; + char *res = slurp_fd(fd, len_out); + int errno_ = errno; + close(fd); + errno = errno_; + return res; +} time_t real_seconds(void) { struct timespec t; @@ -15,23 +122,23 @@ time_t real_seconds(void) { /* Subtract the `struct timeval' values X and Y, storing the result in RESULT. Return 1 if the difference is negative, otherwise 0. */ -int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) { +int timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *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; + if (x->tv_nsec < y->tv_nsec) { + int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1; + y->tv_nsec -= 1000000000 * 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; + if (x->tv_nsec - y->tv_nsec > 1000000000) { + int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000; + y->tv_nsec += 1000000000 * 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; + result->tv_nsec = x->tv_nsec - y->tv_nsec; /* Return 1 if result is negative. */ return x->tv_sec < y->tv_sec;