blob: c6665ee10cd82322b087d32ed7090479ba861b1f [file] [log] [blame]
/* $Id: util.c 91 2006-04-27 23:24:34Z lennart $ */
/***
This file is part of nss-mdns.
nss-mdns is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
nss-mdns 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 Lesser General Public
License along with nss-mdns; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/select.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include "util.h"
#ifdef ENABLE_LEGACY
/* Calculate the difference between the two specfified timeval
* timestamsps. */
usec_t timeval_diff(const struct timeval *a, const struct timeval *b) {
usec_t r;
assert(a && b);
/* Check which whan is the earlier time and swap the two arguments if reuqired. */
if (timeval_cmp(a, b) < 0) {
const struct timeval *c;
c = a;
a = b;
b = c;
}
/* Calculate the second difference*/
r = ((usec_t) a->tv_sec - b->tv_sec)* 1000000;
/* Calculate the microsecond difference */
if (a->tv_usec > b->tv_usec)
r += ((usec_t) a->tv_usec - b->tv_usec);
else if (a->tv_usec < b->tv_usec)
r -= ((usec_t) b->tv_usec - a->tv_usec);
return r;
}
/* Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */
int timeval_cmp(const struct timeval *a, const struct timeval *b) {
assert(a && 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;
}
/* Return the time difference between now and the specified timestamp */
usec_t timeval_age(const struct timeval *tv) {
struct timeval now;
assert(tv);
gettimeofday(&now, NULL);
return timeval_diff(&now, tv);
}
/* Add the specified time inmicroseconds to the specified timeval structure */
void timeval_add(struct timeval *tv, usec_t v) {
unsigned long secs;
assert(tv);
secs = (v/1000000);
tv->tv_sec += (unsigned long) secs;
v -= secs*1000000;
tv->tv_usec += v;
/* Normalize */
while (tv->tv_usec >= 1000000) {
tv->tv_sec++;
tv->tv_usec -= 1000000;
}
}
int set_nonblock(int fd) {
int n;
assert(fd >= 0);
if ((n = fcntl(fd, F_GETFL)) < 0)
return -1;
if (n & O_NONBLOCK)
return 0;
return fcntl(fd, F_SETFL, n|O_NONBLOCK);
}
int wait_for_write(int fd, struct timeval *end) {
struct timeval now;
if (end)
gettimeofday(&now, NULL);
for (;;) {
struct timeval tv;
fd_set fds;
int r;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (end) {
if (timeval_cmp(&now, end) >= 0)
return 1;
tv.tv_sec = tv.tv_usec = 0;
timeval_add(&tv, timeval_diff(end, &now));
}
if ((r = select(fd+1, NULL, &fds, NULL, end ? &tv : NULL)) < 0) {
if (errno != EINTR)
return -1;
} else if (r == 0)
return 1;
else {
if (FD_ISSET(fd, &fds))
return 0;
}
if (end)
gettimeofday(&now, NULL);
}
}
int wait_for_read(int fd, struct timeval *end) {
struct timeval now;
if (end)
gettimeofday(&now, NULL);
for (;;) {
struct timeval tv;
fd_set fds;
int r;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (end) {
if (timeval_cmp(&now, end) >= 0)
return 1;
tv.tv_sec = tv.tv_usec = 0;
timeval_add(&tv, timeval_diff(end, &now));
}
if ((r = select(fd+1, &fds, NULL, NULL, end ? &tv : NULL)) < 0) {
if (errno != EINTR)
return -1;
} else if (r == 0)
return 1;
else {
if (FD_ISSET(fd, &fds))
return 0;
}
if (end)
gettimeofday(&now, NULL);
}
}
#endif
int set_cloexec(int fd) {
int n;
assert(fd >= 0);
if ((n = fcntl(fd, F_GETFD)) < 0)
return -1;
if (n & FD_CLOEXEC)
return 0;
return fcntl(fd, F_SETFD, n|FD_CLOEXEC);
}