Initial commit

This commit is contained in:
llsth 2015-03-07 23:29:12 +01:00
parent db0abbb4c8
commit a56b6e0b0f
20 changed files with 1565 additions and 374 deletions

573
agetaddrinfo.c Normal file
View File

@ -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;
}

215
agetaddrinfo.h Normal file
View File

@ -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

95
alib.c Normal file
View File

@ -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");
}

105
apoll.c Normal file
View File

@ -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;
}

54
apoll.h Normal file
View File

@ -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

82
atimed.h Normal file
View File

@ -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

View File

@ -48,7 +48,7 @@
#include <string.h>
#include "ntimed.h"
#include "atimed.h"
struct cd_stat {
double x;

13
configure vendored
View File

@ -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
View File

@ -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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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 ****************************/

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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);
}

283
time_amiga.c Normal file
View File

@ -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;
}

View File

@ -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);
}

View File

@ -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
View File

@ -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);