diff --git a/agetaddrinfo.c b/agetaddrinfo.c new file mode 100644 index 0000000..b791c0e --- /dev/null +++ b/agetaddrinfo.c @@ -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 +#include +#include +#include +#include + +#include +#include +#include + +#include "atimed.h" +#include "agetaddrinfo.h" + +#if defined(STDC_HEADERS) || defined(HAVE_STRING_H) +#include +#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H) +#include +#endif /* not STDC_HEADERS and HAVE_MEMORY_H */ +#else /* not STDC_HEADERS and not HAVE_STRING_H */ +#include +#endif /* not STDC_HEADERS and not HAVE_STRING_H */ + +#ifdef ENABLE_PTHREAD +#include +#endif + +#ifdef ENABLE_NLS +#include +#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; +} diff --git a/agetaddrinfo.h b/agetaddrinfo.h new file mode 100644 index 0000000..cf0b27d --- /dev/null +++ b/agetaddrinfo.h @@ -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 +#include +#include "atimed.h" + +/********************************************************************/ +/* + * Undefine all the macros. + * 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. + * 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 diff --git a/alib.c b/alib.c new file mode 100644 index 0000000..52b53d3 --- /dev/null +++ b/alib.c @@ -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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef Debug +#undef Debug +#endif +#endif + +#include +#include +#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"); +} diff --git a/apoll.c b/apoll.c new file mode 100644 index 0000000..c4912b4 --- /dev/null +++ b/apoll.c @@ -0,0 +1,105 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: APL License + * + * Copyright (c) 2009 Diego Casorran + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/apoll.h b/apoll.h new file mode 100644 index 0000000..414b245 --- /dev/null +++ b/apoll.h @@ -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 diff --git a/atimed.h b/atimed.h new file mode 100644 index 0000000..ed22cb8 --- /dev/null +++ b/atimed.h @@ -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 +#include +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 +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 diff --git a/combine_delta.c b/combine_delta.c index 9751b4a..c0f9d28 100644 --- a/combine_delta.c +++ b/combine_delta.c @@ -48,7 +48,7 @@ #include #include "ntimed.h" - +#include "atimed.h" struct cd_stat { double x; diff --git a/configure b/configure index 4734a5f..070779f 100644 --- a/configure +++ b/configure @@ -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} diff --git a/main.c b/main.c index 449ba9a..11fbdeb 100644 --- a/main.c +++ b/main.c @@ -30,6 +30,7 @@ #include +#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; } diff --git a/main_client.c b/main_client.c index d87834f..d9557b8 100644 --- a/main_client.c +++ b/main_client.c @@ -35,6 +35,7 @@ #include #include +#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(); diff --git a/main_poll_server.c b/main_poll_server.c index 1da8381..baaa699 100644 --- a/main_poll_server.c +++ b/main_poll_server.c @@ -33,9 +33,9 @@ #include #include - #include +#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); diff --git a/ntimed.h b/ntimed.h index 491491a..333fe82 100644 --- a/ntimed.h +++ b/ntimed.h @@ -32,7 +32,8 @@ #endif #define NTIMED_H_INCLUDED -#include +#include "atimed.h" + #include #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 ****************************/ diff --git a/ntp_peer.c b/ntp_peer.c index 8a6383d..6a7ae36 100644 --- a/ntp_peer.c +++ b/ntp_peer.c @@ -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); diff --git a/ntp_peerset.c b/ntp_peerset.c index a9fe456..d68322a 100644 --- a/ntp_peerset.c +++ b/ntp_peerset.c @@ -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) diff --git a/ocx_stdio.c b/ocx_stdio.c index af08f9f..665d110 100644 --- a/ocx_stdio.c +++ b/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); } diff --git a/suckaddr.c b/suckaddr.c index 97b05ca..6c510d0 100644 --- a/suckaddr.c +++ b/suckaddr.c @@ -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); } diff --git a/time_amiga.c b/time_amiga.c new file mode 100644 index 0000000..203b76a --- /dev/null +++ b/time_amiga.c @@ -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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#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; +} diff --git a/time_stuff.c b/time_stuff.c index 3464f5f..901d50c 100644 --- a/time_stuff.c +++ b/time_stuff.c @@ -36,6 +36,7 @@ #include #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); } diff --git a/time_unix.c b/time_unix.c deleted file mode 100644 index d34b0c5..0000000 --- a/time_unix.c +++ /dev/null @@ -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 -#include -#include -#include -#include - -#include - -#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; -} diff --git a/udp.c b/udp.c index c2b8b14..3e28d37 100644 --- a/udp.c +++ b/udp.c @@ -25,7 +25,7 @@ */ #include -#include +//#include #include #include #include /* Compat for NetBSD */ @@ -35,19 +35,29 @@ #include "ntimed.h" #include "udp.h" +#ifdef AROS +#include +#include +#include +#include +#endif + +#include +#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);