/***
This file was part of nss-mdns.
Cross platform support & limited responder support by Tony Hoyle, 2005.
mdnsclient 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.
mdnsclient 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
#ifndef _WIN32
#include <sys/types.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <sys/socket.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#endif
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <fcntl.h>
#include "mdnsclient.h"
#include "util.h"
/* u_int64_t is sufficiently uncommon to require this */
#ifdef _WIN32
typedef unsigned __int64 local_u_int64_t;
#else
typedef unsigned long long local_u_int64_t;
#endif
/* 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) {
local_u_int64_t secs;
assert(tv);
secs = (v/1000000);
tv->tv_sec += (unsigned long) secs;
v -= secs*1000000;
tv->tv_usec += (long)v;
/* Normalize */
while (tv->tv_usec >= 1000000) {
tv->tv_sec++;
tv->tv_usec -= 1000000;
}
}
int set_cloexec(sock_t fd)
{
#ifndef _WIN32
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);
#else
return 0;
#endif
}
int set_nonblock(sock_t fd)
{
#ifndef _WIN32
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);
#else
int n = 1;
if (ioctlsocket(fd, FIONBIO, &n) == SOCKET_ERROR)
{
return -1;
}
return 0;
#endif
}
int wait_for_write(sock_t 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((int)fd+1, NULL, &fds, NULL, end ? &tv : NULL)) < 0) {
if (errno != EINTR) {
fprintf(stderr, "select() failed: %s\n", strerror(errno));
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(sock_t 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((int)fd+1, &fds, NULL, NULL, end ? &tv : NULL)) < 0) {
if (errno != EINTR) {
fprintf(stderr, "select() failed: %s\n", strerror(errno));
return -1;
}
} else if (r == 0)
return 1;
else {
if (FD_ISSET(fd, &fds))
return 0;
}
if (end)
gettimeofday(&now, NULL);
}
}
syntax highlighted by Code2HTML, v. 0.9.1