Initial commit
This commit is contained in:
parent
db0abbb4c8
commit
a56b6e0b0f
|
@ -0,0 +1,573 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 02 Motoyuki Kasahara
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program provides getaddrinfo() and getnameinfo() described in
|
||||
* RFC2133, 2553 and 3493. These functions are mainly used for IPv6
|
||||
* application to resolve hostname or address.
|
||||
*
|
||||
* This program is designed to be working on traditional IPv4 systems
|
||||
* which don't have those functions. Therefore, this implementation
|
||||
* supports IPv4 only.
|
||||
*
|
||||
* This program is useful for application which should support both IPv6
|
||||
* and traditional IPv4 systems. Use genuine getaddrinfo() and getnameinfo()
|
||||
* provided by system if the system supports IPv6. Otherwise, use this
|
||||
* implementation.
|
||||
*
|
||||
* This program is intended to be used in combination with GNU Autoconf.
|
||||
*
|
||||
* This program also provides freeaddrinfo() and gai_strerror().
|
||||
*
|
||||
* To use this program in your application, insert the following lines to
|
||||
* C source files after including `sys/types.h', `sys/socket.h' and
|
||||
* `netdb.h'. `getaddrinfo.h' defines `struct addrinfo' and AI_, NI_,
|
||||
* EAI_ macros.
|
||||
*
|
||||
* #ifndef HAVE_GETADDRINFO
|
||||
* #include "agetaddrinfo.h"
|
||||
* #endif
|
||||
*
|
||||
* Restriction:
|
||||
* getaddrinfo() and getnameinfo() of this program are NOT thread
|
||||
* safe, unless the cpp macro ENABLE_PTHREAD is defined.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Add the following code to your configure.ac (or configure.in).
|
||||
* AC_C_CONST
|
||||
* AC_HEADER_STDC
|
||||
* AC_CHECK_HEADERS(string.h memory.h stdlib.h)
|
||||
* AC_CHECK_FUNCS(memcpy)
|
||||
* AC_REPLACE_FUNCS(memset)
|
||||
* AC_TYPE_SOCKLEN_T
|
||||
* AC_TYPE_IN_PORT_T
|
||||
* AC_DECL_H_ERRNO
|
||||
*
|
||||
* AC_CHECK_FUNCS(getaddrinfo getnameinfo)
|
||||
* if test "$ac_cv_func_getaddrinfo$ac_cv_func_getnameinfo" != yesyes ; then
|
||||
* LIBOBJS="$LIBOBJS getaddrinfo.$ac_objext"
|
||||
* fi
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "atimed.h"
|
||||
#include "agetaddrinfo.h"
|
||||
|
||||
#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
|
||||
#include <string.h>
|
||||
#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
|
||||
#include <memory.h>
|
||||
#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
|
||||
#else /* not STDC_HEADERS and not HAVE_STRING_H */
|
||||
#include <strings.h>
|
||||
#endif /* not STDC_HEADERS and not HAVE_STRING_H */
|
||||
|
||||
#ifdef ENABLE_PTHREAD
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
#include <libintl.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MEMCPY
|
||||
#define memcpy(d, s, n) bcopy((s), (d), (n))
|
||||
#ifdef __STDC__
|
||||
void *memchr(const void *, int, size_t);
|
||||
int memcmp(const void *, const void *, size_t);
|
||||
void *memmove(void *, const void *, size_t);
|
||||
void *memset(void *, int, size_t);
|
||||
#else /* not __STDC__ */
|
||||
char *memchr();
|
||||
int memcmp();
|
||||
char *memmove();
|
||||
char *memset();
|
||||
#endif /* not __STDC__ */
|
||||
#endif /* not HAVE_MEMCPY */
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
#define _(string) gettext(string)
|
||||
#ifdef gettext_noop
|
||||
#define N_(string) gettext_noop(string)
|
||||
#else
|
||||
#define N_(string) (string)
|
||||
#endif
|
||||
#else
|
||||
#define gettext(string) (string)
|
||||
#define _(string) (string)
|
||||
#define N_(string) (string)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Error messages for gai_strerror().
|
||||
*/
|
||||
static char *eai_errlist[] = {
|
||||
N_("Success"),
|
||||
|
||||
/* EAI_ADDRFAMILY */
|
||||
N_("Address family for hostname not supported"),
|
||||
|
||||
/* EAI_AGAIN */
|
||||
N_("Temporary failure in name resolution"),
|
||||
|
||||
/* EAI_BADFLAGS */
|
||||
N_("Invalid value for ai_flags"),
|
||||
|
||||
/* EAI_FAIL */
|
||||
N_("Non-recoverable failure in name resolution"),
|
||||
|
||||
/* EAI_FAMILY */
|
||||
N_("ai_family not supported"),
|
||||
|
||||
/* EAI_MEMORY */
|
||||
N_("Memory allocation failure"),
|
||||
|
||||
/* EAI_NONAME */
|
||||
N_("hostname nor servname provided, or not known"),
|
||||
|
||||
/* EAI_OVERFLOW */
|
||||
N_("An argument buffer overflowed"),
|
||||
|
||||
/* EAI_SERVICE */
|
||||
N_("servname not supported for ai_socktype"),
|
||||
|
||||
/* EAI_SOCKTYPE */
|
||||
N_("ai_socktype not supported"),
|
||||
|
||||
/* EAI_SYSTEM */
|
||||
N_("System error returned in errno")
|
||||
};
|
||||
|
||||
/*
|
||||
* Default hints for getaddrinfo().
|
||||
*/
|
||||
static struct addrinfo default_hints = {
|
||||
0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Mutex.
|
||||
*/
|
||||
#ifdef ENABLE_PTHREAD
|
||||
static pthread_mutex_t gai_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Declaration of static functions.
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
static int is_integer(const char *);
|
||||
static int is_address(const char *);
|
||||
static int itoa_length(int);
|
||||
#else
|
||||
static int is_integer();
|
||||
static int is_address();
|
||||
static int itoa_length();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* gai_strerror().
|
||||
*/
|
||||
const char *
|
||||
gai_strerror(ecode)
|
||||
int ecode;
|
||||
{
|
||||
if (ecode < 0 || ecode > EAI_SYSTEM)
|
||||
return _("Unknown error");
|
||||
|
||||
return gettext(eai_errlist[ecode]);
|
||||
}
|
||||
|
||||
/*
|
||||
* freeaddrinfo().
|
||||
*/
|
||||
void
|
||||
freeaddrinfo(ai)
|
||||
struct addrinfo *ai;
|
||||
{
|
||||
struct addrinfo *next_ai;
|
||||
|
||||
while (ai != NULL) {
|
||||
if (ai->ai_canonname != NULL)
|
||||
free(ai->ai_canonname);
|
||||
if (ai->ai_addr != NULL)
|
||||
free(ai->ai_addr);
|
||||
next_ai = ai->ai_next;
|
||||
free(ai);
|
||||
ai = next_ai;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 if the string `s' represents an integer.
|
||||
*/
|
||||
static int
|
||||
is_integer(s)
|
||||
const char *s;
|
||||
{
|
||||
if (*s == '-' || *s == '+')
|
||||
s++;
|
||||
if (*s < '0' || '9' < *s)
|
||||
return 0;
|
||||
|
||||
s++;
|
||||
while ('0' <= *s && *s <= '9')
|
||||
s++;
|
||||
|
||||
return (*s == '\0');
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 if the string `s' represents an IPv4 address.
|
||||
* Unlike inet_addr(), it doesn't permit malformed nortation such
|
||||
* as "192.168".
|
||||
*/
|
||||
static int
|
||||
is_address(s)
|
||||
const char *s;
|
||||
{
|
||||
const static char delimiters[] = {'.', '.', '.', '\0'};
|
||||
int i, j;
|
||||
int octet;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (*s == '0' && *(s + 1) != delimiters[i])
|
||||
return 0;
|
||||
for (j = 0, octet = 0; '0' <= *s && *s <= '9' && j < 3; s++, j++)
|
||||
octet = octet * 10 + (*s - '0');
|
||||
if (j == 0 || octet > 255 || *s != delimiters[i])
|
||||
return 0;
|
||||
s++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calcurate length of the string `s', where `s' is set by
|
||||
* sprintf(s, "%d", n).
|
||||
*/
|
||||
static int
|
||||
itoa_length(n)
|
||||
int n;
|
||||
{
|
||||
int result = 1;
|
||||
|
||||
if (n < 0) {
|
||||
n = -n;
|
||||
result++;
|
||||
}
|
||||
|
||||
while (n >= 10) {
|
||||
result++;
|
||||
n /= 10;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* getaddrinfo().
|
||||
*/
|
||||
int
|
||||
getaddrinfo(nodename, servname, hints, res)
|
||||
const char *nodename;
|
||||
const char *servname;
|
||||
const struct addrinfo *hints;
|
||||
struct addrinfo **res;
|
||||
{
|
||||
struct addrinfo *head_res = NULL;
|
||||
struct addrinfo *tail_res = NULL;
|
||||
struct addrinfo *new_res;
|
||||
struct sockaddr_in *sa_in;
|
||||
struct in_addr **addr_list;
|
||||
struct in_addr *addr_list_buf[2];
|
||||
struct in_addr addr_buf;
|
||||
struct in_addr **ap;
|
||||
struct servent *servent;
|
||||
struct hostent *hostent;
|
||||
const char *canonname = NULL;
|
||||
in_port_t port;
|
||||
int saved_h_errno;
|
||||
int result = 0;
|
||||
|
||||
#ifdef ENABLE_PTHREAD
|
||||
pthread_mutex_lock(&gai_mutex);
|
||||
#endif
|
||||
|
||||
saved_h_errno = h_errno;
|
||||
|
||||
if (nodename == NULL && servname == NULL) {
|
||||
result = EAI_NONAME;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (hints != NULL) {
|
||||
if (hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC) {
|
||||
result = EAI_FAMILY;
|
||||
goto end;
|
||||
}
|
||||
if (hints->ai_socktype != SOCK_DGRAM
|
||||
&& hints->ai_socktype != SOCK_STREAM
|
||||
&& hints->ai_socktype != 0) {
|
||||
result = EAI_SOCKTYPE;
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
hints = &default_hints;
|
||||
}
|
||||
|
||||
if (servname != NULL) {
|
||||
if (is_integer(servname))
|
||||
port = htons(atoi(servname));
|
||||
else {
|
||||
if (hints->ai_flags & AI_NUMERICSERV) {
|
||||
result = EAI_NONAME;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (hints->ai_socktype == SOCK_DGRAM)
|
||||
servent = getservbyname((char*)servname, (char*)"udp");
|
||||
else if (hints->ai_socktype == SOCK_STREAM)
|
||||
servent = getservbyname((char*)servname, (char*)"tcp");
|
||||
else if (hints->ai_socktype == 0)
|
||||
servent = getservbyname((char*)servname, (char*)"tcp");
|
||||
else {
|
||||
result = EAI_SOCKTYPE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (servent == NULL) {
|
||||
result = EAI_SERVICE;
|
||||
goto end;
|
||||
}
|
||||
port = servent->s_port;
|
||||
}
|
||||
} else {
|
||||
port = htons(0);
|
||||
}
|
||||
|
||||
if (nodename != NULL) {
|
||||
if (is_address(nodename)) {
|
||||
addr_buf.s_addr = inet_addr(nodename);
|
||||
addr_list_buf[0] = &addr_buf;
|
||||
addr_list_buf[1] = NULL;
|
||||
addr_list = addr_list_buf;
|
||||
|
||||
if (hints->ai_flags & AI_CANONNAME
|
||||
&& !(hints->ai_flags & AI_NUMERICHOST)) {
|
||||
hostent = gethostbyaddr((char *)&addr_buf,
|
||||
sizeof(struct in_addr), AF_INET);
|
||||
if (hostent != NULL)
|
||||
canonname = hostent->h_name;
|
||||
else
|
||||
canonname = nodename;
|
||||
}
|
||||
} else {
|
||||
if (hints->ai_flags & AI_NUMERICHOST) {
|
||||
result = EAI_NONAME;
|
||||
goto end;
|
||||
}
|
||||
|
||||
hostent = gethostbyname(nodename);
|
||||
if (hostent == NULL) {
|
||||
switch (h_errno) {
|
||||
case HOST_NOT_FOUND:
|
||||
case NO_DATA:
|
||||
result = EAI_NONAME;
|
||||
goto end;
|
||||
case TRY_AGAIN:
|
||||
result = EAI_AGAIN;
|
||||
goto end;
|
||||
default:
|
||||
result = EAI_FAIL;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
addr_list = (struct in_addr **)hostent->h_addr_list;
|
||||
|
||||
if (hints->ai_flags & AI_CANONNAME)
|
||||
canonname = hostent->h_name;
|
||||
}
|
||||
} else {
|
||||
if (hints->ai_flags & AI_PASSIVE)
|
||||
addr_buf.s_addr = htonl(INADDR_ANY);
|
||||
else
|
||||
addr_buf.s_addr = htonl(0x7F000001);
|
||||
addr_list_buf[0] = &addr_buf;
|
||||
addr_list_buf[1] = NULL;
|
||||
addr_list = addr_list_buf;
|
||||
}
|
||||
|
||||
for (ap = addr_list; *ap != NULL; ap++) {
|
||||
new_res = (struct addrinfo *)malloc(sizeof(struct addrinfo));
|
||||
if (new_res == NULL) {
|
||||
if (head_res != NULL)
|
||||
freeaddrinfo(head_res);
|
||||
result = EAI_MEMORY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
new_res->ai_family = PF_INET;
|
||||
new_res->ai_socktype = hints->ai_socktype;
|
||||
new_res->ai_protocol = hints->ai_protocol;
|
||||
new_res->ai_addr = NULL;
|
||||
new_res->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
new_res->ai_canonname = NULL;
|
||||
new_res->ai_next = NULL;
|
||||
|
||||
new_res->ai_addr = (struct sockaddr *)
|
||||
malloc(sizeof(struct sockaddr_in));
|
||||
if (new_res->ai_addr == NULL) {
|
||||
free(new_res);
|
||||
if (head_res != NULL)
|
||||
freeaddrinfo(head_res);
|
||||
result = EAI_MEMORY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
sa_in = (struct sockaddr_in *)new_res->ai_addr;
|
||||
memset(sa_in, 0, sizeof(struct sockaddr_in));
|
||||
sa_in->sin_family = PF_INET;
|
||||
sa_in->sin_port = port;
|
||||
memcpy(&sa_in->sin_addr, *ap, sizeof(struct in_addr));
|
||||
|
||||
if (head_res == NULL)
|
||||
head_res = new_res;
|
||||
else
|
||||
tail_res->ai_next = new_res;
|
||||
tail_res = new_res;
|
||||
}
|
||||
|
||||
if (canonname != NULL && head_res != NULL) {
|
||||
head_res->ai_canonname = (char *)malloc(strlen(canonname) + 1);
|
||||
if (head_res->ai_canonname != NULL)
|
||||
strcpy(head_res->ai_canonname, canonname);
|
||||
}
|
||||
|
||||
*res = head_res;
|
||||
|
||||
end:
|
||||
h_errno = saved_h_errno;
|
||||
#ifdef ENABLE_PTHREAD
|
||||
pthread_mutex_unlock(&gai_mutex);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *node, socklen_t nodelen, char *serv, socklen_t servlen, int flags) {
|
||||
|
||||
const struct sockaddr_in *sa_in = (const struct sockaddr_in *)sa;
|
||||
struct hostent *hostent;
|
||||
struct servent *servent;
|
||||
char *ntoa_address;
|
||||
int saved_h_errno;
|
||||
int result = 0;
|
||||
|
||||
#ifdef ENABLE_PTHREAD
|
||||
pthread_mutex_lock(&gai_mutex);
|
||||
#endif
|
||||
|
||||
saved_h_errno = h_errno;
|
||||
|
||||
if (sa_in->sin_family != PF_INET) {
|
||||
result = EAI_FAMILY;
|
||||
goto end;
|
||||
} else if (node == NULL && serv == NULL) {
|
||||
result = EAI_NONAME;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (serv != NULL && servlen > 0) {
|
||||
if (flags & NI_NUMERICSERV)
|
||||
servent = NULL;
|
||||
else if (flags & NI_DGRAM)
|
||||
servent = getservbyport(sa_in->sin_port, "udp");
|
||||
else
|
||||
servent = getservbyport(sa_in->sin_port, "tcp");
|
||||
|
||||
if (servent != NULL) {
|
||||
if (servlen <= strlen(servent->s_name)) {
|
||||
result = EAI_OVERFLOW;
|
||||
goto end;
|
||||
}
|
||||
strcpy(serv, servent->s_name);
|
||||
} else {
|
||||
if (servlen <= itoa_length(ntohs(sa_in->sin_port))) {
|
||||
result = EAI_OVERFLOW;
|
||||
goto end;
|
||||
}
|
||||
sprintf(serv, "%d", ntohs(sa_in->sin_port));
|
||||
}
|
||||
}
|
||||
|
||||
if (node != NULL && nodelen > 0) {
|
||||
if (flags & NI_NUMERICHOST)
|
||||
hostent = NULL;
|
||||
else {
|
||||
hostent = gethostbyaddr((char *)&sa_in->sin_addr,
|
||||
sizeof(struct in_addr), AF_INET);
|
||||
}
|
||||
if (hostent != NULL) {
|
||||
if (nodelen <= strlen(hostent->h_name)) {
|
||||
result = EAI_OVERFLOW;
|
||||
goto end;
|
||||
}
|
||||
strcpy(node, hostent->h_name);
|
||||
} else {
|
||||
if (flags & NI_NAMEREQD) {
|
||||
result = EAI_NONAME;
|
||||
goto end;
|
||||
}
|
||||
ntoa_address = inet_ntoa(sa_in->sin_addr);
|
||||
if (nodelen <= strlen(ntoa_address)) {
|
||||
result = EAI_OVERFLOW;
|
||||
goto end;
|
||||
}
|
||||
strcpy(node, ntoa_address);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end:
|
||||
h_errno = saved_h_errno;
|
||||
#ifdef ENABLE_PTHREAD
|
||||
pthread_mutex_unlock(&gai_mutex);
|
||||
#endif
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 02 Motoyuki Kasahara
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef GETADDRINFO_H
|
||||
#define GETADDRINFO_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include "atimed.h"
|
||||
|
||||
/********************************************************************/
|
||||
/*
|
||||
* Undefine all the macros.
|
||||
* <netdb.h> might defines some of them.
|
||||
*/
|
||||
#ifdef EAI_ADDRFAMILY
|
||||
#undef EAI_ADDRFAMILY
|
||||
#endif
|
||||
#ifdef EAI_AGAIN
|
||||
#undef EAI_AGAIN
|
||||
#endif
|
||||
#ifdef EAI_BADFLAGS
|
||||
#undef EAI_BADFLAGS
|
||||
#endif
|
||||
#ifdef EAI_FAIL
|
||||
#undef EAI_FAIL
|
||||
#endif
|
||||
#ifdef EAI_FAMILY
|
||||
#undef EAI_FAMILY
|
||||
#endif
|
||||
#ifdef EAI_MEMORY
|
||||
#undef EAI_MEMORY
|
||||
#endif
|
||||
#ifdef EAI_NONAME
|
||||
#undef EAI_NONAME
|
||||
#endif
|
||||
#ifdef EAI_OVERFLOW
|
||||
#undef EAI_OVERFLOW
|
||||
#endif
|
||||
#ifdef EAI_SERVICE
|
||||
#undef EAI_SERVICE
|
||||
#endif
|
||||
#ifdef EAI_SOCKTYPE
|
||||
#undef EAI_SOCKTYPE
|
||||
#endif
|
||||
#ifdef EAI_SYSTEM
|
||||
#undef EAI_SYSTEM
|
||||
#endif
|
||||
|
||||
#ifdef AI_PASSIVE
|
||||
#undef AI_PASSIVE
|
||||
#endif
|
||||
#ifdef AI_CANONNAME
|
||||
#undef AI_CANONNAME
|
||||
#endif
|
||||
#ifdef AI_NUMERICHOST
|
||||
#undef AI_NUMERICHOST
|
||||
#endif
|
||||
#ifdef AI_NUMERICSERV
|
||||
#undef AI_NUMERICSERV
|
||||
#endif
|
||||
#ifdef AI_V4MAPPED
|
||||
#undef AI_V4MAPPED
|
||||
#endif
|
||||
#ifdef AI_ALL
|
||||
#undef AI_ALL
|
||||
#endif
|
||||
#ifdef AI_ADDRCONFIG
|
||||
#undef AI_ADDRCONFIG
|
||||
#endif
|
||||
#ifdef AI_DEFAULT
|
||||
#undef AI_DEFAULT
|
||||
#endif
|
||||
|
||||
#ifdef NI_NOFQDN
|
||||
#undef NI_NOFQDN
|
||||
#endif
|
||||
#ifdef NI_NUMERICHOST
|
||||
#undef NI_NUMERICHOST
|
||||
#endif
|
||||
#ifdef NI_NAMEREQD
|
||||
#undef NI_NAMEREQD
|
||||
#endif
|
||||
#ifdef NI_NUMERICSERV
|
||||
#undef NI_NUMERICSERV
|
||||
#endif
|
||||
#ifdef NI_NUMERICSCOPE
|
||||
#undef NI_NUMERICSCOPE
|
||||
#endif
|
||||
|
||||
#ifdef NI_DGRAM
|
||||
#undef NI_DGRAM
|
||||
#endif
|
||||
#ifdef NI_MAXHOST
|
||||
#undef NI_MAXHOST
|
||||
#endif
|
||||
#ifdef NI_MAXSERV
|
||||
#undef NI_MAXSERV
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Fake struct and function names.
|
||||
* <netdb.h> might declares all or some of them.
|
||||
*/
|
||||
/*
|
||||
#if defined(HAVE_GETADDRINFO) || defined(HAVE_GETNAMEINFO)
|
||||
#define addrinfo my_addrinfo
|
||||
#define gai_strerror my_gai_strerror
|
||||
#define freeaddrinfo my_freeaddrinfo
|
||||
#define getaddrinfo my_getaddrinfo
|
||||
#define getnameinfo my_getnameinfo
|
||||
#endif
|
||||
*/
|
||||
|
||||
/********************************************************************/
|
||||
/*
|
||||
* Error codes.
|
||||
*/
|
||||
#define EAI_ADDRFAMILY 1
|
||||
#define EAI_AGAIN 2
|
||||
#define EAI_BADFLAGS 3
|
||||
#define EAI_FAIL 4
|
||||
#define EAI_FAMILY 5
|
||||
#define EAI_MEMORY 6
|
||||
#define EAI_NONAME 7
|
||||
#define EAI_OVERFLOW 8
|
||||
#define EAI_SERVICE 9
|
||||
#define EAI_SOCKTYPE 10
|
||||
#define EAI_SYSTEM 11
|
||||
|
||||
/*
|
||||
* Flags for getaddrinfo().
|
||||
*/
|
||||
#define AI_ADDRCONFIG 0x0001
|
||||
#define AI_ALL 0x0002
|
||||
#define AI_CANONNAME 0x0004
|
||||
#define AI_NUMERICHOST 0x0008
|
||||
#define AI_NUMERICSERV 0x0010
|
||||
#define AI_PASSIVE 0x0020
|
||||
#define AI_V4MAPPED 0x0040
|
||||
#define AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG)
|
||||
|
||||
/*
|
||||
* Flags for getnameinfo().
|
||||
*/
|
||||
#define NI_DGRAM 0x0001
|
||||
#define NI_NAMEREQD 0x0002
|
||||
#define NI_NOFQDN 0x0004
|
||||
#define NI_NUMERICHOST 0x0008
|
||||
#define NI_NUMERICSCOPE 0x0010
|
||||
#define NI_NUMERICSERV 0x0020
|
||||
|
||||
/*
|
||||
* Maximum length of FQDN and servie name for getnameinfo().
|
||||
*/
|
||||
#define NI_MAXHOST 1025
|
||||
#define NI_MAXSERV 32
|
||||
|
||||
/*
|
||||
* Address families and Protocol families.
|
||||
*/
|
||||
#ifndef AF_UNSPEC
|
||||
#define AF_UNSPEC AF_INET
|
||||
#endif
|
||||
#ifndef PF_UNSPEC
|
||||
#define PF_UNSPEC PF_INET
|
||||
#endif
|
||||
|
||||
#ifdef AOS3
|
||||
/*
|
||||
* struct addrinfo.
|
||||
*/
|
||||
struct addrinfo {
|
||||
int ai_flags;
|
||||
int ai_family;
|
||||
int ai_socktype;
|
||||
int ai_protocol;
|
||||
socklen_t ai_addrlen;
|
||||
char *ai_canonname;
|
||||
struct sockaddr *ai_addr;
|
||||
struct addrinfo *ai_next;
|
||||
};
|
||||
#endif
|
||||
|
||||
const char* gai_strerror(int);
|
||||
void freeaddrinfo(struct addrinfo *);
|
||||
int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **);
|
||||
int getnameinfo(const struct sockaddr *, socklen_t, char *, socklen_t, char *, socklen_t, int);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Carsten Larsen
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef AROS
|
||||
#include <proto/exec.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <proto/socket.h>
|
||||
#include <sys/socket.h>
|
||||
#include <bsdsocket/socketbasetags.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#ifdef Debug
|
||||
#undef Debug
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "atimed.h"
|
||||
|
||||
#ifdef AOS3
|
||||
static inline double
|
||||
round(double x)
|
||||
{
|
||||
return x > 0.0 ? floor(x + 0.5) : ceil(x - 0.5);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(AROS) || defined(AOS3)
|
||||
double nan(const char *tagp) {
|
||||
return 0./0.;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Library * SocketBase;
|
||||
extern int errno;
|
||||
|
||||
int OpenLibraries()
|
||||
{
|
||||
#ifdef AROS
|
||||
if(!(SocketBase = OpenLibrary((CONST_STRPTR)"bsdsocket.library", 4 ))) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (IPTR)&errno,
|
||||
SBTM_SETVAL(SBTC_HERRNOLONGPTR), (IPTR)&h_errno, TAG_DONE)) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CloseLibraries()
|
||||
{
|
||||
#ifdef AROS
|
||||
CloseLibrary(SocketBase);
|
||||
#endif
|
||||
printf("\x1B[0m");
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: APL License
|
||||
*
|
||||
* Copyright (c) 2009 Diego Casorran <dcasorran@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "apoll.h"
|
||||
|
||||
int poll(struct pollfd *pfds, nfds_t nfds, int timeout)
|
||||
{
|
||||
unsigned int i;
|
||||
int maxfd = -1, ret;
|
||||
fd_set rset,wset,xset;
|
||||
struct timeval timeout_tv, *tvp = NULL;
|
||||
|
||||
if (timeout >= 0)
|
||||
{
|
||||
timeout_tv.tv_sec = (timeout / 1000);
|
||||
timeout_tv.tv_usec = (timeout % 1000) * 1000;
|
||||
tvp = &timeout_tv;
|
||||
}
|
||||
|
||||
if(pfds==NULL||nfds<1)
|
||||
{
|
||||
if(pfds==NULL&&nfds<1&&timeout>=0)
|
||||
{
|
||||
ret = select(0,NULL,NULL,NULL,tvp);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
errno=EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO (&rset);
|
||||
FD_ZERO (&wset);
|
||||
FD_ZERO (&xset);
|
||||
|
||||
for (i = 0; i < nfds; i++)
|
||||
{
|
||||
pfds[i].revents = 0;
|
||||
|
||||
if (pfds[i].events == 0)
|
||||
continue;
|
||||
|
||||
if (pfds[i].fd > maxfd)
|
||||
maxfd = pfds[i].fd;
|
||||
|
||||
if (pfds[i].events & POLLIN)
|
||||
FD_SET (pfds[i].fd, &rset);
|
||||
|
||||
if (pfds[i].events & POLLOUT)
|
||||
FD_SET (pfds[i].fd, &wset);
|
||||
|
||||
if (pfds[i].events & POLLERR)
|
||||
FD_SET (pfds[i].fd, &xset);
|
||||
}
|
||||
|
||||
ret = select (maxfd + 1, &rset, &wset, &xset, tvp);
|
||||
|
||||
if(ret == -1)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < nfds; i++)
|
||||
{
|
||||
if (pfds[i].events == 0)
|
||||
continue;
|
||||
|
||||
if (FD_ISSET (pfds[i].fd, &rset))
|
||||
pfds[i].revents |= POLLIN;
|
||||
|
||||
if (FD_ISSET (pfds[i].fd, &wset))
|
||||
pfds[i].revents |= POLLOUT;
|
||||
|
||||
if (FD_ISSET (pfds[i].fd, &xset))
|
||||
pfds[i].revents |= POLLERR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*-
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Charles M. Hannum.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef APOLL_H
|
||||
#define APOLL_H
|
||||
|
||||
struct pollfd {
|
||||
int fd; // file descriptor
|
||||
short events; // events to look for
|
||||
short revents; // events returned
|
||||
};
|
||||
|
||||
typedef unsigned int nfds_t;
|
||||
|
||||
int poll(struct pollfd *, nfds_t, int);
|
||||
|
||||
#define INFTIM -1
|
||||
#define POLLIN 0x0001
|
||||
#define POLLPRI 0x0002
|
||||
#define POLLERR 0x0008
|
||||
#define POLLOUT 0x0004
|
||||
#define POLLHUP 0x0010
|
||||
#define POLLNVAL 0x0020
|
||||
#define POLLRDNORM 0x0040
|
||||
#define POLLRDBAND 0x0080
|
||||
#define POLLWRBAND 0x0100
|
||||
|
||||
#endif
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Carsten Larsen
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ATIMED_H
|
||||
#define ATIMED_H
|
||||
|
||||
int OpenLibraries();
|
||||
void CloseLibraries();
|
||||
|
||||
#if defined(AROS) || defined(AOS3)
|
||||
#ifndef AMIGA
|
||||
#define AMIGA
|
||||
#endif
|
||||
double nan(const char*);
|
||||
#endif
|
||||
|
||||
#ifndef AF_INET6
|
||||
#define AF_INET6 10
|
||||
#endif
|
||||
|
||||
#ifndef va_copy
|
||||
#define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list))
|
||||
#endif
|
||||
|
||||
#ifdef AOS3
|
||||
#include <machine/limits.h>
|
||||
#include <machine/types.h>
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef uint32_t uintptr_t;
|
||||
#endif
|
||||
|
||||
#ifdef AROS
|
||||
#include <stdint.h>
|
||||
typedef uint32_t register_t;
|
||||
#endif
|
||||
|
||||
#ifndef _ALIGNBYTES
|
||||
#define _ALIGNBYTES (sizeof(register_t) - 1)
|
||||
#define ALIGN(p) (((uintptr_t)(p) + _ALIGNBYTES) & ~_ALIGNBYTES)
|
||||
#endif
|
||||
|
||||
typedef unsigned int sa_family_t;
|
||||
typedef unsigned int socklen_t;
|
||||
typedef uint16_t in_port_t;
|
||||
|
||||
|
||||
// General socket address holding structure, big enough to hold either
|
||||
// struct sockaddr_in or struct sockaddr_in6 data:
|
||||
struct sockaddr_storage {
|
||||
sa_family_t ss_family; // address family
|
||||
|
||||
// all this is padding, implementation specific, ignore it:
|
||||
char __ss_pad1[128 - sizeof(sa_family_t)];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -48,7 +48,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "ntimed.h"
|
||||
|
||||
#include "atimed.h"
|
||||
|
||||
struct cd_stat {
|
||||
double x;
|
||||
|
|
|
@ -40,6 +40,7 @@ set -e
|
|||
# NB: These SHALL always be included with #include "..."
|
||||
|
||||
HDRS='
|
||||
atimed.h
|
||||
ntimed.h
|
||||
ntimed_endian.h
|
||||
ntimed_queue.h
|
||||
|
@ -49,7 +50,8 @@ HDRS='
|
|||
param_instance.h
|
||||
param_tbl.h
|
||||
udp.h
|
||||
'
|
||||
agetaddrinfo.h
|
||||
apoll.h'
|
||||
|
||||
# List of .c files
|
||||
|
||||
|
@ -68,11 +70,14 @@ SRCS='
|
|||
param.c
|
||||
pll_std.c
|
||||
suckaddr.c
|
||||
time_amiga.c
|
||||
time_sim.c
|
||||
time_stuff.c
|
||||
time_unix.c
|
||||
todo.c
|
||||
udp.c
|
||||
alib.c
|
||||
agetaddrinfo.c
|
||||
apoll.c
|
||||
'
|
||||
|
||||
if make -v 2>&1 | grep GNU > /dev/null 2>&1 ; then
|
||||
|
@ -108,7 +113,9 @@ else
|
|||
echo ''
|
||||
echo 'all: ntimed-client'
|
||||
echo ''
|
||||
echo "CFLAGS += -Wall -Werror"
|
||||
echo 'CC = gcc'
|
||||
echo "CFLAGS += -DAROS -Wall -Werror"
|
||||
# echo "CFLAGS += -DAROS"
|
||||
echo ''
|
||||
|
||||
for f in ${HDRS}
|
||||
|
|
44
main.c
44
main.c
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "atimed.h"
|
||||
#include "ntimed.h"
|
||||
#include "ntp.h"
|
||||
|
||||
|
@ -38,37 +39,46 @@
|
|||
static void
|
||||
dummy(void)
|
||||
{
|
||||
// Reference otherwise unused "library" functions
|
||||
// Reference otherwise unused "library" functions
|
||||
|
||||
NTP_Peer_Destroy(NULL);
|
||||
NTP_Peer_Destroy(NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
main_run_tests(int argc, char * const * argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
Time_Amiga_Passive();
|
||||
|
||||
Time_Unix_Passive();
|
||||
TS_RunTest(NULL);
|
||||
|
||||
TS_RunTest(NULL);
|
||||
|
||||
return (0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char * const *argv)
|
||||
{
|
||||
if (getpid() == 0)
|
||||
dummy();
|
||||
if(OpenLibraries() != 0)
|
||||
return -1;
|
||||
|
||||
if (argc > 1 && !strcmp(argv[1], "--poll-server"))
|
||||
return (main_poll_server(argc - 1, argv + 1));
|
||||
if (argc > 1 && !strcmp(argv[1], "--sim-client"))
|
||||
return (main_sim_client(argc - 1, argv + 1));
|
||||
if (argc > 1 && !strcmp(argv[1], "--run-tests"))
|
||||
return (main_run_tests(argc - 1, argv + 1));
|
||||
if (getpid() == 0)
|
||||
dummy();
|
||||
|
||||
return (main_client(argc, argv));
|
||||
int r;
|
||||
|
||||
if (argc > 1 && !strcmp(argv[1], "--poll-server")) {
|
||||
r = (main_poll_server(argc - 1, argv + 1));
|
||||
} else if (argc > 1 && !strcmp(argv[1], "--sim-client")) {
|
||||
r = (main_sim_client(argc - 1, argv + 1));
|
||||
} else if (argc > 1 && !strcmp(argv[1], "--run-tests")) {
|
||||
r = (main_run_tests(argc - 1, argv + 1));
|
||||
} else {
|
||||
r = main_client(argc, argv);
|
||||
}
|
||||
|
||||
CloseLibraries();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "atimed.h"
|
||||
#include "ntimed.h"
|
||||
#include "ntp.h"
|
||||
#include "udp.h"
|
||||
|
@ -47,7 +48,7 @@
|
|||
|
||||
static volatile sig_atomic_t restart = 1;
|
||||
|
||||
static void __match_proto__()
|
||||
static void
|
||||
sig_hup(int siginfo)
|
||||
{
|
||||
(void)signal(SIGHUP, sig_hup);
|
||||
|
@ -66,11 +67,11 @@ main_client(int argc, char *const *argv)
|
|||
struct udp_socket *usc;
|
||||
int npeer = 0;
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
setbuf(stderr, NULL);
|
||||
//setbuf(stdout, NULL);
|
||||
//setbuf(stderr, NULL);
|
||||
|
||||
tdl = TODO_NewList();
|
||||
Time_Unix(tdl);
|
||||
Time_Amiga(tdl);
|
||||
|
||||
PLL_Init();
|
||||
|
||||
|
|
|
@ -33,9 +33,9 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "atimed.h"
|
||||
#include "ntimed.h"
|
||||
#include "ntp.h"
|
||||
#include "udp.h"
|
||||
|
@ -94,13 +94,13 @@ main_poll_server(int argc, char *const *argv)
|
|||
struct todolist *tdl;
|
||||
double duration = 1800;
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
setbuf(stderr, NULL);
|
||||
//setbuf(stdout, NULL);
|
||||
//setbuf(stderr, NULL);
|
||||
|
||||
ArgTracefile("-");
|
||||
|
||||
tdl = TODO_NewList();
|
||||
Time_Unix_Passive();
|
||||
Time_Amiga_Passive();
|
||||
|
||||
npl = NTP_PeerSet_New(NULL);
|
||||
AN(npl);
|
||||
|
|
14
ntimed.h
14
ntimed.h
|
@ -32,7 +32,8 @@
|
|||
#endif
|
||||
#define NTIMED_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
#include "atimed.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include "ntimed_queue.h"
|
||||
#include "ntimed_tricks.h"
|
||||
|
@ -101,8 +102,15 @@ void Time_Sim_Bump(struct todolist *, double when, double freq, double phase);
|
|||
|
||||
/* time_unix.c -- UNIX timebase ***************************************/
|
||||
|
||||
void Time_Unix(struct todolist *);
|
||||
void Time_Unix_Passive(void);
|
||||
//void Time_Unix(struct todolist *);
|
||||
//void Time_Unix_Passive(void);
|
||||
|
||||
/* time_amiga.c -- Amiga timebase *************************************/
|
||||
|
||||
void Time_Amiga(struct todolist *);
|
||||
void Time_Amiga_Passive(void);
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/* time_stuff.c -- Timebase infrastructure ****************************/
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include "udp.h"
|
||||
#include "ntp.h"
|
||||
|
||||
#include "agetaddrinfo.h"
|
||||
|
||||
struct ntp_peer *
|
||||
NTP_Peer_New(const char *hostname, const void *sa, unsigned salen)
|
||||
{
|
||||
|
@ -78,9 +80,9 @@ NTP_Peer_NewLookup(struct ocx *ocx, const char *hostname)
|
|||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
error = getaddrinfo(hostname, "ntp", &hints, &res0);
|
||||
error = getaddrinfo(hostname, "123", &hints, &res0);
|
||||
if (error)
|
||||
Fail(ocx, 0, "hostname '%s', port 'ntp': %s\n",
|
||||
Fail(ocx, 0, "hostname '%s', port '123': %s\n",
|
||||
hostname, gai_strerror(error));
|
||||
|
||||
np = NTP_Peer_New(hostname, res0->ai_addr, res0->ai_addrlen);
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
|
||||
#include "ntimed.h"
|
||||
#include "ntp.h"
|
||||
#include "agetaddrinfo.h"
|
||||
|
||||
struct ntp_group {
|
||||
unsigned magic;
|
||||
|
@ -126,9 +127,9 @@ ntp_peerset_fillgroup(struct ocx *ocx, struct ntp_peerset *nps,
|
|||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
error = getaddrinfo(lookup, "ntp", &hints, &res0);
|
||||
error = getaddrinfo(lookup, "123", &hints, &res0);
|
||||
if (error)
|
||||
Fail(ocx, 1, "hostname '%s', port 'ntp': %s\n",
|
||||
Fail(ocx, 1, "hostname '%s', port '123': %s\n",
|
||||
lookup, gai_strerror(error));
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
if (res->ai_family != AF_INET && res->ai_family != AF_INET6)
|
||||
|
|
115
ocx_stdio.c
115
ocx_stdio.c
|
@ -72,29 +72,31 @@ static FILE *tracefile;
|
|||
static FILE *
|
||||
getdst(enum ocx_chan chan)
|
||||
{
|
||||
if (chan == OCX_DIAG)
|
||||
return (stderr);
|
||||
if (chan == OCX_TRACE)
|
||||
return (tracefile);
|
||||
if (chan == OCX_DEBUG)
|
||||
return (stdout);
|
||||
WRONG("Wrong ocx_chan");
|
||||
NEEDLESS_RETURN(NULL);
|
||||
if (chan == OCX_DIAG)
|
||||
return (stderr);
|
||||
if (chan == OCX_TRACE)
|
||||
return (tracefile);
|
||||
if (chan == OCX_DEBUG)
|
||||
return (stdout);
|
||||
WRONG("Wrong ocx_chan");
|
||||
NEEDLESS_RETURN(NULL);
|
||||
}
|
||||
|
||||
static void __match_proto__()
|
||||
static void
|
||||
putv(struct ocx *ocx, enum ocx_chan chan, const char *fmt, va_list ap)
|
||||
{
|
||||
FILE *dst = getdst(chan);
|
||||
va_list ap2;
|
||||
FILE *dst = getdst(chan);
|
||||
va_list ap2;
|
||||
|
||||
va_copy(ap2, ap);
|
||||
AZ(ocx);
|
||||
if (dst != NULL)
|
||||
(void)vfprintf(dst, fmt, ap);
|
||||
if (chan == OCX_DIAG)
|
||||
vsyslog(LOG_ERR, fmt, ap2);
|
||||
va_end(ap2);
|
||||
va_copy(ap2, ap);
|
||||
AZ(ocx);
|
||||
if (dst != NULL) {
|
||||
(void)vfprintf(dst, fmt, ap);
|
||||
fflush(dst);
|
||||
}
|
||||
// if (chan == OCX_DIAG)
|
||||
// vsyslog(LOG_ERR, fmt, ap2);
|
||||
va_end(ap2);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
@ -105,23 +107,23 @@ void
|
|||
ArgTracefile(const char *fn)
|
||||
{
|
||||
|
||||
if (tracefile != NULL && tracefile != stdout) {
|
||||
AZ(fclose(tracefile));
|
||||
tracefile = NULL;
|
||||
}
|
||||
if (tracefile != NULL && tracefile != stdout) {
|
||||
AZ(fclose(tracefile));
|
||||
tracefile = NULL;
|
||||
}
|
||||
|
||||
if (fn == NULL)
|
||||
return;
|
||||
if (fn == NULL)
|
||||
return;
|
||||
|
||||
if (!strcmp(fn, "-")) {
|
||||
tracefile = stdout;
|
||||
return;
|
||||
}
|
||||
if (!strcmp(fn, "-")) {
|
||||
tracefile = stdout;
|
||||
return;
|
||||
}
|
||||
|
||||
tracefile = fopen(fn, "w");
|
||||
if (tracefile == NULL)
|
||||
Fail(NULL, 1, "Could not open '%s' for writing", fn);
|
||||
setbuf(tracefile, NULL);
|
||||
tracefile = fopen(fn, "w");
|
||||
if (tracefile == NULL)
|
||||
Fail(NULL, 1, "Could not open '%s' for writing", fn);
|
||||
setbuf(tracefile, NULL);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
@ -132,42 +134,43 @@ ArgTracefile(const char *fn)
|
|||
void
|
||||
Put(struct ocx *ocx, enum ocx_chan chan, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_list ap;
|
||||
|
||||
AZ(ocx);
|
||||
va_start(ap, fmt);
|
||||
putv(ocx, chan, fmt, ap);
|
||||
va_end(ap);
|
||||
AZ(ocx);
|
||||
va_start(ap, fmt);
|
||||
putv(ocx, chan, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
PutHex(struct ocx *ocx, enum ocx_chan chan, const void *ptr, ssize_t len)
|
||||
{
|
||||
const uint8_t *p = ptr;
|
||||
const char *s = "";
|
||||
const uint8_t *p = ptr;
|
||||
const char *s = "";
|
||||
|
||||
AN(ptr);
|
||||
assert(len >= 0);
|
||||
AN(ptr);
|
||||
assert(len >= 0);
|
||||
|
||||
while(len--) {
|
||||
Put(ocx, chan, "%s%02x", s, *p++);
|
||||
s = " ";
|
||||
}
|
||||
while(len--) {
|
||||
// Put(ocx, chan, "%s%02x", s, *p++);
|
||||
Put(ocx, chan, "%s%x", s, *p++);
|
||||
s = " ";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Fail(struct ocx *ocx, int err, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_list ap;
|
||||
|
||||
if (err)
|
||||
err = errno;
|
||||
Put(ocx, OCX_DIAG, "Failure: ");
|
||||
va_start(ap, fmt);
|
||||
putv(ocx, OCX_DIAG, fmt, ap);
|
||||
va_end(ap);
|
||||
Put(ocx, OCX_DIAG, "\n");
|
||||
if (err)
|
||||
Put(ocx, OCX_DIAG, "errno = %d (%s)\n", err, strerror(err));
|
||||
exit(1);
|
||||
if (err)
|
||||
err = errno;
|
||||
Put(ocx, OCX_DIAG, "Failure: ");
|
||||
va_start(ap, fmt);
|
||||
putv(ocx, OCX_DIAG, fmt, ap);
|
||||
va_end(ap);
|
||||
Put(ocx, OCX_DIAG, "\n");
|
||||
if (err)
|
||||
Put(ocx, OCX_DIAG, "errno = %d (%s)\n", err, strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ SA_Equal(const void *sa1, size_t sl1, const void *sa2, size_t sl2)
|
|||
{
|
||||
const struct sockaddr *s1, *s2;
|
||||
const struct sockaddr_in *s41, *s42;
|
||||
const struct sockaddr_in6 *s61, *s62;
|
||||
// const struct sockaddr_in6 *s61, *s62;
|
||||
|
||||
AN(sa1);
|
||||
AN(sa2);
|
||||
|
@ -66,7 +66,7 @@ SA_Equal(const void *sa1, size_t sl1, const void *sa2, size_t sl2)
|
|||
return (1);
|
||||
}
|
||||
|
||||
if (s1->sa_family == AF_INET6) {
|
||||
/* if (s1->sa_family == AF_INET6) {
|
||||
assert(sl1 >= sizeof(struct sockaddr_in6));
|
||||
assert(sl2 >= sizeof(struct sockaddr_in6));
|
||||
s61 = sa1;
|
||||
|
@ -79,6 +79,6 @@ SA_Equal(const void *sa1, size_t sl1, const void *sa2, size_t sl2)
|
|||
sizeof s61->sin6_addr))
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
}*/
|
||||
return (0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Carsten Larsen
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <exec/types.h>
|
||||
#include <exec/io.h>
|
||||
#include <exec/memory.h>
|
||||
#include <proto/exec.h>
|
||||
#include <clib/alib_protos.h>
|
||||
#include <proto/dos.h>
|
||||
|
||||
#include <devices/timer.h>
|
||||
|
||||
#ifdef Debug
|
||||
#undef Debug
|
||||
#endif
|
||||
|
||||
#include "atimed.h"
|
||||
#include "ntimed.h"
|
||||
|
||||
int amiga_get_time(struct timeval *tv);
|
||||
int amiga_set_time(struct timeval *tv);
|
||||
struct timerequest* create_timer();
|
||||
void delete_timer(struct timerequest*);
|
||||
void adjust_timeval(struct timeval *tv, double offset);
|
||||
|
||||
// Ntimed internals
|
||||
static double adj_offset = 0;
|
||||
static double adj_duration = 0;
|
||||
static double adj_freq = 0;
|
||||
|
||||
static uintptr_t ticker;
|
||||
static struct todolist *kt_tdl;
|
||||
|
||||
#ifndef AMIGA
|
||||
struct timeval {
|
||||
ULONG tv_secs;
|
||||
ULONG tv_micro;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static void
|
||||
amiga_setfreq(struct ocx *ocx, double frequency)
|
||||
{
|
||||
assert(isfinite(frequency));
|
||||
|
||||
// frequency offset (scaled ppm)
|
||||
long int freq = (long)floor(frequency * (65536 * 1e6));
|
||||
Put(ocx, OCX_TRACE, "KERNPLL %.6e\n", frequency);
|
||||
}
|
||||
|
||||
static enum todo_e __match_proto__(todo_f)
|
||||
amiga_ticker(struct ocx *ocx, struct todolist *tdl, void *priv)
|
||||
{
|
||||
(void)ocx;
|
||||
AN(tdl);
|
||||
AZ(priv);
|
||||
amiga_setfreq(ocx, adj_freq);
|
||||
ticker = 0;
|
||||
return (TODO_OK);
|
||||
}
|
||||
|
||||
static void __match_proto__(tb_adjust_f)
|
||||
amiga_adjust(struct ocx *ocx, double offset, double duration, double frequency)
|
||||
{
|
||||
double freq;
|
||||
|
||||
(void)ocx;
|
||||
assert(duration >= 0.0);
|
||||
|
||||
if (ticker)
|
||||
TODO_Cancel(kt_tdl, &ticker);
|
||||
|
||||
adj_offset = offset;
|
||||
adj_duration = floor(duration);
|
||||
if (adj_offset > 0.0 && adj_duration == 0.0)
|
||||
adj_duration = 1.0;
|
||||
adj_freq = frequency;
|
||||
|
||||
freq = adj_freq;
|
||||
if (adj_duration > 0.0)
|
||||
freq += adj_offset / adj_duration;
|
||||
amiga_setfreq(ocx, freq);
|
||||
if (adj_duration > 0.0)
|
||||
ticker = TODO_ScheduleRel(kt_tdl, amiga_ticker, NULL,
|
||||
adj_duration, 0.0, "KT_TICK");
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static void __match_proto__(tb_step_f)
|
||||
amiga_step(struct ocx *ocx, double offset)
|
||||
{
|
||||
double d;
|
||||
struct timeval tv;
|
||||
|
||||
Put(ocx, OCX_TRACE, "KERNTIME_STEP %.3e\n", offset);
|
||||
|
||||
AZ(amiga_get_time(&tv));
|
||||
adjust_timeval(&tv, offset);
|
||||
AZ(amiga_set_time(&tv));
|
||||
TB_generation++;
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct timestamp * __match_proto__(tb_now_f)
|
||||
amiga_now(struct timestamp *storage)
|
||||
{
|
||||
struct timeval tv;
|
||||
AZ(amiga_get_time(&tv));
|
||||
return (TS_Nanosec(storage, tv.tv_secs, tv.tv_micro * 1000LL));
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static int __match_proto__(tb_sleep_f)
|
||||
amiga_sleep(double dur)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
adjust_timeval(&tv, dur);
|
||||
|
||||
struct timerequest *request = create_timer();
|
||||
if (request == NULL)
|
||||
return 1;
|
||||
|
||||
request->tr_node.io_Command = TR_ADDREQUEST;
|
||||
request->tr_time = tv;
|
||||
|
||||
DoIO((struct IORequest*)request);
|
||||
|
||||
delete_timer(request);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void Time_Amiga(struct todolist *tdl)
|
||||
{
|
||||
AN(tdl);
|
||||
TB_Step = amiga_step;
|
||||
TB_Adjust = amiga_adjust;
|
||||
TB_Sleep = amiga_sleep;
|
||||
TB_Now = amiga_now;
|
||||
kt_tdl = tdl;
|
||||
}
|
||||
|
||||
void Time_Amiga_Passive(void)
|
||||
{
|
||||
TB_Sleep = amiga_sleep;
|
||||
TB_Now = amiga_now;
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
struct timerequest* create_timer()
|
||||
{
|
||||
struct MsgPort *port = CreatePort(0, 0);
|
||||
if (port == NULL)
|
||||
return NULL;
|
||||
|
||||
struct timerequest *request = (struct timerequest*)CreateExtIO(port, sizeof(struct timerequest));
|
||||
if (request == NULL)
|
||||
{
|
||||
DeletePort(port);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LONG error = OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest*)request, 0L);
|
||||
if (error != 0)
|
||||
{
|
||||
delete_timer(request);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
void delete_timer(struct timerequest *request)
|
||||
{
|
||||
if (request == NULL)
|
||||
return;
|
||||
|
||||
struct MsgPort *port = request->tr_node.io_Message.mn_ReplyPort;
|
||||
|
||||
if (port != 0)
|
||||
DeletePort(port);
|
||||
|
||||
CloseDevice((struct IORequest*)request);
|
||||
DeleteExtIO((struct IORequest*)request);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
// 2922 is the number of days between 1.1.1970 and 1.1.1978 (2 leap years and 6 normal)
|
||||
const long amigaoffset = 2922 * 24 * 60 * 60; // 252460800
|
||||
const long cetoffset = 60 * 60;
|
||||
|
||||
int amiga_get_time(struct timeval *tv)
|
||||
{
|
||||
struct timerequest *request = create_timer();
|
||||
if (request == NULL)
|
||||
return 1;
|
||||
|
||||
request->tr_node.io_Command = TR_GETSYSTIME;
|
||||
DoIO((struct IORequest*)request);
|
||||
|
||||
*tv = request->tr_time;
|
||||
tv->tv_secs = tv->tv_secs + (amigaoffset - cetoffset);
|
||||
|
||||
delete_timer(request);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amiga_set_time(struct timeval *tv)
|
||||
{
|
||||
struct timerequest *request = create_timer();
|
||||
if (request == NULL)
|
||||
return 1;
|
||||
|
||||
request->tr_node.io_Command = TR_SETSYSTIME;
|
||||
request->tr_time = *tv;
|
||||
request->tr_time.tv_secs -= (amigaoffset - cetoffset);
|
||||
|
||||
DoIO((struct IORequest*)request);
|
||||
|
||||
delete_timer(request);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void adjust_timeval(struct timeval *tv, double offset)
|
||||
{
|
||||
double d = floor(offset);
|
||||
offset -= d;
|
||||
|
||||
long sec = tv->tv_secs + (long)d;
|
||||
long micro = tv->tv_micro + (long)floor(offset * 1e6);
|
||||
|
||||
if (micro < 0) {
|
||||
sec -= 1;
|
||||
micro += 1000000;
|
||||
} else if (micro >= 1000000) {
|
||||
sec += 1;
|
||||
micro -= 1000000;
|
||||
}
|
||||
|
||||
tv->tv_secs = sec;
|
||||
tv->tv_micro = micro;
|
||||
}
|
|
@ -36,6 +36,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "ntimed.h"
|
||||
#include "atimed.h"
|
||||
|
||||
#define NANO_FRAC 18446744074ULL // 2^64 / 1e9
|
||||
|
||||
|
@ -103,7 +104,8 @@ TS_Add(struct timestamp *ts, double dt)
|
|||
CHECK_OBJ_NOTNULL(ts, TIMESTAMP_MAGIC);
|
||||
dt += ldexp(ts->frac, -64);
|
||||
di = floor(dt);
|
||||
ts->sec += (uint64_t)di;
|
||||
// ts->sec += (uint64_t)di;
|
||||
ts->sec = (uint64_t)((double)ts->sec + di);
|
||||
ts->frac = (uint64_t)ldexp(dt - di, 64);
|
||||
}
|
||||
|
||||
|
@ -142,7 +144,7 @@ TS_SleepUntil(const struct timestamp *t)
|
|||
void
|
||||
TS_Format(char *buf, size_t len, const struct timestamp *ts)
|
||||
{
|
||||
CHECK_OBJ_NOTNULL(ts, TIMESTAMP_MAGIC);
|
||||
// CHECK_OBJ_NOTNULL(ts, TIMESTAMP_MAGIC);
|
||||
uint64_t x, y;
|
||||
int i;
|
||||
|
||||
|
@ -153,7 +155,8 @@ TS_Format(char *buf, size_t len, const struct timestamp *ts)
|
|||
y -= 1000000000ULL;
|
||||
x += 1;
|
||||
}
|
||||
i = snprintf(buf, len, "%jd.%09jd", (intmax_t)x, (intmax_t)y);
|
||||
// i = snprintf(buf, len, "%jd.%09jd", (intmax_t)x, (intmax_t)y);
|
||||
i = snprintf(buf, len, "%lld.%09lld", x, y);
|
||||
assert(i < (int)len);
|
||||
}
|
||||
|
||||
|
|
262
time_unix.c
262
time_unix.c
|
@ -1,262 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2014 Poul-Henning Kamp
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* UNIX timebase
|
||||
* =============
|
||||
*
|
||||
* Implement the timebase functions on top of a modern UNIX kernel which
|
||||
* has the some version of the Mills/Kamp kernel PLL code and either
|
||||
* [gs]ettimeofday(2) or better: clock_[gs]ettime(2) API.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <sys/timex.h>
|
||||
|
||||
#include "ntimed.h"
|
||||
|
||||
static double adj_offset = 0;
|
||||
static double adj_duration = 0;
|
||||
static double adj_freq = 0;
|
||||
|
||||
static uintptr_t ticker;
|
||||
static struct todolist *kt_tdl;
|
||||
|
||||
// #undef CLOCK_REALTIME /* Test old unix code */
|
||||
|
||||
/**********************************************************************
|
||||
* The NTP-pll in UNIX kernels apply the offset correction in an
|
||||
* exponential-decay fashion for historical and wrong reasons.
|
||||
*
|
||||
* The short explanation is that this ends up confusing all PLLs I have
|
||||
* ever seen, by introducing mainly odd harmonics of the PLL update period
|
||||
* into all time-measurements in the system.
|
||||
*
|
||||
* A much more sane mode would be to tell the kernel "I want this much
|
||||
* offset accumulated over this many seconds", giving a constant frequency
|
||||
* over the PLL update period while still falling back to the frequency
|
||||
* estimate should the time-steering userland process fail.
|
||||
*
|
||||
* I will add such a mode to the FreeBSD kernel as a reference implementation
|
||||
* at a later date, in the mean time this code implements it by updating the
|
||||
* kernel frequency from userland as needed.
|
||||
*
|
||||
* XXX: Optimise to only wake up when truly needed, rather than every second.
|
||||
* XXX: Requires TODO cancellation.
|
||||
*/
|
||||
|
||||
static void
|
||||
kt_setfreq(struct ocx *ocx, double frequency)
|
||||
{
|
||||
struct timex tx;
|
||||
int i;
|
||||
|
||||
assert(isfinite(frequency));
|
||||
|
||||
memset(&tx, 0, sizeof tx);
|
||||
tx.modes = MOD_STATUS;
|
||||
#if defined(MOD_NANO)
|
||||
tx.modes |= MOD_NANO;
|
||||
#elif defined(MOD_MICRO)
|
||||
tx.modes |= MOD_MICRO;
|
||||
#endif
|
||||
|
||||
tx.status = STA_PLL | STA_FREQHOLD;
|
||||
tx.modes = MOD_FREQUENCY;
|
||||
tx.freq = (long)floor(frequency * (65536 * 1e6));
|
||||
errno = 0;
|
||||
i = ntp_adjtime(&tx);
|
||||
Put(ocx, OCX_TRACE, "KERNPLL %.6e %d\n", frequency, i);
|
||||
/* XXX: what is the correct error test here ? */
|
||||
assert(i >= 0);
|
||||
}
|
||||
|
||||
static enum todo_e __match_proto__(todo_f)
|
||||
kt_ticker(struct ocx *ocx, struct todolist *tdl, void *priv)
|
||||
{
|
||||
|
||||
(void)ocx;
|
||||
AN(tdl);
|
||||
AZ(priv);
|
||||
kt_setfreq(ocx, adj_freq);
|
||||
ticker = 0;
|
||||
return (TODO_OK);
|
||||
}
|
||||
|
||||
static void __match_proto__(tb_adjust_f)
|
||||
kt_adjust(struct ocx *ocx, double offset, double duration, double frequency)
|
||||
{
|
||||
double freq;
|
||||
|
||||
(void)ocx;
|
||||
assert(duration >= 0.0);
|
||||
|
||||
if (ticker)
|
||||
TODO_Cancel(kt_tdl, &ticker);
|
||||
|
||||
adj_offset = offset;
|
||||
adj_duration = floor(duration);
|
||||
if (adj_offset > 0.0 && adj_duration == 0.0)
|
||||
adj_duration = 1.0;
|
||||
adj_freq = frequency;
|
||||
|
||||
freq = adj_freq;
|
||||
if (adj_duration > 0.0)
|
||||
freq += adj_offset / adj_duration;
|
||||
kt_setfreq(ocx, freq);
|
||||
if (adj_duration > 0.0)
|
||||
ticker = TODO_ScheduleRel(kt_tdl, kt_ticker, NULL,
|
||||
adj_duration, 0.0, "KT_TICK");
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
#ifdef CLOCK_REALTIME
|
||||
|
||||
static void __match_proto__(tb_step_f)
|
||||
kt_step(struct ocx *ocx, double offset)
|
||||
{
|
||||
double d;
|
||||
struct timespec ts;
|
||||
|
||||
Put(ocx, OCX_TRACE, "KERNTIME_STEP %.3e\n", offset);
|
||||
d = floor(offset);
|
||||
offset -= d;
|
||||
|
||||
AZ(clock_gettime(CLOCK_REALTIME, &ts));
|
||||
ts.tv_sec += (long)d;
|
||||
ts.tv_nsec += (long)floor(offset * 1e9);
|
||||
if (ts.tv_nsec < 0) {
|
||||
ts.tv_sec -= 1;
|
||||
ts.tv_nsec += 1000000000;
|
||||
} else if (ts.tv_nsec >= 1000000000) {
|
||||
ts.tv_sec += 1;
|
||||
ts.tv_nsec -= 1000000000;
|
||||
}
|
||||
AZ(clock_settime(CLOCK_REALTIME, &ts));
|
||||
TB_generation++;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void __match_proto__(tb_step_f)
|
||||
kt_step(struct ocx *ocx, double offset)
|
||||
{
|
||||
double d;
|
||||
struct timeval tv;
|
||||
|
||||
Put(ocx, OCX_TRACE, "KERNTIME_STEP %.3e\n", offset);
|
||||
d = floor(offset);
|
||||
offset -= d;
|
||||
|
||||
AZ(gettimeofday(&tv, NULL));
|
||||
tv.tv_sec += (long)d;
|
||||
tv.tv_usec += (long)floor(offset * 1e6);
|
||||
if (tv.tv_usec < 0) {
|
||||
tv.tv_sec -= 1;
|
||||
tv.tv_usec += 1000000;
|
||||
} else if (tv.tv_usec >= 1000000) {
|
||||
tv.tv_sec += 1;
|
||||
tv.tv_usec -= 1000000;
|
||||
}
|
||||
AZ(settimeofday(&tv, NULL));
|
||||
TB_generation++;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
#if defined (CLOCK_REALTIME)
|
||||
|
||||
static struct timestamp * __match_proto__(tb_now_f)
|
||||
kt_now(struct timestamp *storage)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
AZ(clock_gettime(CLOCK_REALTIME, &ts));
|
||||
return (TS_Nanosec(storage, ts.tv_sec, ts.tv_nsec));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static struct timestamp * __match_proto__(tb_now_f)
|
||||
kt_now(struct timestamp *storage)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
AZ(gettimeofday(&tv, NULL));
|
||||
return (TS_Nanosec(storage, tv.tv_sec, tv.tv_usec * 1000LL));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static int __match_proto__(tb_sleep_f)
|
||||
kt_sleep(double dur)
|
||||
{
|
||||
struct pollfd fds[1];
|
||||
int i;
|
||||
|
||||
i = poll(fds, 0, (int)floor(dur * 1e3));
|
||||
if (i < 0 && errno == EINTR)
|
||||
return (1);
|
||||
AZ(i);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void
|
||||
Time_Unix(struct todolist *tdl)
|
||||
{
|
||||
|
||||
AN(tdl);
|
||||
TB_Step = kt_step;
|
||||
TB_Adjust = kt_adjust;
|
||||
TB_Sleep = kt_sleep;
|
||||
TB_Now = kt_now;
|
||||
kt_tdl = tdl;
|
||||
|
||||
/* XXX: test if we have perms */
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Non-tweaking subset.
|
||||
*/
|
||||
|
||||
void
|
||||
Time_Unix_Passive(void)
|
||||
{
|
||||
|
||||
TB_Sleep = kt_sleep;
|
||||
TB_Now = kt_now;
|
||||
}
|
39
udp.c
39
udp.c
|
@ -25,7 +25,7 @@
|
|||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <poll.h>
|
||||
//#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h> /* Compat for NetBSD */
|
||||
|
@ -35,19 +35,29 @@
|
|||
#include "ntimed.h"
|
||||
#include "udp.h"
|
||||
|
||||
#ifdef AROS
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include <sys/uio.h>
|
||||
#include "atimed.h"
|
||||
#include "apoll.h"
|
||||
|
||||
struct udp_socket {
|
||||
unsigned magic;
|
||||
#define UDP_SOCKET_MAGIC 0x302a563f
|
||||
|
||||
int fd4;
|
||||
int fd6;
|
||||
};
|
||||
|
||||
static int
|
||||
udp_sock(int fam)
|
||||
{
|
||||
int fd;
|
||||
int i;
|
||||
// int i;
|
||||
|
||||
fd = socket(fam, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
|
@ -71,8 +81,8 @@ UdpTimedSocket(struct ocx *ocx)
|
|||
ALLOC_OBJ(usc, UDP_SOCKET_MAGIC);
|
||||
AN(usc);
|
||||
usc->fd4 = udp_sock(AF_INET);
|
||||
usc->fd6 = udp_sock(AF_INET6);
|
||||
if (usc->fd4 < 0 && usc->fd6 < 0)
|
||||
// usc->fd6 = udp_sock(AF_INET6);
|
||||
if (usc->fd4 < 0)
|
||||
Fail(ocx, 1, "socket(2) failed");
|
||||
return (usc);
|
||||
}
|
||||
|
@ -101,8 +111,8 @@ UdpTimedRx(struct ocx *ocx, const struct udp_socket *usc,
|
|||
|
||||
if (fam == AF_INET)
|
||||
pfd[0].fd = usc->fd4;
|
||||
else if (fam == AF_INET6)
|
||||
pfd[0].fd = usc->fd6;
|
||||
// else if (fam == AF_INET6)
|
||||
// pfd[0].fd = usc->fd6;
|
||||
else
|
||||
WRONG("Wrong family in UdpTimedRx");
|
||||
|
||||
|
@ -112,18 +122,18 @@ UdpTimedRx(struct ocx *ocx, const struct udp_socket *usc,
|
|||
if (tmo == 0.0) {
|
||||
tmo_msec = -1;
|
||||
} else {
|
||||
tmo_msec = lround(1e3 * tmo);
|
||||
tmo_msec = round(1e3 * tmo);// lround(1e3 * tmo);
|
||||
if (tmo_msec <= 0)
|
||||
tmo_msec = 0;
|
||||
}
|
||||
i = poll(pfd, 1, tmo_msec);
|
||||
|
||||
|
||||
if (i < 0)
|
||||
Fail(ocx, 1, "poll(2) failed\n");
|
||||
|
||||
if (i == 0)
|
||||
return (0);
|
||||
|
||||
|
||||
/* Grab a timestamp in case none of the SCM_TIMESTAMP* works */
|
||||
TB_Now(ts);
|
||||
|
||||
|
@ -132,7 +142,7 @@ UdpTimedRx(struct ocx *ocx, const struct udp_socket *usc,
|
|||
msg.msg_namelen = sizeof *ss;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = ctrl;
|
||||
msg.msg_control = (char*)ctrl;
|
||||
msg.msg_controllen = sizeof ctrl;
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = (size_t)len;
|
||||
|
@ -140,8 +150,9 @@ UdpTimedRx(struct ocx *ocx, const struct udp_socket *usc,
|
|||
cmsg = (void*)ctrl;
|
||||
|
||||
rl = recvmsg(pfd[0].fd, &msg, 0);
|
||||
if (rl <= 0)
|
||||
if (rl <= 0) {
|
||||
return (rl);
|
||||
}
|
||||
|
||||
*sl = msg.msg_namelen;
|
||||
|
||||
|
@ -195,8 +206,8 @@ Udp_Send(struct ocx *ocx, const struct udp_socket *usc,
|
|||
sa = ss;
|
||||
if (sa->sa_family == AF_INET)
|
||||
return (sendto(usc->fd4, buf, len, 0, ss, sl));
|
||||
if (sa->sa_family == AF_INET6)
|
||||
return (sendto(usc->fd6, buf, len, 0, ss, sl));
|
||||
// if (sa->sa_family == AF_INET6)
|
||||
// return (sendto(usc->fd6, buf, len, 0, ss, sl));
|
||||
|
||||
WRONG("Wrong AF_");
|
||||
NEEDLESS_RETURN(0);
|
||||
|
|
Loading…
Reference in New Issue