From 5aae9c2cce6a1d84c484fb65cf0eb0fa85713735 Mon Sep 17 00:00:00 2001 From: Carsten Larsen Date: Sat, 24 Nov 2018 22:39:18 +0100 Subject: [PATCH] Version 1.05 --- AmiTimeKeeper.i386-aros.readme | 25 + AmiTimeKeeper.kdev4 | 4 + AmiTimeKeeper.readme | 25 + ChangeLog | 33 ++ LICENSE | 25 + Makefile.aros | 49 ++ Makefile.m68k | 58 +++ broker.c | 331 +++++++++++++ com.c | 461 +++++++++++++++++ compiler.h | 47 ++ config.h | 219 ++++++++ include/clib/amitcp_protos.h | 114 +++++ include/inline/amitcp.h | 203 ++++++++ include/netdb.h | 231 +++++++++ include/netinet/in.h | 275 +++++++++++ include/sys/errno.h | 189 +++++++ include/sys/netinclude_types.h | 64 +++ include/sys/socket.h | 421 ++++++++++++++++ library.c | 341 +++++++++++++ log.c | 247 +++++++++ log.h | 42 ++ main.c | 154 ++++++ mem.c | 297 +++++++++++ mem.h | 39 ++ message.c | 97 ++++ message.h | 60 +++ net.c | 182 +++++++ net_getaddrinfo.c | 564 +++++++++++++++++++++ net_getaddrinfo.h | 209 ++++++++ net_poll.c | 82 +++ sntp.c | 466 +++++++++++++++++ sntp.h | 105 ++++ state.c | 880 +++++++++++++++++++++++++++++++++ state.h | 146 ++++++ string.c | 391 +++++++++++++++ string.h | 49 ++ time.c | 235 +++++++++ time.h | 51 ++ win.h | 65 +++ win_gad.c | 686 +++++++++++++++++++++++++ win_main.c | 343 +++++++++++++ 41 files changed, 8505 insertions(+) create mode 100644 AmiTimeKeeper.i386-aros.readme create mode 100644 AmiTimeKeeper.kdev4 create mode 100644 AmiTimeKeeper.readme create mode 100644 ChangeLog create mode 100644 LICENSE create mode 100644 Makefile.aros create mode 100644 Makefile.m68k create mode 100644 broker.c create mode 100644 com.c create mode 100644 compiler.h create mode 100644 config.h create mode 100644 include/clib/amitcp_protos.h create mode 100644 include/inline/amitcp.h create mode 100644 include/netdb.h create mode 100644 include/netinet/in.h create mode 100644 include/sys/errno.h create mode 100644 include/sys/netinclude_types.h create mode 100644 include/sys/socket.h create mode 100644 library.c create mode 100644 log.c create mode 100644 log.h create mode 100644 main.c create mode 100644 mem.c create mode 100644 mem.h create mode 100644 message.c create mode 100644 message.h create mode 100644 net.c create mode 100644 net_getaddrinfo.c create mode 100644 net_getaddrinfo.h create mode 100644 net_poll.c create mode 100644 sntp.c create mode 100644 sntp.h create mode 100644 state.c create mode 100644 state.h create mode 100644 string.c create mode 100644 string.h create mode 100644 time.c create mode 100644 time.h create mode 100644 win.h create mode 100644 win_gad.c create mode 100644 win_main.c diff --git a/AmiTimeKeeper.i386-aros.readme b/AmiTimeKeeper.i386-aros.readme new file mode 100644 index 0000000..991cea2 --- /dev/null +++ b/AmiTimeKeeper.i386-aros.readme @@ -0,0 +1,25 @@ +Short: Keep your time right +Uploader: Carsten Larsen +Author: Carsten Larsen (carsten.larsen@mail.com) +Type: util/cdity +Version: 1.05 +Architecture: i386-aros + +AmiTimeKeeper is a small program which keeps the time right on your +machine. No installation is required. Only an internet connection is +needed. + +AmiTimeKeeper can be controlled through a number of settings. This +can be done either directly from the command line or by using the +tooltypes of an icon. Preferences can also be saved between reboots. + +The default server address is currently pool.ntp.org. To find another +server try visiting support.ntp.org or one of the other sites listing +time servers. + +Major changes in 1.05 06.08.2018 +- Preferences can now be saved from settings window +- Running multiple instances no longer creates zombie processes +- Low water option renamed to threshold and high water option removed +- New option for sending log messages to file instead of to screen +- Read-only options is now applied consistently diff --git a/AmiTimeKeeper.kdev4 b/AmiTimeKeeper.kdev4 new file mode 100644 index 0000000..509d95e --- /dev/null +++ b/AmiTimeKeeper.kdev4 @@ -0,0 +1,4 @@ +[Project] +CreatedFrom=Makefile.m68k +Manager=KDevCustomMakeManager +Name=AmiTimeKeeper diff --git a/AmiTimeKeeper.readme b/AmiTimeKeeper.readme new file mode 100644 index 0000000..5e20326 --- /dev/null +++ b/AmiTimeKeeper.readme @@ -0,0 +1,25 @@ +Short: Keep your time right +Uploader: Carsten Larsen +Author: Carsten Larsen (carsten.larsen@mail.com) +Type: util/cdity +Version: 1.05 +Architecture: m68k-amigaos + +AmiTimeKeeper is a small program which keeps the time right on your +machine. No installation is required. Only an internet connection is +needed. + +AmiTimeKeeper can be controlled through a number of settings. This +can be done either directly from the command line or by using the +tooltypes of an icon. Preferences can also be saved between reboots. + +The default server address is currently pool.ntp.org. To find another +server try visiting support.ntp.org or one of the other sites listing +time servers. + +Major changes in 1.05 06.08.2018 +- Preferences can now be saved from settings window +- Running multiple instances no longer creates zombie processes +- Low water option renamed to threshold and high water option removed +- New option for sending log messages to file instead of to screen +- Read-only options is now applied consistently diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..704f5fa --- /dev/null +++ b/ChangeLog @@ -0,0 +1,33 @@ +AmiTimeKeeper Change Log + +v1.05 06.08.2018 + - Preferences can now be saved from settings window + - Time zone is shown as UTC offset in settings window + - Running multiple instances no longer creates zombie processes + - Low water option renamed to threshold and high water option removed + - New option for sending log messages to file instead of to screen + - Some incorrect NTP log messages no longer appears + - Read-only options is now applied consistently + - Potential race condition in memory allocation fixed + - Other minor enhancements + +v1.04 15.12.2017 + - Default settings adjusted to comply better with AmigaOS + - Bugs in threshold settings (high/low water) fixed + - Bugs in opening and closing of libraries fixed + - New and more accurate error and log messages + +v1.03 09.12.2017 + - Settings window + +v1.02 29.11.2017 + - AROS code compliance + +v1.01 28.11.2017 + - Handle network disconnection + - Fix infinity timeout problem + - Support hardware clock + - Improved error messages + +v1.00 26.11.2017 + - First public release diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8841b7d --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2001, 02 Motoyuki Kasahara +Copyright (c) 2007 TANDBERG Telecom AS +Copyright (c) 2008-2009 Dag-Erling Smørgrav +Copyright (c) 2017-2018 Carsten Sonne 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. diff --git a/Makefile.aros b/Makefile.aros new file mode 100644 index 0000000..4ed896f --- /dev/null +++ b/Makefile.aros @@ -0,0 +1,49 @@ + +all: timekeeper + +CC = gcc +CFLAGS += -O2 -fno-stack-protector -DAROS -Wall +LDLIBS += + +broker.o: compiler.h config.h message.h win.h + +com.o: compiler.h config.h message.h state.h time.h sntp.h mem.h + +library.o: compiler.h config.h time.h mem.h + +log.o: compiler.h config.h log.h mem.h + +main.o: compiler.h config.h state.h time.h mem.h + +mem.o: compiler.h config.h mem.h + +message.o: compiler.h config.h message.h mem.h + +net_getaddrinfo.o: compiler.h mem.h config.h net_getaddrinfo.h + +net_poll.o: compiler.h config.h mem.h + +net.o: compiler.h config.h net_getaddrinfo.h message.h mem.h + +sntp.o: compiler.h config.h sntp.h time.h net_getaddrinfo.h message.h mem.h + +state.o: compiler.h config.h state.h mem.h + +string.o: compiler.h config.h string.h mem.h + +time.o: compiler.h config.h time.h mem.h + +win_main.o: compiler.h config.h message.h state.h time.h mem.h win.h + +win_gad.o: compiler.h config.h message.h state.h time.h mem.h win.h + +timekeeper: broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o win_main.o win_gad.o + ${CC} ${CFLAGS} ${LFLAGS} -s -o TimeKeeper \ + broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o win_main.o win_gad.o \ + ${LDLIBS} + +clean: + rm -f TimeKeeper broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o settings.o sntp.o state.o time.o string.o win_main.o win_gad.o TimeKeeper.map + +depend: + @echo Dependencies already done diff --git a/Makefile.m68k b/Makefile.m68k new file mode 100644 index 0000000..dd33844 --- /dev/null +++ b/Makefile.m68k @@ -0,0 +1,58 @@ + +all: timekeeper + +CC = /opt/m68k-amigaos/bin/m68k-amigaos-gcc + +# clib2 +#CFLAGS = -O2 -DAOS3 -Iinclude -mcrt=clib2 -m68020 -fbaserel32 -Wall +#LFALGS = -Wl,--cref,-M,-Map=TimeKeeper.map +#LDLIBS = -lnet + +# libnix +#CFLAGS = -O2 -DAOS3 -fomit-frame-pointer -fno-stack-check -Iinclude -noixemul -Wall +CFLAGS = -O2 -DAOS3 -fno-stack-check -Iinclude -noixemul -Wall +LFLAGS = -Wl,--cref,-M,-Map=TimeKeeper.map +LDLIBS = + +broker.o: compiler.h config.h message.h win.h + +com.o: compiler.h config.h message.h state.h time.h sntp.h mem.h + +library.o: compiler.h config.h time.h mem.h + +log.o: compiler.h config.h log.h mem.h + +main.o: compiler.h config.h state.h time.h mem.h + +mem.o: compiler.h config.h mem.h + +message.o: compiler.h config.h message.h mem.h + +net_getaddrinfo.o: compiler.h mem.h config.h net_getaddrinfo.h + +net_poll.o: compiler.h config.h mem.h + +net.o: compiler.h config.h net_getaddrinfo.h message.h mem.h + +sntp.o: compiler.h config.h sntp.h time.h net_getaddrinfo.h message.h mem.h + +state.o: compiler.h config.h state.h mem.h + +string.o: compiler.h config.h string.h mem.h + +time.o: compiler.h config.h time.h mem.h + +win_main.o: compiler.h config.h message.h state.h time.h mem.h win.h + +win_gad.o: compiler.h config.h message.h state.h time.h mem.h win.h + +timekeeper: broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o win_main.o win_gad.o + ${CC} ${CFLAGS} ${LFLAGS} -s -o TimeKeeper \ + broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o win_main.o win_gad.o \ + ${LDLIBS} + +clean: + rm -f TimeKeeper broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o settings.o sntp.o state.o time.o string.o win_main.o win_gad.o TimeKeeper.map + +depend: + @echo Dependencies already done diff --git a/broker.c b/broker.c new file mode 100644 index 0000000..ebe4333 --- /dev/null +++ b/broker.c @@ -0,0 +1,331 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" +#include "message.h" +#include "mem.h" +#include "win.h" + +static void ProcessMsg(void); + +static struct NewBroker newBroker = { + NB_VERSION, + (STRPTR)APP_SHORT_NAME, + (STRPTR)APP_TITLE_VERSION, + (STRPTR) "Synchronize Clock With Internet Servers", + NBU_UNIQUE | NBU_NOTIFY, + COF_SHOW_HIDE, + 0, 0, 0}; + +void StartBroker(void) +{ + LONG error; + struct Message *msg; + + Globals->Broker->BrokerPort = CreateMsgPort(); + if (Globals->Broker->BrokerPort == NULL) + { + LogError("Could not allocate broker port"); + return; + } + + Globals->Broker->UserPort = CreateMsgPort(); + if (Globals->Broker->UserPort == NULL) + { + LogError("Could not allocate broker user port"); + DeleteMsgPort(Globals->Broker->BrokerPort); + Globals->Broker->BrokerPort = NULL; + return; + } + + Globals->Broker->ReplyPort = CreateMsgPort(); + if (Globals->Broker->ReplyPort == NULL) + { + LogError("Could not allocate broker reply port"); + DeleteMsgPort(Globals->Broker->BrokerPort); + DeleteMsgPort(Globals->Broker->UserPort); + Globals->Broker->BrokerPort = NULL; + Globals->Broker->UserPort = NULL; + return; + } + + Globals->Broker->ShutdownSigBit = AllocSignal(-1); + if (Globals->Broker->ShutdownSigBit == -1) + { + SendErrorMessage("Could not allocate signal for broker"); + DeleteMsgPort(Globals->Broker->BrokerPort); + DeleteMsgPort(Globals->Broker->UserPort); + DeleteMsgPort(Globals->Broker->ReplyPort); + Globals->Broker->BrokerPort = NULL; + Globals->Broker->UserPort = NULL; + Globals->Broker->ReplyPort = NULL; + return; + } + + newBroker.nb_Port = Globals->Broker->BrokerPort; + newBroker.nb_Pri = Globals->Settings->Priority; + + Globals->Broker->Object = CxBroker(&newBroker, &error); + if (!Globals->Broker->Object) + { + switch (error) + { + case CBERR_SYSERR: + LogError("System problems (CBERR_SYSERR). Could not allocate broker object"); + break; + case CBERR_DUP: + LogWarning(APP_SHORT_NAME " already running"); + break; + default: + LogError("Could not allocate broker object (error code: %ld)", error); + break; + } + + DeleteMsgPort(Globals->Broker->BrokerPort); + DeleteMsgPort(Globals->Broker->UserPort); + DeleteMsgPort(Globals->Broker->ReplyPort); + Globals->Broker->BrokerPort = NULL; + Globals->Broker->UserPort = NULL; + Globals->Broker->ReplyPort = NULL; + Globals->Broker->Object = NULL; + return; + } + + Globals->Broker->Task = FindTask(NULL); + + StartCom(); + ProcessMsg(); + + while ((msg = GetMsg(Globals->Broker->BrokerPort))) + ReplyMsg(msg); + + while ((msg = GetMsg(Globals->Broker->UserPort))) + ReplyMsg(msg); + + while ((msg = GetMsg(Globals->Broker->ReplyPort))) + ReplyMsg(msg); + + DeleteCxObj(Globals->Broker->Object); + FreeSignal(Globals->Broker->ShutdownSigBit); + DeleteMsgPort(Globals->Broker->BrokerPort); + DeleteMsgPort(Globals->Broker->UserPort); + DeleteMsgPort(Globals->Broker->ReplyPort); + Globals->Broker->BrokerPort = NULL; + Globals->Broker->UserPort = NULL; + Globals->Broker->ReplyPort = NULL; + Globals->Broker->Object = NULL; +} + +void ShutdownBroker(void) +{ + Signal((struct Task *)Globals->Broker->Task, + (1 << Globals->Broker->ShutdownSigBit)); +} + +void SetBrokerPriority(int priority) +{ + SetCxObjPri(Globals->Broker->Object, priority); +} + +static void Activate(void) +{ + LogWarning("ACTIVE changed: 1 -> 0"); + ActivateCxObj(Globals->Broker->Object, 0); + Globals->Active = false; + StopComAsync(); + while (!CheckComClosed()) + Delay(1); +} + +static void Deactivate(void) +{ + LogWarning("ACTIVE changed: 0 -> 1"); + ActivateCxObj(Globals->Broker->Object, 1); + Globals->Active = true; + StartCom(); +} + +static void StopSubProcesses(void) +{ + Forbid(); + Globals->ShuttingDown = true; + Permit(); + + HideSettingWindow(); + while (!CheckSettingWindowClosed()) + Delay(10); + + StopComAsync(); + while (!CheckComClosed()) + Delay(10); +} + +static void ProcessMsg(void) +{ + bool run = true; + ULONG sigmask = SIGBREAKF_CTRL_C | + (1 << Globals->Broker->ShutdownSigBit) | + (1 << Globals->Broker->BrokerPort->mp_SigBit) | + (1 << Globals->Broker->UserPort->mp_SigBit) | + (1 << Globals->Broker->ReplyPort->mp_SigBit); + + ActivateCxObj(Globals->Broker->Object, 1); + Globals->Active = true; + + do + { + ULONG sigrcvd = Wait(sigmask); + + if (sigrcvd & (1 << Globals->Broker->BrokerPort->mp_SigBit)) + { + CxMsg *msg; + while ((msg = (CxMsg *)GetMsg(Globals->Broker->BrokerPort))) + { + LONG msgid = CxMsgID(msg); + ULONG msgtype = CxMsgType(msg); + ReplyMsg((struct Message *)msg); + + switch (msgtype) + { + case CXM_IEVENT: + break; + case CXM_COMMAND: + switch (msgid) + { + case CXCMD_DISABLE: + Activate(); + break; + case CXCMD_ENABLE: + Deactivate(); + break; + case CXCMD_KILL: + LogInfo("Received shut down from commodity"); + LogWarning("Shutting down"); + StopSubProcesses(); + run = false; + break; + case CXCMD_UNIQUE: + LogWarning("Commodity duplicate detected"); + LogTrace("Show window"); + ShowSettingWindow(); + break; + case CXCMD_APPEAR: + LogTrace("Show window"); + ShowSettingWindow(); + break; + case CXCMD_DISAPPEAR: + LogTrace("Hide window"); + HideSettingWindow(); + break; + } + } + } + } + + if (sigrcvd & (1 << Globals->Broker->UserPort->mp_SigBit)) + { + struct AppWindowMessage *msg; + while ((msg = (struct AppWindowMessage *)GetMsg(Globals->Broker->UserPort))) + { + switch (msg->Type) + { + case ATK_LOGERROR: + LogError(msg->Text); + break; + case ATK_LOGWARN: + LogWarning(msg->Text); + break; + case ATK_LOGINFO: + LogInfo(msg->Text); + break; + case ATK_LOGTRACE: + LogTrace(msg->Text); + break; + case ATK_STORE: + SaveSettings(true); + SaveSettings(false); + break; + case ATK_APPLY: + SaveSettings(false); + break; + case ATK_UNDO: + ApplyAppSettings(Globals->Window->Settings, true); + break; + case ATK_RESTART: + RestartSntpAsync(); + break; + case ATK_REFRESH: + // Broker cannot refresh + break; + case ATK_DISABLE: + Activate(); + break; + case ATK_ENABLE: + Deactivate(); + break; + case ATK_READONLY: + LogWarning("READONLY changed: 1 -> 0"); + break; + case ATK_READWRITE: + LogWarning("READONLY changed: 0 -> 1"); + break; + default: + break; + } + ReplyMsg((struct Message *)msg); + } + } + + if (sigrcvd & (1 << Globals->Broker->ReplyPort->mp_SigBit)) + { + struct AppWindowMessage *msg; + while ((msg = (struct AppWindowMessage *)GetMsg(Globals->Broker->ReplyPort))) + { + if (msg->Text != NULL) + { + FreeMemSafe(msg->Text); + } + FreeMemSafe(msg); + } + } + + if (sigrcvd & (1 << Globals->Broker->ShutdownSigBit)) + { + LogInfo("Received shut down from setting window"); + LogWarning("Shutting down"); + StopSubProcesses(); + run = false; + } + + if (sigrcvd & SIGBREAKF_CTRL_C) + { + LogInfo("Received CTRL + C"); + LogWarning("Shutting down"); + StopSubProcesses(); + run = false; + } + } while (run); +} diff --git a/com.c b/com.c new file mode 100644 index 0000000..590846c --- /dev/null +++ b/com.c @@ -0,0 +1,461 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" +#include "message.h" +#include "state.h" +#include "time.h" +#include "sntp.h" +#include "mem.h" + +struct AppCom +{ + bool Run; + bool Restart; + bool Exited; + struct Process *Task; + struct TimerInfo *TimerInfo; + struct sntp *Client; + short RestartSigBit; + bool FirstRun; + int RunCount; + int FailCount; +}; + +static void SyncProc(void); +static void ComOpen(void); +static void ComInit(void); +static int SyncClock(void); +static void ShowStats(void); +static ULONG GetSntpRestartSigMask(void); +static const char *SntpErrorText(enum sntp_err error); + +void RestartSntpAsync(void) +{ + if (Globals->Syncer->Task != NULL) + { + Signal((struct Task *)Globals->Syncer->Task, GetSntpRestartSigMask()); + } +} + +void StopComAsync(void) +{ + if (Globals->Syncer->Task != NULL) + { + Signal((struct Task *)Globals->Syncer->Task, SIGBREAKF_CTRL_C); + } +} + +bool CheckComClosed(void) +{ + return Globals->Syncer->Exited; +} + +void StartCom(void) +{ + if (Globals->Syncer != NULL && Globals->Syncer->Task != NULL) + { + LogTrace("Synchronizer process already running"); + return; + } + + if (Globals->Syncer == NULL) + { + Globals->Syncer = (struct AppCom *)AllocMemSafe(sizeof(struct AppCom)); + } + + Globals->Syncer->Run = true; + Globals->Syncer->Restart = false; + Globals->Syncer->Exited = false; + Globals->Syncer->FirstRun = true; + Globals->Syncer->RunCount = 0; + Globals->Syncer->FailCount = 0; + + Forbid(); + Globals->Syncer->Task = CreateNewProcTags( + NP_Entry, (IPTR)SyncProc, + NP_Name, (IPTR)APP_SHORT_NAME " Synchronizer", + NP_StackSize, 64 * 1024, + TAG_DONE); + Permit(); + + if (Globals->Syncer->Task != NULL) + { + LogTrace("Created synchronizer process"); + } + else + { + LogError("Failed to create synchronizer process"); + } +} + +static ULONG GetSntpRestartSigMask(void) +{ + return (1 << Globals->Syncer->RestartSigBit); +} + +static void ComDestroy(void) +{ + if (Globals->Syncer->Client != NULL) + { + sntp_destroy(Globals->Syncer->Client); + Globals->Syncer->Client = NULL; + } +} + +static void Sync(void) +{ + char message[SETTINGMESSAGELEN]; + ComOpen(); + SetTimer(Globals->Syncer->TimerInfo); + SNPrintf(message, SETTINGMESSAGELEN, + "Sending next NTP request in %ld milliseconds", + Globals->Settings->Interval); + SendTraceMessage(message); + ShowStats(); + Globals->Syncer->RunCount++; +} + +static void SyncProc(void) +{ + Globals->Syncer->TimerInfo = CreateTimer(false); + if (Globals->Syncer->TimerInfo == NULL) + { + SendErrorMessage("Could not create timer for synchronizer"); + Globals->Syncer->Exited = true; + return; + } + + Globals->Syncer->RestartSigBit = AllocSignal(-1); + if (Globals->Syncer->RestartSigBit == -1) + { + SendErrorMessage("Could not allocate signal for synchronizer"); + DeleteTimer(Globals->Syncer->TimerInfo); + Globals->Syncer->Exited = true; + return; + } + + Sync(); + + do + { + ULONG sigtime = GetTimerSigMask(Globals->Syncer->TimerInfo); + ULONG sigrest = GetSntpRestartSigMask(); + ULONG sigmask = SIGBREAKF_CTRL_C | sigtime | sigrest; + ULONG sigrcvd = Wait(sigmask); + + if (sigrcvd & sigtime) + { + Sync(); + } + + if (sigrcvd & sigrest) + { + ComDestroy(); + Globals->Syncer->Restart = true; + ComOpen(); + } + + if (sigrcvd & SIGBREAKF_CTRL_C) + { + Globals->Syncer->Run = false; + } + } while (Globals->Syncer->Run); + + ComDestroy(); + FreeSignal(Globals->Syncer->RestartSigBit); + DeleteTimer(Globals->Syncer->TimerInfo); + CloseSocketLibrary(); + + if (!Globals->ShuttingDown) + { + SendWarningMessage("Exited synchronizer process"); + } + + Globals->Syncer->TimerInfo = NULL; + Globals->Syncer->Task = NULL; + Globals->Syncer->Exited = true; +} + +static void ComOpen(void) +{ + if (OpenSocketLibrary() != LIB_OK) + { + // Make sure socket library is open + return; + } + + if (Globals->Syncer->FirstRun) + { + SendInfoMessage("Starting SNTP client"); + ComInit(); + Globals->Syncer->FirstRun = false; + } + + if (Globals->Syncer->Restart) + { + SendInfoMessage("Restart SNTP client"); + ComInit(); + Globals->Syncer->Restart = false; + } + + if (SyncClock() == COM_OK) + { + Globals->Syncer->FailCount = 0; + } + else + { + Globals->Syncer->FailCount++; + } + + if (Globals->Syncer->FailCount != 0 && Globals->Syncer->FailCount % 5 == 0) + { + ComDestroy(); + Globals->Syncer->Restart = true; + } + + if (Globals->Syncer->FailCount == 10) + { + SendInfoMessage("Reinitialize socket library"); + ComDestroy(); + CloseSocketLibrary(); + Globals->Syncer->FailCount = 0; + } +} + +static void ShowStats(void) +{ + if (Globals->Syncer->RunCount % 10 == 0) + { + char message[SETTINGMESSAGELEN]; + char timeString[10], dateString[10], dayString[10]; + SystemTimeString(timeString, dateString, dayString); + SNPrintf(message, SETTINGMESSAGELEN, + "Local time is %s %s %s", + dayString, dateString, timeString); + SendInfoMessage(message); + } + + if (Globals->Syncer->RunCount % 25 == 0) + { + char message[SETTINGMESSAGELEN]; + long blocks, size; + MemUsage(&blocks, &size, NULL); + SNPrintf(message, SETTINGMESSAGELEN, + "Currently using %ld bytes in %ld blocks on heap", + size, blocks); + SendInfoMessage(message); + } +} + +static void ComInit(void) +{ + if (Globals->Syncer->Client != NULL) + { + sntp_destroy(Globals->Syncer->Client); + Globals->Syncer->Client = NULL; + } + + Globals->Syncer->Client = sntp_create( + Globals->Settings->DestinationAddress, + Globals->Settings->DestinationPort, + NULL, + NULL); + + if (Globals->Syncer->Client == NULL) + { + SendWarningMessage("Could not create SNTP client"); + return; + } +} + +static int SyncClock(void) +{ + char message[SETTINGMESSAGELEN]; + struct timeval rtv, ltv, tv; + long long lt, rt, dt, adt, th; + struct ntptime nt; + bool readOnly; + int trace, ret; + + th = Globals->Settings->Threshold; + readOnly = Globals->Settings->Readonly; + trace = TraceLogging(); + + SNPrintf(message, SETTINGMESSAGELEN, + "Sending request to %s:%s", + Globals->Settings->DestinationAddress, + Globals->Settings->DestinationPort); + SendInfoMessage(message); + + ret = sntp_send(Globals->Syncer->Client); + if (ret != SNTP_OK) + { + SNPrintf(message, SETTINGMESSAGELEN, + "SNTP send failed: %s", + SntpErrorText(ret)); + SendWarningMessage(message); + return COM_ERROR; + } + + if (trace) + { + SendTraceMessage("Waiting for response"); + } + + ret = sntp_poll(Globals->Syncer->Client, Globals->Settings->Timeout); + if (ret != SNTP_OK) + { + SNPrintf(message, SETTINGMESSAGELEN, + "SNTP poll failed: %s", + SntpErrorText(ret)); + SendWarningMessage(message); + return COM_ERROR; + } + + if (trace) + { + SendTraceMessage("Processing response"); + } + + ret = sntp_recv(Globals->Syncer->Client, &nt); + if (ret != SNTP_OK) + { + SNPrintf(message, SETTINGMESSAGELEN, + "SNTP recieve failed: %s", + SntpErrorText(ret)); + SendWarningMessage(message); + + if (ret == SNTP_BACKOFF) + { + SNPrintf(message, SETTINGMESSAGELEN, + "Increasing polling interval: %ld -> %ld", + Globals->Settings->Interval, + Globals->Settings->Interval * 2); + SendWarningMessage(message); + Globals->Settings->Interval *= 2; + } + return COM_ERROR; + } + + nt2tv(&nt, &rtv); + if (trace) + { + SNPrintf(message, SETTINGMESSAGELEN, + "Got time %lu.%06lu", + (unsigned long)rtv.tv_secs, + (unsigned long)rtv.tv_micro); + SendTraceMessage(message); + } + + GetTimeOfDay(<v); + + lt = 1000000LL * ltv.tv_secs + ltv.tv_micro; + rt = 1000000LL * rtv.tv_secs + rtv.tv_micro; + dt = rt - lt; + adt = dt < 0 ? -dt : dt; + + if (trace) + { + static char out[MAXLONGLONGCHARSIZE]; + LongLongToStr(rt, out); + SNPrintf(message, SETTINGMESSAGELEN, "True time %s", out); + SendTraceMessage(message); + LongLongToStr(lt, out); + SNPrintf(message, SETTINGMESSAGELEN, "Kernel time %s", out); + SendTraceMessage(message); + LongLongToStr(dt, out); + SNPrintf(message, SETTINGMESSAGELEN, "Delta %s", out); + SendTraceMessage(message); + } + + if (!readOnly && adt < th) + { + static char out[MAXLONGLONGCHARSIZE]; + static char out2[MAXLONGLONGCHARSIZE]; + LongLongToStr(adt, out); + LongLongToStr(th, out2); + SNPrintf(message, SETTINGMESSAGELEN, + "%s us < %s us, not setting clock", + out, out2); + SendInfoMessage(message); + } + else if (!readOnly) + { + tv.tv_secs = rt / 1000000; + tv.tv_micro = rt % 1000000; + SetTimeOfDay(Globals->Syncer->TimerInfo, &tv); + + { // Log after setting clock + static char out[MAXLONGLONGCHARSIZE]; + static char out2[MAXLONGLONGCHARSIZE]; + LongLongToStr(adt, out); + LongLongToStr(th, out2); + SNPrintf(message, SETTINGMESSAGELEN, + "%s us > %s us, setting software clock", + out, out2); + SendWarningMessage(message); + SendWarningMessage("Setting hardware clock"); + SaveTimeOfDay(&tv); + } + } + + Globals->LastNtpSync = rtv; + Forbid(); + if (Globals->Window->Task != NULL && !Globals->ShuttingDown) + { + SendMessageTo(Globals->Window->UserPort, Globals->Broker->ReplyPort, ATK_REFRESH); + } + Permit(); + + return COM_OK; +} + +static const char *SntpErrorText(enum sntp_err error) +{ + switch (error) + { + case SNTP_OK: + return "OK"; + case SNTP_SYSERR: + return GetErrorText(); + case SNTP_DNSERR: + return GetHostErrorText(); + case SNTP_NOREQ: + return "No request sent"; + case SNTP_NORESP: + return "No response received"; + case SNTP_BADRESP: + return "Invalid response received"; + case SNTP_LAME: + return "Server is lame / unsynchronized"; + case SNTP_BACKOFF: + return "Polling too frequently"; + default: + return "Unknown error"; + } + return "Unknown error"; +} diff --git a/compiler.h b/compiler.h new file mode 100644 index 0000000..96a2dfe --- /dev/null +++ b/compiler.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2014-2018 Carsten Sonne 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 COMPILER_H_INCLUDED +#define COMPILER_H_INCLUDED + +#ifndef __cplusplus +typedef int bool; +#define true 1 +#define false 0 +#endif + +#ifdef __GNUC__ +#ifndef REG +#define REG(reg, arg) arg __asm(#reg) +#endif +#else +#error Need REG assembler define +#endif + +#define MAXLONGCHARSIZE 12 +#define MAXLONGLONGCHARSIZE 22 + +#endif diff --git a/config.h b/config.h new file mode 100644 index 0000000..ed41d25 --- /dev/null +++ b/config.h @@ -0,0 +1,219 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 CONFIG_H_INCLUDED +#define CONFIG_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "compiler.h" + +//#define DEBUG_BUILD 1 + +#if defined(AROS) || defined(__CLIB2__) +#include +#endif + +#if defined(__libnix__) +typedef u_int8_t uint8_t; +typedef u_int16_t uint16_t; +typedef u_int32_t uint32_t; +typedef u_int64_t uint64_t; +typedef uint32_t uintptr_t; +#endif + +#if defined(__CLIB2__) +#define __NO_NET_API +#define NO_INLINE_STDARG +#endif + +#if defined(AROS) || defined(__CLIB2__) +#include +#include +#endif + +#if defined(__libnix__) +#include +#include "clib/amitcp_protos.h" +#endif + +#if defined(__libnix__) || defined(__CLIB2__) +#include "netdb.h" +#include "sys/errno.h" +#include "sys/socket.h" +#include "netinet/in.h" +#else +#include +#include +#include +#include +#endif + +#ifdef MAXPATHLEN +#undef MAXPATHLEN +#endif +#ifdef MAXFILELEN +#undef MAXFILELEN +#endif +#ifdef MAXFILEPATHLEN +#undef MAXFILEPATHLEN +#endif +#define MAXPATHLEN 1792 +#define MAXFILELEN 256 +#define MAXFILEPATHLEN MAXPATHLEN + MAXFILELEN +#define MAXDOSERRORLEN 256 +#define SETTINGMESSAGELEN 128 + +#ifndef HAVE_POLL +#define POLLIN 0x0001 +struct pollfd +{ + int fd; + short events; + short revents; +}; +typedef unsigned int nfds_t; +int poll(struct pollfd *, nfds_t, int); +#endif + +#if AOS3 +#define IPTR ULONG +#endif +#if AOS3 +#define VARSIZE 0 +#else +#define VARSIZE 1 +#endif + +#ifdef AROS +#define VSNPrintf(str, n, format, args) vsnprintf(str, n, format, args) +#define SNPrintf(str, n, format, ...) snprintf(str, n, format, __VA_ARGS__) +#endif + +#define LIB_OK 0 +#define COM_OK 0 +#define LIB_ERROR -1 +#define COM_ERROR -1 + +#define APP_SHORT_NAME "AmiTimeKeeper" +#define APP_LONG_NAME "Amiga Time Keeper" +#define APP_VERSION "1.05" +#define APP_DATE_VERSION "1.05 (06.08.2018)" +#define APP_ID APP_SHORT_NAME " " APP_DATE_VERSION +#define APP_TITLE APP_LONG_NAME " " APP_DATE_VERSION +#define APP_TITLE_VERSION APP_LONG_NAME " " APP_VERSION + +#include "log.h" +#include "state.h" +#include "string.h" + +#define KEYWORD_COUNT 9 +#define KEYWORD_SERVER "SERVER" +#define KEYWORD_PORT "PORT" +#define KEYWORD_THRESHOLD "THRESHOLD" +#define KEYWORD_INTERVAL "INTERVAL" +#define KEYWORD_PRIORITY "CX_PRIORITY" +#define KEYWORD_READONLY "READONLY" +#define KEYWORD_TIMEOUT "TIMEOUT" +#define KEYWORD_VERBOSE "VERBOSE" +#define KEYWORD_LOGFILE "LOGFILE" + +#define SERVER_DEF "pool.ntp.org" +#define PORT_DEF "123" +#define THRESHOLD_MIN 1000LL +#define THRESHOLD_DEF 1000000LL +#define INTERVAL_MIN 500 +#define INTERVAL_DEF 17500 +#define PRIORITY_MIN -128 +#define PRIORITY_DEF 25 +#define PRIORITY_MAX 127 +#define READONLY_DEF 0 +#define TIMEOUT_MIN 100 +#define TIMEOUT_DEF 5000 +#define TIMEOUT_MAX 30000 +#define VERBOSE_MIN 0 +#define VERBOSE_DEF 0 +#define VERBOSE_MAX 3 +#define LOGFILE_DEF NULL + +#define KEYWORD_TEMPLATE_1 KEYWORD_READONLY "/S," KEYWORD_SERVER "/K," KEYWORD_PORT "/K," KEYWORD_TIMEOUT "/N/K," KEYWORD_THRESHOLD "/K," +#define KEYWORD_TEMPLATE_2 KEYWORD_INTERVAL "/N/K," KEYWORD_VERBOSE "/N/K," KEYWORD_PRIORITY "/N/K," KEYWORD_LOGFILE "/K" +#define KEYWORD_TEMPLATE KEYWORD_TEMPLATE_1 KEYWORD_TEMPLATE_2 + +/* broker.c */ +void StartBroker(void); +void SetBrokerPriority(int); +void ShutdownBroker(void); + +/* com.c */ +void StartCom(void); +void StopComAsync(void); +void RestartSntpAsync(void); +bool CheckComClosed(void); + +/* win_main.c */ +void ShowSettingWindow(void); +void HideSettingWindow(void); + +/* libraries.c */ +int OpenLibraries(void); +void CloseLibraries(void); + +/* net.c */ +int OpenSocketLibrary(void); +void CloseSocketLibrary(void); +const char *GetErrorText(void); +const char *GetHostErrorText(void); +int GetErrorNo(void); +int GetHostErrorNo(void); +extern struct Library *SocketBase; + +#endif diff --git a/include/clib/amitcp_protos.h b/include/clib/amitcp_protos.h new file mode 100644 index 0000000..4570685 --- /dev/null +++ b/include/clib/amitcp_protos.h @@ -0,0 +1,114 @@ +/* + * 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 _SOCKET_AMITCP_H +#define _SOCKET_AMITCP_H + +#define AMITCP_BASE_NAME SocketBase +#include "inline/amitcp.h" + +#define socket Socket +#define bind Bind +#define listen Listen +#define accept Accept +#define connect Connect +#define send Send +#define sendto SendTo +#define sendmsg SendMsg +#define recv Recv +#define recvfrom RecvFrom +#define recvmsg RecvMsg +#define shutdown Shutdown +#define setsockopt SetSockOpt +#define getsockopt GetSockOpt +#define getsockname GetSockName +#define getpeername GetPeerName +#define inet_addr Inet_Addr +#define inet_network Inet_Network +#define inet_ntoa Inet_NtoA +#define gethostbyname GetHostByName +#define gethostbyaddr GetHostByAddr +#define getnetbyname GetNetByName +#define getnetbyaddr GetNetByAddr +#define getservbyname GetServByName +#define getservbyport GetServByPort +#define getprotobyname GetProtoByName +#define getprotobynumber GetProtoByNumber +#define getdtablesize GetDTableSize +#define gethostname GetHostName +#define gethostid GetHostId +#define vsyslog SyslogA +#define syslog Syslog + +#define Accept TCP_Accept +#define Bind TCP_Bind +#define CloseSocket TCP_CloseSocket +#define Connect TCP_Connect +#define Dup2Socket TCP_Dup2Socket +#define Errno TCP_Errno +#define GetDTableSize TCP_GetDTableSize +#define GetHostByAddr TCP_GetHostByAddr +#define GetHostByName TCP_GetHostByName +#define GetHostId TCP_GetHostId +#define GetHostName TCP_GetHostName +#define GetNetByAddr TCP_GetNetByAddr +#define GetNetByName TCP_GetNetByName +#define GetPeerName TCP_GetPeerName +#define GetProtoByName TCP_GetProtoByName +#define GetProtoByNumber TCP_GetProtoByNumber +#define GetServByName TCP_GetServByName +#define GetServByPort TCP_GetServByPort +#define GetSockName TCP_GetSockName +#define GetSockOpt TCP_GetSockOpt +#define GetSocketEvents TCP_GetSocketEvents +#define Inet_Addr TCP_Inet_Addr +#define Inet_LnaOf TCP_Inet_LnaOf +#define Inet_MakeAddr TCP_Inet_MakeAddr +#define Inet_NetOf TCP_Inet_NetOf +#define Inet_Network TCP_Inet_Network +#define Inet_NtoA TCP_Inet_NtoA +#define IoctlSocket TCP_IoctlSocket +#define Listen TCP_Listen +#define ObtainSocket TCP_ObtainSocket +#define Recv TCP_Recv +#define RecvFrom TCP_RecvFrom +#define RecvMsg TCP_RecvMsg +#define ReleaseCopyOfSocket TCP_ReleaseCopyOfSocket +#define ReleaseSocket TCP_ReleaseSocket +#define Send TCP_Send +#define SendMsg TCP_SendMsg +#define SendTo TCP_SendTo +#define SetErrnoPtr TCP_SetErrnoPtr +#define SetSockOpt TCP_SetSockOpt +#define SetSocketSignals TCP_SetSocketSignals +#define ShutDown TCP_ShutDown +#define Socket TCP_Socket +#define SocketBaseTagList TCP_SocketBaseTagList +#define SocketBaseTags TCP_SocketBaseTags +#define SyslogA TCP_SyslogA +#define WaitSelect TCP_WaitSelect + +#endif diff --git a/include/inline/amitcp.h b/include/inline/amitcp.h new file mode 100644 index 0000000..5ea5e14 --- /dev/null +++ b/include/inline/amitcp.h @@ -0,0 +1,203 @@ +/* Automatically generated header! Do not edit! */ + +#ifndef _INLINE_AMITCP_H +#define _INLINE_AMITCP_H + +#ifndef __INLINE_MACROS_H +#include +#endif + +#ifndef AMITCP_BASE_NAME +#define AMITCP_BASE_NAME lss->lx_BsdSocketBase +#endif + +#define TCP_Accept(s, addr, addrlen) \ + LP3(0x30, LONG, TCP_Accept, LONG, s, d0, struct sockaddr *, addr, a0, int *, addrlen, a1, \ + , AMITCP_BASE_NAME) + +#define TCP_Bind(s, name, namelen) \ + LP3(0x24, LONG, TCP_Bind, LONG, s, d0, const struct sockaddr *, name, a0, LONG, namelen, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_CloseSocket(d) \ + LP1(0x78, LONG, TCP_CloseSocket, LONG, d, d0, \ + , AMITCP_BASE_NAME) + +#define TCP_Connect(s, name, namelen) \ + LP3(0x36, LONG, TCP_Connect, LONG, s, d0, const struct sockaddr *, name, a0, LONG, namelen, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_Dup2Socket(fd1, fd2) \ + LP2(0x108, LONG, TCP_Dup2Socket, LONG, fd1, d0, LONG, fd2, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_Errno() \ + LP0(0xa2, LONG, TCP_Errno, \ + , AMITCP_BASE_NAME) + +#define TCP_GetDTableSize() \ + LP0(0x8a, LONG, TCP_GetDTableSize, \ + , AMITCP_BASE_NAME) + +#define TCP_GetHostByAddr(addr, len, type) \ + LP3(0xd8, struct hostent *, TCP_GetHostByAddr, const UBYTE *, addr, a0, LONG, len, d0, LONG, type, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_GetHostByName(name) \ + LP1(0xd2, struct hostent *, TCP_GetHostByName, const UBYTE *, name, a0, \ + , AMITCP_BASE_NAME) + +#define TCP_GetHostId() \ + LP0(0x120, ULONG, TCP_GetHostId, \ + , AMITCP_BASE_NAME) + +#define TCP_GetHostName(hostname, size) \ + LP2(0x11a, LONG, TCP_GetHostName, STRPTR, hostname, a0, LONG, size, d0, \ + , AMITCP_BASE_NAME) + +#define TCP_GetNetByAddr(net, type) \ + LP2(0xe4, struct netent *, TCP_GetNetByAddr, LONG, net, d0, LONG, type, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_GetNetByName(name) \ + LP1(0xde, struct netent *, TCP_GetNetByName, const UBYTE *, name, a0, \ + , AMITCP_BASE_NAME) + +#define TCP_GetPeerName(s, hostname, namelen) \ + LP3(0x6c, LONG, TCP_GetPeerName, LONG, s, d0, struct sockaddr *, hostname, a0, int *, namelen, a1, \ + , AMITCP_BASE_NAME) + +#define TCP_GetProtoByName(name) \ + LP1(0xf6, struct protoent *, TCP_GetProtoByName, const UBYTE *, name, a0, \ + , AMITCP_BASE_NAME) + +#define TCP_GetProtoByNumber(proto) \ + LP1(0xfc, struct protoent *, TCP_GetProtoByNumber, LONG, proto, d0, \ + , AMITCP_BASE_NAME) + +#define TCP_GetServByName(name, proto) \ + LP2(0xea, struct servent *, TCP_GetServByName, const UBYTE *, name, a0, const UBYTE *, proto, a1, \ + , AMITCP_BASE_NAME) + +#define TCP_GetServByPort(port, proto) \ + LP2(0xf0, struct servent *, TCP_GetServByPort, LONG, port, d0, const UBYTE *, proto, a0, \ + , AMITCP_BASE_NAME) + +#define TCP_GetSockName(s, hostname, namelen) \ + LP3(0x66, LONG, TCP_GetSockName, LONG, s, d0, struct sockaddr *, hostname, a0, int *, namelen, a1, \ + , AMITCP_BASE_NAME) + +#define TCP_GetSockOpt(s, level, optname, optval, optlen) \ + LP5(0x60, LONG, TCP_GetSockOpt, LONG, s, d0, LONG, level, d1, LONG, optname, d2, void *, optval, a0, int *, optlen, a1, \ + , AMITCP_BASE_NAME) + +#define TCP_GetSocketEvents(eventmaskp) \ + LP1(0x12c, LONG, TCP_GetSocketEvents, ULONG *, eventmaskp, a0, \ + , AMITCP_BASE_NAME) + +#define TCP_Inet_Addr(cp) \ + LP1(0xb4, ULONG, TCP_Inet_Addr, const UBYTE *, cp, a0, \ + , AMITCP_BASE_NAME) + +#define TCP_Inet_LnaOf(in) \ + LP1(0xba, ULONG, TCP_Inet_LnaOf, LONG, in, d0, \ + , AMITCP_BASE_NAME) + +#define TCP_Inet_MakeAddr(net, host) \ + LP2(0xc6, ULONG, TCP_Inet_MakeAddr, ULONG, net, d0, ULONG, host, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_Inet_NetOf(in) \ + LP1(0xc0, ULONG, TCP_Inet_NetOf, LONG, in, d0, \ + , AMITCP_BASE_NAME) + +#define TCP_Inet_Network(cp) \ + LP1(0xcc, ULONG, TCP_Inet_Network, const UBYTE *, cp, a0, \ + , AMITCP_BASE_NAME) + +#define TCP_Inet_NtoA(in) \ + LP1(0xae, char *, TCP_Inet_NtoA, ULONG, in, d0, \ + , AMITCP_BASE_NAME) + +#define TCP_IoctlSocket(d, request, argp) \ + LP3(0x72, LONG, TCP_IoctlSocket, LONG, d, d0, ULONG, request, d1, char *, argp, a0, \ + , AMITCP_BASE_NAME) + +#define TCP_Listen(s, backlog) \ + LP2(0x2a, LONG, TCP_Listen, LONG, s, d0, LONG, backlog, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_ObtainSocket(id, domain, type, protocol) \ + LP4(0x90, LONG, TCP_ObtainSocket, LONG, id, d0, LONG, domain, d1, LONG, type, d2, LONG, protocol, d3, \ + , AMITCP_BASE_NAME) + +#define TCP_Recv(s, buf, len, flags) \ + LP4(0x4e, LONG, TCP_Recv, LONG, s, d0, UBYTE *, buf, a0, LONG, len, d1, LONG, flags, d2, \ + , AMITCP_BASE_NAME) + +#define TCP_RecvFrom(s, buf, len, flags, from, fromlen) \ + LP6(0x48, LONG, TCP_RecvFrom, LONG, s, d0, UBYTE *, buf, a0, LONG, len, d1, LONG, flags, d2, struct sockaddr *, from, a1, int *, fromlen, a2, \ + , AMITCP_BASE_NAME) + +#define TCP_RecvMsg(s, msg, flags) \ + LP3(0x114, LONG, TCP_RecvMsg, LONG, s, d0, struct msghdr *, msg, a0, LONG, flags, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_ReleaseCopyOfSocket(fd, id) \ + LP2(0x9c, LONG, TCP_ReleaseCopyOfSocket, LONG, fd, d0, LONG, id, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_ReleaseSocket(fd, id) \ + LP2(0x96, LONG, TCP_ReleaseSocket, LONG, fd, d0, LONG, id, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_Send(s, msg, len, flags) \ + LP4(0x42, LONG, TCP_Send, LONG, s, d0, const UBYTE *, msg, a0, LONG, len, d1, LONG, flags, d2, \ + , AMITCP_BASE_NAME) + +#define TCP_SendMsg(s, msg, flags) \ + LP3(0x10e, LONG, TCP_SendMsg, LONG, s, d0, const struct msghdr *, msg, a0, LONG, flags, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_SendTo(s, msg, len, flags, to, tolen) \ + LP6(0x3c, LONG, TCP_SendTo, LONG, s, d0, const UBYTE *, msg, a0, LONG, len, d1, LONG, flags, d2, const struct sockaddr *, to, a1, LONG, tolen, d3, \ + , AMITCP_BASE_NAME) + +#define TCP_SetErrnoPtr(errno_p, size) \ + LP2(0xa8, LONG, TCP_SetErrnoPtr, void *, errno_p, a0, LONG, size, d0, \ + , AMITCP_BASE_NAME) + +#define TCP_SetSockOpt(s, level, optname, optval, optlen) \ + LP5(0x5a, LONG, TCP_SetSockOpt, LONG, s, d0, LONG, level, d1, LONG, optname, d2, const void *, optval, a0, LONG, optlen, d3, \ + , AMITCP_BASE_NAME) + +#define TCP_SetSocketSignals(SIGINTR, SIGIO, SIGURG) \ + LP3NR(0x84, TCP_SetSocketSignals, ULONG, SIGINTR, d0, ULONG, SIGIO, d1, ULONG, SIGURG, d2, \ + , AMITCP_BASE_NAME) + +#define TCP_ShutDown(s, how) \ + LP2(0x54, LONG, TCP_ShutDown, LONG, s, d0, LONG, how, d1, \ + , AMITCP_BASE_NAME) + +#define TCP_Socket(domain, type, protocol) \ + LP3(0x1e, LONG, TCP_Socket, LONG, domain, d0, LONG, type, d1, LONG, protocol, d2, \ + , AMITCP_BASE_NAME) + +#define TCP_SocketBaseTagList(taglist) \ + LP1(0x126, LONG, TCP_SocketBaseTagList, struct TagItem *, taglist, a0, \ + , AMITCP_BASE_NAME) + +#ifndef NO_INLINE_STDARG +#define TCP_SocketBaseTags(tags...) \ + ({ULONG _tags[] = { tags }; TCP_SocketBaseTagList((struct TagItem *)_tags); }) +#endif + +#define TCP_SyslogA(level, format, ap) \ + LP3NR(0x102, TCP_SyslogA, ULONG, level, d0, const char *, format, a0, va_list, ap, a1, \ + , AMITCP_BASE_NAME) + +#define TCP_WaitSelect(nfds, readfds, writefds, execptfds, timeout, maskp) \ + LP6(0x7e, LONG, TCP_WaitSelect, LONG, nfds, d0, fd_set *, readfds, a0, fd_set *, writefds, a1, fd_set *, execptfds, a2, struct timeval *, timeout, a3, ULONG *, maskp, d1, \ + , AMITCP_BASE_NAME) + +#endif diff --git a/include/netdb.h b/include/netdb.h new file mode 100644 index 0000000..a97e718 --- /dev/null +++ b/include/netdb.h @@ -0,0 +1,231 @@ +/* + * $Id$ + * + * :ts=8 + * + * 'Roadshow' -- Amiga TCP/IP stack + * Copyright (c) 2001-2016 by Olaf Barthel. + * All Rights Reserved. + * + * Amiga specific TCP/IP 'C' header files; + * Freely Distributable + */ + +/* + * ++Copyright++ 1980, 1983, 1988, 1993 + * - + * Copyright (c) 1980, 1983, 1988, 1993 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +/* + * @(#)netdb.h 8.1 (Berkeley) 6/2/93 + * $NetBSD: netdb.h,v 1.8 1997/10/13 09:26:06 lukem Exp $ + */ + +#ifndef _NETDB_H +#define _NETDB_H + +/****************************************************************************/ + +#ifndef _SYS_NETINCLUDE_TYPES_H +#include "sys/netinclude_types.h" +#endif /* _SYS_NETINCLUDE_TYPES_H */ + +#ifndef _SYS_ERRNO_H +#include "sys/errno.h" +#endif /* _SYS_ERRNO_H */ + +#ifndef _NETINET_IN_H +#include "netinet/in.h" +#endif /* _NETINET_IN_H */ + +/****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/****************************************************************************/ + +#ifdef __GNUC__ + #ifdef __PPC__ + #pragma pack(2) + #endif +#elif defined(__VBCC__) + #pragma amiga-align +#endif + +/****************************************************************************/ + +/* This used to be in */ +#define MAXHOSTNAMELEN 256 /* max hostname size */ + +/* + * Structures returned by network data base library. All addresses are + * supplied in host order, and returned in network order (suitable for + * use in system calls). + */ +struct hostent +{ + __STRPTR h_name; /* official name of host */ + __STRPTR * h_aliases; /* alias list */ + __LONG h_addrtype; /* host address type */ + __LONG h_length; /* length of address */ + __BYTE ** h_addr_list; /* list of addresses from name server */ +#define h_addr h_addr_list[0] /* address, for backward compatiblity */ +}; + +/* + * Assumption here is that a network number + * fits in an unsigned long -- probably a poor one. + */ +struct netent +{ + __STRPTR n_name; /* official name of net */ + __STRPTR * n_aliases; /* alias list */ + __LONG n_addrtype; /* net address type */ + in_addr_t n_net; /* network # */ +}; + +struct servent +{ + __STRPTR s_name; /* official service name */ + __STRPTR * s_aliases; /* alias list */ + __LONG s_port; /* port # */ + __STRPTR s_proto; /* protocol to use */ +}; + +struct protoent +{ + __STRPTR p_name; /* official protocol name */ + __STRPTR * p_aliases; /* alias list */ + __LONG p_proto; /* protocol # */ +}; + +/* + * Error return codes from gethostbyname() and gethostbyaddr() + * (left in extern int h_errno). + */ + +#define NETDB_INTERNAL -1 /* see errno */ +#define NETDB_SUCCESS 0 /* no problem */ +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +/****************************************************************************/ + +/* Values for getaddrinfo() and getnameinfo() */ +#define AI_PASSIVE 1 /* socket address is intended for bind() */ +#define AI_CANONNAME 2 /* request for canonical name */ +#define AI_NUMERICHOST 4 /* don't ever try hostname lookup */ +#define AI_EXT 8 /* enable non-portable extensions */ +#define AI_NUMERICSERV 16 /* don't ever try servname lookup */ +/* valid flags for addrinfo */ +#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV) + +#define NI_NUMERICHOST 1 /* return the host address, not the name */ +#define NI_NUMERICSERV 2 /* return the service address, not the name */ +#define NI_NOFQDN 4 /* return a short name if in the local domain */ +#define NI_NAMEREQD 8 /* fail if either host or service name is unknown */ +#define NI_DGRAM 16 /* look up datagram service instead of stream */ +#define NI_WITHSCOPEID 32 /* KAME hack: attach scopeid to host portion */ + +#define NI_MAXHOST MAXHOSTNAMELEN /* max host name returned by getnameinfo */ +#define NI_MAXSERV 32 /* max serv. name length returned by getnameinfo */ + +#define EAI_BADFLAGS -1 /* invalid value for ai_flags */ +#define EAI_NONAME -2 /* name or service is not known */ +#define EAI_AGAIN -3 /* temporary failure in name resolution */ +#define EAI_FAIL -4 /* non-recoverable failure in name resolution */ +#define EAI_NODATA -5 /* no address associated with name */ +#define EAI_FAMILY -6 /* ai_family not supported */ +#define EAI_SOCKTYPE -7 /* ai_socktype not supported */ +#define EAI_SERVICE -8 /* service not supported for ai_socktype */ +#define EAI_ADDRFAMILY -9 /* address family for name not supported */ +#define EAI_MEMORY -10 /* memory allocation failure */ +#define EAI_SYSTEM -11 /* system error (code indicated in errno) */ +#define EAI_BADHINTS -12 /* invalid value for hints */ +#define EAI_PROTOCOL -13 /* resolved protocol is unknown */ + +struct addrinfo { + int ai_flags; /* input flags */ + int ai_family; /* protocol family for socket */ + int ai_socktype; /* socket type */ + int ai_protocol; /* protocol for socket */ + socklen_t ai_addrlen; /* length of socket-address */ + struct sockaddr *ai_addr; /* socket-address for socket */ + char *ai_canonname; /* canonical name for service location (iff req) */ + struct addrinfo *ai_next; /* pointer to next in list */ +}; + +/****************************************************************************/ + +#ifdef __GNUC__ + #ifdef __PPC__ + #pragma pack() + #endif +#elif defined(__VBCC__) + #pragma default-align +#endif + +/****************************************************************************/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/****************************************************************************/ + +#endif /* !_NETDB_H */ diff --git a/include/netinet/in.h b/include/netinet/in.h new file mode 100644 index 0000000..c5dd05d --- /dev/null +++ b/include/netinet/in.h @@ -0,0 +1,275 @@ +/* + * :ts=8 + * + * 'Roadshow' -- Amiga TCP/IP stack + * Copyright (c) 2001-2016 by Olaf Barthel. + * All Rights Reserved. + * + * Amiga specific TCP/IP 'C' header files; + * Freely Distributable + */ + +/* + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)in.h 8.3 (Berkeley) 1/3/94 + */ + +#ifndef _NETINET_IN_H +#define _NETINET_IN_H + +/****************************************************************************/ + +#ifndef _SYS_NETINCLUDE_TYPES_H +#include "sys/netinclude_types.h" +#endif /* _SYS_NETINCLUDE_TYPES_H */ + +#ifndef _SYS_SOCKET_H +#include "sys/socket.h" +#endif /* _SYS_SOCKET_H */ + +/****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/****************************************************************************/ + +#ifdef __GNUC__ + #ifdef __PPC__ + #pragma pack(2) + #endif +#elif defined(__VBCC__) + #pragma amiga-align +#endif + +/****************************************************************************/ + +/* + * Constants and structures defined by the internet system, + * Per RFC 790, September 1981, and numerous additions. + */ + +/* + * Data types. + */ +typedef unsigned long in_addr_t; +typedef unsigned short in_port_t; + +/* + * Protocols + */ +#define IPPROTO_IP 0 /* dummy for IP */ +#define IPPROTO_ICMP 1 /* control message protocol */ +#define IPPROTO_IGMP 2 /* group mgmt protocol */ +#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ +#define IPPROTO_TCP 6 /* tcp */ +#define IPPROTO_EGP 8 /* exterior gateway protocol */ +#define IPPROTO_PUP 12 /* pup */ +#define IPPROTO_UDP 17 /* user datagram protocol */ +#define IPPROTO_IDP 22 /* xns idp */ +#define IPPROTO_TP 29 /* tp-4 w/ class negotiation */ +#define IPPROTO_EON 80 /* ISO cnlp */ +#define IPPROTO_ENCAP 98 /* encapsulation header */ + +#define IPPROTO_RAW 255 /* raw IP packet */ +#define IPPROTO_MAX 256 + + +/* + * Local port number conventions: + * Ports < IPPORT_RESERVED are reserved for + * privileged processes (e.g. root). + * Ports > IPPORT_USERRESERVED are reserved + * for servers, not necessarily privileged. + */ +#define IPPORT_RESERVED 1024 +#define IPPORT_USERRESERVED 5000 + +/* + * Internet address (a structure for historical reasons) + */ +struct in_addr { + in_addr_t s_addr; +}; + +/* + * Definitions of bits in internet address integers. + * On subnets, the decomposition of addresses to host and net parts + * is done according to subnet mask, not the masks here. + */ +#define IN_CLASSA(i) (((__ULONG)(i) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST 0x00ffffff +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(i) (((__ULONG)(i) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST 0x0000ffff +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(i) (((__ULONG)(i) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST 0x000000ff + +#define IN_CLASSD(i) (((__ULONG)(i) & 0xf0000000) == 0xe0000000) +#define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */ +#define IN_CLASSD_NSHIFT 28 /* net and host fields, but */ +#define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */ +#define IN_MULTICAST(i) IN_CLASSD(i) + +#define IN_EXPERIMENTAL(i) (((__ULONG)(i) & 0xf0000000) == 0xf0000000) +#define IN_BADCLASS(i) (((__ULONG)(i) & 0xf0000000) == 0xf0000000) + +#define INADDR_ANY 0x00000000UL +#define INADDR_BROADCAST 0xffffffffUL /* must be masked */ +#define INADDR_NONE 0xffffffff /* -1 return */ + +#define INADDR_UNSPEC_GROUP 0xe0000000UL /* 224.0.0.0 */ +#define INADDR_ALLHOSTS_GROUP 0xe0000001UL /* 224.0.0.1 */ +#define INADDR_MAX_LOCAL_GROUP 0xe00000ffUL /* 224.0.0.255 */ + +#define IN_LOOPBACKNET 127 /* official! */ + +/* + * Socket address, internet style. + */ +struct sockaddr_in { + __UBYTE sin_len; + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + __UBYTE sin_zero[8]; +}; + +/* + * Structure used to describe IP options. + * Used to store options internally, to pass them to a process, + * or to restore options retrieved earlier. + * The ip_dst is used for the first-hop gateway when using a source route + * (this gets put into the header proper). + */ +struct ip_opts { + struct in_addr ip_dst; /* first hop, 0 w/o src rt */ + __UBYTE ip_options[40]; /* actually variable in size */ +}; + +/* + * Options for use with [gs]etsockopt at the IP level. + * First word of comment is data type; bool is stored in int. + */ +#define IP_OPTIONS 1 /* buf/ip_opts; set/get IP options */ +#define IP_HDRINCL 2 /* __LONG; header is included with data */ +#define IP_TOS 3 /* __LONG; IP type of service and preced. */ +#define IP_TTL 4 /* __LONG; IP time to live */ +#define IP_RECVOPTS 5 /* bool; receive all IP opts w/dgram */ +#define IP_RECVRETOPTS 6 /* bool; receive IP opts for response */ +#define IP_RECVDSTADDR 7 /* bool; receive IP dst addr w/dgram */ +#define IP_RETOPTS 8 /* ip_opts; set/get IP options */ +#define IP_MULTICAST_IF 9 /* __UBYTE; set/get IP multicast i/f */ +#define IP_MULTICAST_TTL 10 /* __UBYTE; set/get IP multicast ttl */ +#define IP_MULTICAST_LOOP 11 /* __UBYTE; set/get IP multicast loopback */ +#define IP_ADD_MEMBERSHIP 12 /* ip_mreq; add an IP group membership */ +#define IP_DROP_MEMBERSHIP 13 /* ip_mreq; drop an IP group membership */ + +/* + * Defaults and limits for options + */ +#define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */ +#define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ +#define IP_MAX_MEMBERSHIPS 20 /* per socket; must fit in one mbuf */ + +/* + * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP. + */ +struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +}; + +/* + * Definitions for inet sysctl operations. + * + * Third level is protocol number. + * Fourth level is desired variable within that protocol. + */ +#define IPPROTO_MAXID (IPPROTO_IDP + 1) /* don't list to IPPROTO_MAX */ + +/* + * Names for IP sysctl objects + */ +#define IPCTL_FORWARDING 1 /* act as router */ +#define IPCTL_SENDREDIRECTS 2 /* may send redirects when forwarding */ +#define IPCTL_DEFTTL 3 /* default TTL */ +#ifdef notyet +#define IPCTL_DEFMTU 4 /* default MTU */ +#endif +#define IPCTL_MAXID 5 + +/****************************************************************************/ + +/* + * Macros for network/external number representation conversion. + */ +#define ntohl(x) (x) +#define ntohs(x) (x) +#define htonl(x) (x) +#define htons(x) (x) + +#define NTOHL(x) (x) +#define NTOHS(x) (x) +#define HTONL(x) (x) +#define HTONS(x) (x) + +/****************************************************************************/ + +#ifdef __GNUC__ + #ifdef __PPC__ + #pragma pack() + #endif +#elif defined(__VBCC__) + #pragma default-align +#endif + +/****************************************************************************/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/****************************************************************************/ + +#endif /* _NETINET_IN_H */ diff --git a/include/sys/errno.h b/include/sys/errno.h new file mode 100644 index 0000000..f3bd297 --- /dev/null +++ b/include/sys/errno.h @@ -0,0 +1,189 @@ +/* + * :ts=8 + * + * 'Roadshow' -- Amiga TCP/IP stack + * Copyright (c) 2001-2016 by Olaf Barthel. + * All Rights Reserved. + * + * Amiga specific TCP/IP 'C' header files; + * Freely Distributable + */ + +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)errno.h 8.5 (Berkeley) 1/21/94 + */ + +#ifndef _SYS_ERRNO_H +#define _SYS_ERRNO_H + +/****************************************************************************/ + +/* NOTE: the global 'extern int errno;' declaration below may conflict with + what your 'C' runtime library uses for its own 'errno' declaration. + While you should not need to #include this header file, and use + your 'C' runtime library version instead, it is sometimes not + possible to do without the error codes defined in this file. If + this is the case, define the preprocessor symbol __NO_NETINCLUDE_ERRNO + before you include this header file. */ + +/****************************************************************************/ + +#ifndef __NO_NETINCLUDE_ERRNO +extern int errno; /* global error number */ +#endif /* __NO_NETINCLUDE_ERRNO */ + +/****************************************************************************/ + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* Input/output error */ +#define ENXIO 6 /* Device not configured */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file descriptor */ +#define ECHILD 10 /* No child processes */ +#define EDEADLK 11 /* Resource deadlock avoided */ + /* 11 was EAGAIN */ +#define ENOMEM 12 /* Cannot allocate memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#ifndef _POSIX_SOURCE +#define ENOTBLK 15 /* Block device required */ +#endif +#define EBUSY 16 /* Device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* Operation not supported by device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Inappropriate ioctl for device */ +#ifndef _POSIX_SOURCE +#define ETXTBSY 26 /* Text file busy */ +#endif +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ + +/* math software */ +#define EDOM 33 /* Numerical argument out of domain */ +#define ERANGE 34 /* Result too large */ + +/* non-blocking and interrupt i/o */ +#define EAGAIN 35 /* Resource temporarily unavailable */ +#ifndef _POSIX_SOURCE +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define EINPROGRESS 36 /* Operation now in progress */ +#define EALREADY 37 /* Operation already in progress */ + +/* ipc/network software -- argument errors */ +#define ENOTSOCK 38 /* Socket operation on non-socket */ +#define EDESTADDRREQ 39 /* Destination address required */ +#define EMSGSIZE 40 /* Message too long */ +#define EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 42 /* Protocol not available */ +#define EPROTONOSUPPORT 43 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define EOPNOTSUPP 45 /* Operation not supported */ +#define EPFNOSUPPORT 46 /* Protocol family not supported */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define EADDRINUSE 48 /* Address already in use */ +#define EADDRNOTAVAIL 49 /* Can't assign requested address */ + +/* ipc/network software -- operational errors */ +#define ENETDOWN 50 /* Network is down */ +#define ENETUNREACH 51 /* Network is unreachable */ +#define ENETRESET 52 /* Network dropped connection on reset */ +#define ECONNABORTED 53 /* Software caused connection abort */ +#define ECONNRESET 54 /* Connection reset by peer */ +#define ENOBUFS 55 /* No buffer space available */ +#define EISCONN 56 /* Socket is already connected */ +#define ENOTCONN 57 /* Socket is not connected */ +#define ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define ETOOMANYREFS 59 /* Too many references: can't splice */ +#define ETIMEDOUT 60 /* Operation timed out */ +#define ECONNREFUSED 61 /* Connection refused */ + +#define ELOOP 62 /* Too many levels of symbolic links */ +#endif /* _POSIX_SOURCE */ +#define ENAMETOOLONG 63 /* File name too long */ + +/* should be rearranged */ +#ifndef _POSIX_SOURCE +#define EHOSTDOWN 64 /* Host is down */ +#define EHOSTUNREACH 65 /* No route to host */ +#endif /* _POSIX_SOURCE */ +#define ENOTEMPTY 66 /* Directory not empty */ + +/* quotas & mush */ +#ifndef _POSIX_SOURCE +#define EPROCLIM 67 /* Too many processes */ +#define EUSERS 68 /* Too many users */ +#define EDQUOT 69 /* Disc quota exceeded */ + +/* Network File System */ +#define ESTALE 70 /* Stale NFS file handle */ +#define EREMOTE 71 /* Too many levels of remote in path */ +#define EBADRPC 72 /* RPC struct is bad */ +#define ERPCMISMATCH 73 /* RPC version wrong */ +#define EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define EPROGMISMATCH 75 /* Program version wrong */ +#define EPROCUNAVAIL 76 /* Bad procedure for program */ +#endif /* _POSIX_SOURCE */ + +#define ENOLCK 77 /* No locks available */ +#define ENOSYS 78 /* Function not implemented */ + +#ifndef _POSIX_SOURCE +#define EFTYPE 79 /* Inappropriate file type or format */ +#define EAUTH 80 /* Authentication error */ +#define ENEEDAUTH 81 /* Need authenticator */ +#define ELAST 81 /* Must be equal largest errno */ +#endif /* _POSIX_SOURCE */ + +/****************************************************************************/ + +#endif /* _SYS_ERRNO_H */ diff --git a/include/sys/netinclude_types.h b/include/sys/netinclude_types.h new file mode 100644 index 0000000..c148481 --- /dev/null +++ b/include/sys/netinclude_types.h @@ -0,0 +1,64 @@ +/* + * :ts=8 + * + * 'Roadshow' -- Amiga TCP/IP stack + * Copyright (c) 2001-2016 by Olaf Barthel. + * All Rights Reserved. + * + * Amiga specific TCP/IP 'C' header files; + * Freely Distributable + */ + +#ifndef _SYS_NETINCLUDE_TYPES_H +#define _SYS_NETINCLUDE_TYPES_H + +/****************************************************************************/ + +/* The type definitions below mirror those in , which may + clash with local type definitions. Hence, replacements are used which + are rather unlikely to cause similar conflicts. Note that the definition + of the __TEXT and __STRPTR types currently support only SAS/C and the + GNU 'C' compiler. */ + +/****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************/ + +typedef long __LONG; /* signed 32-bit quantity */ +typedef unsigned long __ULONG; /* unsigned 32-bit quantity */ +typedef short __WORD; /* signed 16-bit quantity */ +typedef unsigned short __UWORD; /* unsigned 16-bit quantity */ +typedef signed char __BYTE; /* signed 8-bit quantity */ +typedef unsigned char __UBYTE; /* unsigned 8-bit quantity */ + +/****************************************************************************/ + +typedef void * __APTR; /* 32-bit untyped pointer */ + +/****************************************************************************/ + +#if (defined(__GNUC__) && defined(__CHAR_UNSIGNED__)) || (defined(__SASC) && defined(_UNSCHAR)) +typedef char * __STRPTR; /* string pointer (NULL terminated) */ +#else +typedef unsigned char * __STRPTR; /* string pointer (NULL terminated) */ +#endif + +#if (defined(__GNUC__) && defined(__CHAR_UNSIGNED__)) || (defined(__SASC) && defined(_UNSCHAR)) +typedef char __TEXT; /* Non-negative character */ +#else +typedef unsigned char __TEXT; /* Non-negative character */ +#endif + +/****************************************************************************/ + +#ifdef __cplusplus +} +#endif + +/****************************************************************************/ + +#endif /* !_SYS_NETINCLUDE_TYPES_H */ diff --git a/include/sys/socket.h b/include/sys/socket.h new file mode 100644 index 0000000..7d093c2 --- /dev/null +++ b/include/sys/socket.h @@ -0,0 +1,421 @@ +/* + * :ts=8 + * + * 'Roadshow' -- Amiga TCP/IP stack + * Copyright (c) 2001-2016 by Olaf Barthel. + * All Rights Reserved. + * + * Amiga specific TCP/IP 'C' header files; + * Freely Distributable + */ + +/* + * Copyright (c) 1982, 1985, 1986, 1988, 1993, 1994 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)socket.h 8.6 (Berkeley) 5/3/95 + */ + +#ifndef _SYS_SOCKET_H +#define _SYS_SOCKET_H + +/****************************************************************************/ + +/* NOTE: the 'struct timeval' structure definition differs slightly between + the AmigaOS usage (as defined in ) and the POSIX + usage (as defined in . By default, this header file + will include under the assumption that there + will be no problem as a result of that. However, if there are + compilation issues, you might want to define the 'struct timeval' + separately and disable the inclusion of , + which can be achieved by defining the preprocessor symbol + __NO_NETINCLUDE_TIMEVAL before you include this header file. */ + +/****************************************************************************/ + +#ifndef _SYS_NETINCLUDE_TYPES_H +#include +#endif /* _SYS_NETINCLUDE_TYPES_H */ + +/****************************************************************************/ + +/* + * We might reference memmove() and memset() below, which is why + * we need to make sure that both are declared somewhere. + */ +#include +#include +#include + +/****************************************************************************/ + +/* 'struct iovec', as used in a 'struct msghdr' is defined in . */ +#ifndef _SYS_UIO_H +#include +#endif /* _SYS_UIO_H */ + +/****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/****************************************************************************/ + +#ifdef __GNUC__ + #ifdef __PPC__ + #pragma pack(2) + #endif +#elif defined(__VBCC__) + #pragma amiga-align +#endif + +/****************************************************************************/ + +/* + * Definitions related to sockets: types, address families, options. + */ + +/* + * Data types. + */ +typedef unsigned char sa_family_t; +typedef unsigned long socklen_t; + +/* + * Types + */ +#define SOCK_STREAM 1 /* stream socket */ +#define SOCK_DGRAM 2 /* datagram socket */ +#define SOCK_RAW 3 /* raw-protocol interface */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequenced packet stream */ + +/* + * Option flags per-socket. + */ +#define SO_DEBUG 0x0001 /* turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */ +#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */ + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF 0x1001 /* send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ + +/* This is a private option which is used exclusively + * by this Amiga TCP/IP stack implementation and should not + * be used by user code. + */ +#define SO_EVENTMASK 0x2001 + +/* + * Structure used for manipulating linger option. + */ +struct linger { + __LONG l_onoff; /* option on/off */ + __LONG l_linger; /* linger time in seconds */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define SOL_SOCKET 0xffff /* options for socket level */ + +/* + * Address families. + */ +#define AF_UNSPEC 0 /* unspecified */ +#define AF_LOCAL 1 /* local to host (pipes, portals) */ +#define AF_UNIX AF_LOCAL /* backward compatibility */ +#define AF_INET 2 /* internetwork: UDP, TCP, etc. */ +#define AF_IMPLINK 3 /* arpanet imp addresses */ +#define AF_PUP 4 /* pup protocols: e.g. BSP */ +#define AF_CHAOS 5 /* mit CHAOS protocols */ +#define AF_NS 6 /* XEROX NS protocols */ +#define AF_ISO 7 /* ISO protocols */ +#define AF_OSI AF_ISO +#define AF_ECMA 8 /* european computer manufacturers */ +#define AF_DATAKIT 9 /* datakit protocols */ +#define AF_CCITT 10 /* CCITT protocols, X.25 etc */ +#define AF_SNA 11 /* IBM SNA */ +#define AF_DECnet 12 /* DECnet */ +#define AF_DLI 13 /* DEC Direct data link interface */ +#define AF_LAT 14 /* LAT */ +#define AF_HYLINK 15 /* NSC Hyperchannel */ +#define AF_APPLETALK 16 /* Apple Talk */ +#define AF_ROUTE 17 /* Internal Routing Protocol */ +#define AF_LINK 18 /* Link layer interface */ +#define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */ +#define AF_COIP 20 /* connection-oriented IP, aka ST II */ +#define AF_CNT 21 /* Computer Network Technology */ +#define pseudo_AF_RTIP 22 /* Help Identify RTIP packets */ +#define AF_IPX 23 /* Novell Internet Protocol */ +#define AF_SIP 24 /* Simple Internet Protocol */ +#define pseudo_AF_PIP 25 /* Help Identify PIP packets */ + +#define AF_MAX 26 + +/* + * Structure used by kernel to store most + * addresses. + */ +struct sockaddr { + __UBYTE sa_len; /* total length */ + sa_family_t sa_family; /* address family */ + __UBYTE sa_data[14]; /* actually longer; address value */ +}; + +/* + * Structure used by kernel to pass protocol + * information in raw sockets. + */ +struct sockproto { + __UWORD sp_family; /* address family */ + __UWORD sp_protocol; /* protocol */ +}; + +/* + * Protocol families, same as address families for now. + */ +#define PF_UNSPEC AF_UNSPEC +#define PF_LOCAL AF_LOCAL +#define PF_UNIX PF_LOCAL /* backward compatibility */ +#define PF_INET AF_INET +#define PF_IMPLINK AF_IMPLINK +#define PF_PUP AF_PUP +#define PF_CHAOS AF_CHAOS +#define PF_NS AF_NS +#define PF_ISO AF_ISO +#define PF_OSI AF_ISO +#define PF_ECMA AF_ECMA +#define PF_DATAKIT AF_DATAKIT +#define PF_CCITT AF_CCITT +#define PF_SNA AF_SNA +#define PF_DECnet AF_DECnet +#define PF_DLI AF_DLI +#define PF_LAT AF_LAT +#define PF_HYLINK AF_HYLINK +#define PF_APPLETALK AF_APPLETALK +#define PF_ROUTE AF_ROUTE +#define PF_LINK AF_LINK +#define PF_XTP pseudo_AF_XTP /* really just proto family, no AF */ +#define PF_COIP AF_COIP +#define PF_CNT AF_CNT +#define PF_SIP AF_SIP +#define PF_IPX AF_IPX /* same format as AF_NS */ +#define PF_RTIP pseudo_AF_FTIP /* same format as AF_INET */ +#define PF_PIP pseudo_AF_PIP + +#define PF_MAX AF_MAX + +/* + * Definitions for network related sysctl, CTL_NET. + * + * Second level is protocol family. + * Third level is protocol number. + * + * Further levels are defined by the individual families below. + */ +#define NET_MAXID AF_MAX + +/* + * PF_ROUTE - Routing table + * + * Three additional levels are defined: + * Fourth: address family, 0 is wildcard + * Fifth: type of info, defined below + * Sixth: flag(s) to mask with for NET_RT_FLAGS + */ +#define NET_RT_DUMP 1 /* dump; may limit to a.f. */ +#define NET_RT_FLAGS 2 /* by flags, e.g. RESOLVING */ +#define NET_RT_IFLIST 3 /* survey interface list */ +#define NET_RT_MAXID 4 + +/* + * Maximum queue length specifiable by listen. + */ +#define SOMAXCONN 5 + +/* + * Message header for recvmsg and sendmsg calls. + * Used value-result for recvmsg, value only for sendmsg. + */ +struct msghdr { + __APTR msg_name; /* optional address */ + socklen_t msg_namelen; /* size of address */ + struct iovec * msg_iov; /* scatter/gather array */ + __ULONG msg_iovlen; /* # elements in msg_iov */ + __APTR msg_control; /* ancillary data, see below */ + socklen_t msg_controllen; /* ancillary data buffer len */ + __LONG msg_flags; /* flags on received message */ +}; + +#define MSG_OOB 0x1 /* process out-of-band data */ +#define MSG_PEEK 0x2 /* peek at incoming message */ +#define MSG_DONTROUTE 0x4 /* send without using routing tables */ +#define MSG_EOR 0x8 /* data completes record */ +#define MSG_TRUNC 0x10 /* data discarded before delivery */ +#define MSG_CTRUNC 0x20 /* control data lost before delivery */ +#define MSG_WAITALL 0x40 /* wait for full request or error */ +#define MSG_DONTWAIT 0x80 /* this message should be nonblocking */ + +/* + * Header for ancillary data objects in msg_control buffer. + * Used for additional information with/about a datagram + * not expressible by flags. The format is a sequence + * of message elements headed by cmsghdr structures. + */ +struct cmsghdr { + socklen_t cmsg_len; /* data byte count, including hdr */ + __LONG cmsg_level; /* originating protocol */ + __LONG cmsg_type; /* protocol-specific type */ +/* followed by __UBYTE cmsg_data[]; */ +}; + +/* given pointer to struct cmsghdr, return pointer to data */ +#define CMSG_DATA(cmsg) ((__UBYTE *)((cmsg) + 1)) + +/* given pointer to struct cmsghdr, return pointer to next cmsghdr */ +#define CMSG_NXTHDR(mhdr, cmsg) \ + (((__APTR)(cmsg) + (cmsg)->cmsg_len + sizeof(struct cmsghdr) > \ + (mhdr)->msg_control + (mhdr)->msg_controllen) ? \ + (struct cmsghdr *)NULL : \ + (struct cmsghdr *)((__APTR)(cmsg) + ALIGN((cmsg)->cmsg_len))) + +#define CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control) + +/* "Socket"-level control message types: */ +#define SCM_RIGHTS 0x01 /* access rights (array of __LONG) */ + +/* + * The following comes from the original header file, + * which has been retired in favour of the + * type definitions. What remains are the macros in support of the + * "select()" call and those for endian-neutral operations. + */ + +/****************************************************************************/ + +/* + * In case the select() data structures and macros are already + * defined by somebody else... + */ + +#ifndef FD_SET + +#define NBBY 8 /* number of bits in a byte */ + +/* + * Select uses bit masks of file descriptors in longs. These macros + * manipulate such bit fields (the filesystem macros use chars). + * FD_SETSIZE may be defined by the user, but the default here should + * be enough for most uses. + */ +#ifndef FD_SETSIZE +#define FD_SETSIZE 256 +#endif + +typedef unsigned long fd_mask; +#define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ + +#ifndef howmany +#define howmany(x, y) (((x) + ((y) - 1)) / (y)) +#endif + +typedef struct fd_set { + fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; +} fd_set; + +#define FD_SET(n, p) ((void)(((unsigned long)n) < FD_SETSIZE ? (p)->fds_bits[((unsigned long)n)/NFDBITS] |= (1 << (((unsigned long)n) % NFDBITS)) : 0)) +#define FD_CLR(n, p) ((void)(((unsigned long)n) < FD_SETSIZE ? (p)->fds_bits[((unsigned long)n)/NFDBITS] &= ~(1 << (((unsigned long)n) % NFDBITS)) : 0)) +#define FD_ISSET(n, p) (((unsigned long)n) < FD_SETSIZE && ((p)->fds_bits[((unsigned long)n)/NFDBITS] & (1 << (((unsigned long)n) % NFDBITS)))) +#define FD_COPY(f, t) ((void)memmove((t), (f), sizeof(*(f)))) +#define FD_ZERO(p) ((void)memset((p), 0, sizeof(*(p)))) + +#endif /* FD_SET */ + +/****************************************************************************/ + +#ifdef __GNUC__ + #ifdef __PPC__ + #pragma pack() + #endif +#elif defined(__VBCC__) + #pragma default-align +#endif + +/****************************************************************************/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/****************************************************************************/ + +#ifndef __NO_NETINCLUDE_TIMEVAL + +/* + * This is for compatibility with POSIX-like 'timeval' structures + * which are remarkably similar to the Amiga 'timeval' except for + * the structure member names... + */ +#ifndef DEVICES_TIMER_H +#include +#endif /* DEVICES_TIMER_H */ + +#ifndef tv_sec +#define tv_sec tv_secs +#endif /* tv_sec */ + +#ifndef tv_usec +#define tv_usec tv_micro +#endif /* tv_usec */ + +#endif /* __NO_NETINCLUDE_TIMEVAL */ + +/****************************************************************************/ + +#endif /* !_SYS_SOCKET_H_ */ diff --git a/library.c b/library.c new file mode 100644 index 0000000..39264f8 --- /dev/null +++ b/library.c @@ -0,0 +1,341 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" +#include "time.h" +#include "mem.h" + +/* Library identifiers */ +static const char *dosName = "dos.library"; +static const char *aslName = "asl.library"; +static const char *iconName = "icon.library"; +static const char *commoditiesName = "commodities.library"; +static const char *localeName = "locale.library"; +static const char *utilityName = "utility.library"; +static const char *gadgetName = "gadtools.library"; +static const char *intuitionName = "intuition.library"; +static const char *mathName = "mathieeedoubbas.library"; + +#if !defined(LIB_HOST) +/* Use fake bases */ +#define DOSBase __FX_DOSBase +#define LocaleBase __FX_LocaleBase +#define UtilityBase __FX_UtilityBase +#define IntuitionBase __FX_IntuitionBase +#define CxBase __FX_CxBase +#define AslBase __FX_AslBase +#define IconBase __FX_IconBase +#define GadToolsBase __FX_GadToolsBase +#define __MathIeeeDoubBasBase __FX__MathIeeeDoubBasBase +#define __UtilityBase __FX__UtilityBase +#endif + +/* Library addresses */ +//struct ExecBase *SysBase = (struct ExecBase *)4L; +struct DosLibrary *DOSBase = NULL; +struct LocaleBase *LocaleBase = NULL; +struct UtilityBase *UtilityBase = NULL; +struct IntuitionBase *IntuitionBase = NULL; +struct Library *CxBase = NULL; +struct Library *AslBase = NULL; +struct Library *IconBase = NULL; +struct Library *GadToolsBase = NULL; +struct Library *__MathIeeeDoubBasBase = NULL; +struct UtilityBase *__UtilityBase = NULL; + +#define DOSLIB_NAME ((STRPTR)dosName) +#define DOSLIB_REV 36L +#define ASLLIB_NAME ((STRPTR)aslName) +#define ASLLIB_REV 37L +#define ICONLIB_NAME ((STRPTR)iconName) +#define ICONLIB_REV 36L +#define COMMODLIB_NAME ((STRPTR)commoditiesName) +#define COMMODLIB_REV 37L +#define INTUITIONLIB_NAME ((STRPTR)intuitionName) +#define INTUITIONLIB_REV 37L +#define LOCALELIB_NAME ((STRPTR)localeName) +#define LOCALELIB_REV 37L +#define UTILLIB_NAME ((STRPTR)utilityName) +#define UTILLIB_REV 37L +#define GADGETLIB_NAME ((STRPTR)gadgetName) +#define GADGETLIB_REV 37L +#define MATHLIB_NAME ((STRPTR)mathName) +#define MATHLIB_REV 34L + +// RTC Clock +static const char *batteryClockName = "battclock.resource"; +#define BATTCLOCK_NAME ((STRPTR)batteryClockName) +struct Library *BattClockBase = NULL; + +static struct Device *TimerDevice = NULL; +static const char *currentLocale = "Current Locale"; + +static void OpenLibrarySuccess(STRPTR name) +{ + LogTrace("Opened %s", name); +} + +static void OpenLibraryError(STRPTR name, long version) +{ + LogError("Cannot open %s %ld.0", name, version); +} + +static void ClosingLibrary(STRPTR name) +{ + LogTrace("Closing %s", name); +} + +static void OpenResourceSuccess(const char *name) +{ + LogTrace("Opened %s", name); +} + +static void OpenResourceError(const char *name) +{ + LogError("Cannot open %s", name); +} + +static void ClosingResource(const char *name) +{ + LogTrace("Closing %s", name); +} + +int OpenLibraries(void) +{ + // DOS Library + if (!(DOSBase = (struct DosLibrary *)OpenLibrary((STRPTR)DOSLIB_NAME, DOSLIB_REV))) + { + OpenLibraryError(DOSLIB_NAME, DOSLIB_REV); + return LIB_ERROR; + } + +#ifdef AOS3 + // Library does not always provide IdString + OpenResourceSuccess(DOSLIB_NAME); +#else + OpenLibrarySuccess(((struct Library *)DOSBase)->lib_IdString); +#endif + + // Math Library + if (!(__MathIeeeDoubBasBase = OpenLibrary((STRPTR)MATHLIB_NAME, MATHLIB_REV))) + { + OpenLibraryError(MATHLIB_NAME, MATHLIB_REV); + return LIB_ERROR; + } + +#ifdef AOS3 + // Library does not always provide IdString + OpenResourceSuccess(MATHLIB_NAME); +#else + OpenLibrarySuccess(((struct Library *)__MathIeeeDoubBasBase)->lib_IdString); +#endif + + // Commodities Library + if (!(CxBase = OpenLibrary((STRPTR)COMMODLIB_NAME, COMMODLIB_REV))) + { + OpenLibraryError(COMMODLIB_NAME, COMMODLIB_REV); + return LIB_ERROR; + } + + OpenLibrarySuccess(CxBase->lib_IdString); + + // Intuition Library + if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary((STRPTR)INTUITIONLIB_NAME, INTUITIONLIB_REV))) + { + OpenLibraryError(INTUITIONLIB_NAME, INTUITIONLIB_REV); + return LIB_ERROR; + } + + OpenLibrarySuccess(((struct Library *)IntuitionBase)->lib_IdString); + + // Icon Library + if (!(IconBase = OpenLibrary((STRPTR)ICONLIB_NAME, ICONLIB_REV))) + { + OpenLibraryError(ICONLIB_NAME, ICONLIB_REV); + return LIB_ERROR; + } + + OpenLibrarySuccess(IconBase->lib_IdString); + + // Icon Library + if (!(AslBase = OpenLibrary((STRPTR)ASLLIB_NAME, ASLLIB_REV))) + { + OpenLibraryError(ASLLIB_NAME, ASLLIB_REV); + return LIB_ERROR; + } + + OpenLibrarySuccess(AslBase->lib_IdString); + + // Locale Library + if (!(LocaleBase = (struct LocaleBase *)OpenLibrary((STRPTR)LOCALELIB_NAME, LOCALELIB_REV))) + { + OpenLibraryError(LOCALELIB_NAME, LOCALELIB_REV); + return LIB_ERROR; + } + + OpenLibrarySuccess(((struct Library *)LocaleBase)->lib_IdString); + + // Utility Library + if (!(UtilityBase = (struct UtilityBase *)OpenLibrary((STRPTR)UTILLIB_NAME, UTILLIB_REV))) + { + OpenLibraryError(UTILLIB_NAME, UTILLIB_REV); + return LIB_ERROR; + } + + __UtilityBase = UtilityBase; + OpenLibrarySuccess(((struct Library *)UtilityBase)->lib_IdString); + + // Gadget Library + if (!(GadToolsBase = OpenLibrary((STRPTR)GADGETLIB_NAME, GADGETLIB_REV))) + { + OpenLibraryError(GADGETLIB_NAME, GADGETLIB_REV); + return LIB_ERROR; + } + + OpenLibrarySuccess(GadToolsBase->lib_IdString); + + // Locale + if (!(Globals->Locale = OpenLocale(NULL))) + { + OpenResourceError(currentLocale); + return LIB_ERROR; + } + + OpenResourceSuccess((const char *)Globals->Locale->loc_LocaleName); + + // RTC Clock + if (!(BattClockBase = OpenResource((STRPTR)BATTCLOCK_NAME))) + { + OpenResourceError((const char *)BATTCLOCK_NAME); + return LIB_ERROR; + } + + OpenResourceSuccess((const char *)BATTCLOCK_NAME); + + // Timer Device + if (!(TimerDevice = OpenTimerBase())) + { + OpenResourceError(TIMERNAME); + return LIB_ERROR; + } + + OpenResourceSuccess(TIMERNAME); + + InitUtcOffset(); + + return LIB_OK; +} + +void CloseLibraries(void) +{ + if (TimerDevice != NULL) + { + ClosingResource((const char *)TIMERNAME); + CloseTimerBase(); + TimerDevice = NULL; + } + + if (Globals->Locale != NULL) + { + ClosingResource((const char *)Globals->Locale->loc_LocaleName); + CloseLocale(Globals->Locale); + Globals->Locale = NULL; + } + + if (CxBase != NULL) + { + ClosingLibrary(CxBase->lib_IdString); + CloseLibrary(CxBase); + CxBase = NULL; + } + + if (AslBase != NULL) + { + ClosingLibrary(AslBase->lib_IdString); + CloseLibrary(AslBase); + AslBase = NULL; + } + + if (IconBase != NULL) + { + ClosingLibrary(IconBase->lib_IdString); + CloseLibrary(IconBase); + IconBase = NULL; + } + + if (LocaleBase != NULL) + { + ClosingLibrary(((struct Library *)LocaleBase)->lib_IdString); + CloseLibrary((struct Library *)LocaleBase); + LocaleBase = NULL; + } + + if (UtilityBase != NULL) + { + ClosingLibrary(((struct Library *)UtilityBase)->lib_IdString); + CloseLibrary((struct Library *)UtilityBase); + UtilityBase = NULL; + __UtilityBase = NULL; + } + + if (GadToolsBase != NULL) + { + ClosingLibrary(GadToolsBase->lib_IdString); + CloseLibrary(GadToolsBase); + GadToolsBase = NULL; + } + + if (IntuitionBase != NULL) + { + ClosingLibrary(((struct Library *)IntuitionBase)->lib_IdString); + CloseLibrary((struct Library *)IntuitionBase); + IntuitionBase = NULL; + } + + if (DOSBase != NULL) + { +#ifdef AOS3 + // Library does not always provide IdString + ClosingResource(DOSLIB_NAME); +#else + ClosingLibrary(((struct Library *)DOSBase)->lib_IdString); +#endif + CloseLibrary((struct Library *)DOSBase); + DOSBase = NULL; + } + + if (__MathIeeeDoubBasBase != NULL) + { +#ifdef AOS3 + // Library does not always provide IdString + ClosingResource(MATHLIB_NAME); +#else + ClosingLibrary(((struct Library *)__MathIeeeDoubBasBase)->lib_IdString); +#endif + CloseLibrary((struct Library *)__MathIeeeDoubBasBase); + __MathIeeeDoubBasBase = NULL; + } +} diff --git a/log.c b/log.c new file mode 100644 index 0000000..51b63f5 --- /dev/null +++ b/log.c @@ -0,0 +1,247 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" +#include "log.h" +#include "mem.h" +#include + +#define MAXLOGLINESIZE 255 + +enum LogSeverity +{ + ErrorMessage = 5, + WarningMessage = 10, + InfoMessage = 20, + TraceMessage = 30 +}; + +struct LogEntry +{ + enum LogSeverity level; + char *line; + struct LogEntry *next; +}; + +static bool logDisabled = false; +static bool bufferLog = false; +static BPTR logFile = NULL; +static struct LogEntry *firstEntry = NULL; +static struct LogEntry *lastEntry = NULL; + +void OpenLogFile(void) +{ + BPTR lock; + bool deleteFirst = false; + + if (Globals->Settings->LogFile == NULL) + { + return; + } + + lock = Lock((STRPTR)Globals->Settings->LogFile, ACCESS_READ); + if (lock) + { + deleteFirst = true; + UnLock(lock); + } + + if (deleteFirst) + { + bool success; + LogWarning("Deleting existing log file %s", Globals->Settings->LogFile); + success = DeleteFile((STRPTR)Globals->Settings->LogFile); + if (!success) + { + char message[MAXDOSERRORLEN]; + long error = IoErr(); + Fault(error, (STRPTR) "Cannot delete existing log file %s", (STRPTR)message, MAXDOSERRORLEN); + LogWarning(message); + logFile = NULL; + return; + } + } + + LogInfo("Opening log file %s", Globals->Settings->LogFile); + logFile = Open((STRPTR)Globals->Settings->LogFile, MODE_READWRITE); + if (!logFile) + { + char message[MAXDOSERRORLEN]; + long error = IoErr(); + Fault(error, (STRPTR) "Cannot open log file %s", (STRPTR)message, MAXDOSERRORLEN); + LogWarning(message); + logFile = NULL; + return; + } +} + +void CloseLogFile(void) +{ + if (logFile == NULL) + { + return; + } + + LogTrace("Closing log file %s", Globals->Settings->LogFile); + Close(logFile); + logFile = NULL; + logDisabled = true; +} + +bool TraceLogging(void) +{ + return Globals->Settings->Verbose * 10 >= (int)TraceMessage + ? true + : false; +} + +static void VLogLine(enum LogSeverity level, const char *format, va_list ap) +{ + struct LogEntry *entry; + char line[MAXLOGLINESIZE + 1]; + + if (logDisabled) + { + return; + } + + if (bufferLog || Globals->Settings->Verbose * 10 >= (int)level) + { + int len; + VSNPrintf(line, MAXLOGLINESIZE - 1, format, ap); + len = TrimRight(line); + if (len != 0) + { + line[len++] = '\n'; + line[len] = '\0'; + } + } + + if (bufferLog) + { + entry = (struct LogEntry *)AllocMemSafe(sizeof(struct LogEntry)); + entry->level = level; + entry->line = StrDupSafe(line); + entry->next = NULL; + + if (firstEntry == NULL) + { + firstEntry = entry; + lastEntry = entry; + } + else + { + lastEntry->next = entry; + lastEntry = entry; + } + return; + } + + if (Globals->Settings->Verbose * 10 >= (int)level) + { + if (logFile != NULL) + { + FPuts(logFile, (STRPTR)line); + Flush(logFile); + } + else + { + Printf((STRPTR)line); + } + } +} + +void LogTrace(const char *format, ...) +{ + va_list args; + va_start(args, format); + VLogLine(TraceMessage, format, args); + va_end(args); +} + +void LogInfo(const char *format, ...) +{ + va_list args; + va_start(args, format); + VLogLine(InfoMessage, format, args); + va_end(args); +} + +void LogWarning(const char *format, ...) +{ + va_list args; + va_start(args, format); + VLogLine(WarningMessage, format, args); + va_end(args); +} + +void LogError(const char *format, ...) +{ + va_list args; + va_start(args, format); + VLogLine(ErrorMessage, format, args); + va_end(args); +} + +void SetLogBuffer(void) +{ + bufferLog = true; +} + +void FlushLogBuffer(void) +{ + struct LogEntry *current; + + if (!bufferLog) + return; + + current = firstEntry; + while (current != NULL) + { + struct LogEntry *last; + if (Globals->Settings->Verbose * 10 >= (int)current->level) + { + if (logFile != NULL) + { + FPuts(logFile, (STRPTR)current->line); + } + else + { + Printf((STRPTR)current->line); + } + } + + last = current; + current = current->next; + + FreeMemSafe(last->line); + FreeMemSafe(last); + } + + bufferLog = false; + firstEntry = NULL; + lastEntry = NULL; +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..a404c5e --- /dev/null +++ b/log.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 LOG_H_INCLUDED +#define LOG_H_INCLUDED + +#include "compiler.h" + +void LogTrace(const char *format, ...); +void LogInfo(const char *format, ...); +void LogWarning(const char *format, ...); +void LogError(const char *format, ...); +bool TraceLogging(void); +void OpenLogFile(void); +void CloseLogFile(void); +void SetLogBuffer(void); +void FlushLogBuffer(void); + +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..4a0bcdf --- /dev/null +++ b/main.c @@ -0,0 +1,154 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" +#include "state.h" +#include "time.h" +#include "mem.h" + +#include + +const char *vers = "\0$VER: " APP_ID; +static const char *template = KEYWORD_TEMPLATE; + +static void LogStartMessage(void); +static void LogLocalTime(void); +static void GetCliSettings(void); +static void GetWbSettings(struct WBStartup *); + +int main(int argc, char **argv) +{ + InitState(); + SetLogBuffer(); + LogStartMessage(); + LogLocalTime(); + + if (OpenLibraries() != 0) + return RETURN_ERROR; + + LoadSettings(); + + if (argc != 0) + GetCliSettings(); + else + GetWbSettings((struct WBStartup *)argv); + + ApplySettings(); + SanitizeSettings(); + ShowSettings(); + OpenLogFile(); + FlushLogBuffer(); + + StartBroker(); + + LogLocalTime(); + CloseSocketLibrary(); + CloseLibraries(); + CloseLogFile(); + DestroyState(); + FreeAllSafe(); + + return RETURN_OK; +} + +static void GetCliSettings(void) +{ + struct AppSettings *settings; + struct RDArgs *inArgs; + long args[KEYWORD_COUNT]; + int i; + + for (i = 0; i < KEYWORD_COUNT; i++) + args[i] = 0; + + settings = CreateSettings(CliSettingType); + settings->Verbose = 1; + + inArgs = ReadArgs((void *)template, (void *)&args, NULL); + if (inArgs) + { + // Keyword order in template needs to match order in settingFunctions + for (i = 0; i < KEYWORD_COUNT; i++) + { + if (args[i] != 0) + { + settingFunctions[i].Function(settings, (void *)args[i]); + } + } + FreeArgs(inArgs); + } + + CacheSettings(settings); +} + +static void GetWbSettings(struct WBStartup *wbs) +{ + struct AppSettings *settings; + struct DiskObject *diskObject; + STRPTR filename, arg; + BPTR oldDir; + int argNo, i; + + filename = (STRPTR)AllocMemSafe(MAXFILEPATHLEN); + settings = CreateSettings(WbSettingType); + + for (argNo = 0; argNo < wbs->sm_NumArgs; ++argNo) + { + if (wbs->sm_ArgList[argNo].wa_Lock != NULL) + { + oldDir = CurrentDir(wbs->sm_ArgList[argNo].wa_Lock); + diskObject = GetDiskObjectNew((void *)wbs->sm_ArgList[argNo].wa_Name); + if (diskObject) + { + for (i = 0; i < KEYWORD_COUNT; i++) + { + arg = FindToolType(diskObject->do_ToolTypes, (STRPTR)settingFunctions[i].Name); + if (arg) + { + settingFunctions[i].Function(settings, (char *)arg); + } + } + FreeDiskObject(diskObject); + } + CurrentDir(oldDir); + } + } + + CacheSettings(settings); + FreeMemSafe(filename); +} + +static void LogStartMessage(void) +{ + LogWarning("%s", APP_TITLE); +} + +static void LogLocalTime(void) +{ + char timeString[10], dateString[10], dayString[10]; + SystemTimeString(timeString, dateString, dayString); + LogWarning("Local time is %s %s %s", dayString, dateString, timeString); +} diff --git a/mem.c b/mem.c new file mode 100644 index 0000000..33c77c2 --- /dev/null +++ b/mem.c @@ -0,0 +1,297 @@ +/*- + * Copyright (c) 2014-2018 Carsten Sonne 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 +#define ALLOC_MEM(x) AllocVec(x, MEMF_ANY | MEMF_CLEAR) +#define FREE_MEM(x) FreeVec(x) + +#include "compiler.h" +#include "log.h" +int StrLen(const char *); + +#if defined(__x86_64__) || defined(__aarch64__) || \ + defined(_M_AMD64) || defined(_M_ARM64) || \ + defined(__powerpc64__) +#define P64BIT +#endif + +#ifdef DEBUG_BUILD +#define MEM_TRACE 1 +#endif + +/** + * @brief Block of allocated memory. + */ +struct MemoryBlock +{ + struct MemoryBlock *next; + size_t size; + void *address; +}; + +/** + * @brief List of allocated memory. Uses the LIFO principle. + */ +struct MemoryList +{ + struct MemoryBlock *first; + size_t peak; + size_t size; + long count; +}; + +/** + * @brief Global list of allocated memory. + */ +static struct MemoryList *list = NULL; + +void AllocationError(char *, size_t); +void DeAllocationError(char *, void *); + +/** + * @brief Allocate memory and add it to the global memory list. + */ +void *AllocMemSafe(size_t size) +{ + struct MemoryBlock *newblock; + size_t allocsize; + + Forbid(); + if (list == NULL) + { + list = (struct MemoryList *)ALLOC_MEM(sizeof(struct MemoryList)); + if (!list) + { + AllocationError("list", sizeof(struct MemoryList)); + return 0; + } + + list->first = NULL; + list->peak = 0; + list->size = 0; + list->count = 0; + } + +#ifdef P64BIT + // Align to bytes of 8 + allocsize = (size + 7) & ~0x07; +#else + // Align to bytes of 4 + allocsize = (size + 3) & ~0x03; +#endif + + newblock = (struct MemoryBlock *)ALLOC_MEM(sizeof(struct MemoryBlock)); + if (!newblock) + { + AllocationError("block", sizeof(struct MemoryBlock)); + return 0; + } + + newblock->address = (struct MemoryBlock *)ALLOC_MEM(allocsize); + if (!newblock->address) + { + FREE_MEM(newblock); + AllocationError("memory", allocsize); + return 0; + } + + newblock->size = allocsize; + newblock->next = list->first; + list->first = newblock; + list->size += allocsize; + list->count++; + + if (list->size > list->peak) + { + list->peak = list->size; + } + Permit(); + +#ifdef MEM_TRACE + Printf("Allocated memory block off %ld bytes at 0x%lx\n", + newblock->size, newblock->address); +#endif + + // Memory allocated + return newblock->address; +} + +void RemoveMemSafe(void *block, bool deallocate) +{ + struct MemoryBlock *current, *previous; + + Forbid(); + if (list == NULL || block == NULL) + { + DeAllocationError("list", 0); + return; + } + + if (block == NULL) + { + DeAllocationError("memory", 0); + return; + } + + previous = NULL; + current = list->first; + while (current != NULL && current->address != block) + { + previous = current; + current = current->next; + } + + if (current == NULL) + { + DeAllocationError("address not found", block); + return; + } + + if (previous == NULL) + { + list->first = current->next; + } + else + { + previous->next = current->next; + } + + list->size -= current->size; + list->count--; + + if (deallocate) + { + FREE_MEM(current->address); + } + + current->address = NULL; + current->next = NULL; + current->size = 0; + FREE_MEM(current); + Permit(); +} + +/** + * @brief Deallocate memory from the global memory list. + */ +void FreeMemSafe(void *block) +{ + RemoveMemSafe(block, true); +} + +void *MemDupSafe(const void *s1, size_t len) +{ + char *dup; + dup = AllocMemSafe(len); + CopyMem((void *)s1, dup, len); + return dup; +} + +char *StrDupSafe(const char *s1) +{ + char *s2; + size_t len = s1 != NULL ? StrLen(s1) : 1; + s2 = AllocMemSafe(++len); + + if (s2 == NULL) + { + return NULL; + } + + CopyMem((void *)s1, s2, --len); + return s2; +} + +/** + * @brief Deallocate all memory in the global memory list. + */ +void FreeAllSafe(void) +{ + struct MemoryBlock *current, *next; + + Forbid(); + if (list == NULL) + { + return; + } + + current = list->first; + while (current != NULL) + { + LogTrace("Released forgotten memory block on %ld bytes at 0x%lx", + (long)current->size, + (unsigned long)current->address); + next = current->next; + FREE_MEM(current->address); + FREE_MEM(current); + current = next; + } + + FREE_MEM(list); + list = NULL; + Permit(); +} + +/** + * @brief Get memory usage in the global memory list. + */ +void MemUsage(long *blocks, long *size, long *peak) +{ + if (blocks != NULL) + { + *blocks = list->count; + } + + if (size != NULL) + { + *size = (long)list->size; + } + + if (peak != NULL) + { + *peak = (long)list->peak; + } +} + +/** + * @brief Log a memory allocation error. + */ +void AllocationError(char *descr, size_t size) +{ + LogTrace("Memory allocation error (%s) with size (%ld)", descr, (long)size); +} + +/** + * @brief Log a memory deallocation error. + */ +void DeAllocationError(char *descr, void *p) +{ + LogTrace("Memory deallocation error (%s) at 0x%lx", descr, p); +} diff --git a/mem.h b/mem.h new file mode 100644 index 0000000..3770d79 --- /dev/null +++ b/mem.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2014-2018 Carsten Sonne 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 MEM_H_INCLUDED +#define MEM_H_INCLUDED + +#include + +void *AllocMemSafe(size_t); +char *StrDupSafe(const char *); +void *MemDupSafe(const void *s1, size_t len); +void FreeMemSafe(void *); +void FreeAllSafe(void); +void MemUsage(long *, long *, long *); + +#endif diff --git a/message.c b/message.c new file mode 100644 index 0000000..9241437 --- /dev/null +++ b/message.c @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" +#include "message.h" +#include "mem.h" + +static void SendTextMessage(char *text, long type) +{ + Forbid(); + if (!Globals->ShuttingDown) + { + struct AppWindowMessage *message = (struct AppWindowMessage *)AllocMemSafe(sizeof(struct AppWindowMessage)); + message->Msg.mn_Node.ln_Type = NT_MESSAGE; + message->Msg.mn_Length = sizeof(struct AppWindowMessage); + message->Msg.mn_ReplyPort = Globals->Broker->ReplyPort; + message->Type = type; + message->Text = StrDupSafe(text); + PutMsg(Globals->Broker->UserPort, (struct Message *)message); + } + Permit(); +} + +void SendErrorMessage(char *text) +{ + SendTextMessage(text, ATK_LOGERROR); +} + +void SendWarningMessage(char *text) +{ + SendTextMessage(text, ATK_LOGWARN); +} + +void SendInfoMessage(char *text) +{ + SendTextMessage(text, ATK_LOGINFO); +} + +void SendTraceMessage(char *text) +{ + SendTextMessage(text, ATK_LOGTRACE); +} + +void SendMessage(long type) +{ + Forbid(); + if (!Globals->ShuttingDown) + { + struct AppWindowMessage *message = (struct AppWindowMessage *)AllocMemSafe(sizeof(struct AppWindowMessage)); + message->Msg.mn_Node.ln_Type = NT_MESSAGE; + message->Msg.mn_Length = sizeof(struct AppWindowMessage); + message->Msg.mn_ReplyPort = Globals->Broker->ReplyPort; + message->Type = type; + message->Text = NULL; + PutMsg(Globals->Broker->UserPort, (struct Message *)message); + } + Permit(); +} + +void SendMessageTo(struct MsgPort *dest, struct MsgPort *reply, long type) +{ + Forbid(); + if (!Globals->ShuttingDown) + { + struct AppWindowMessage *message = (struct AppWindowMessage *)AllocMemSafe(sizeof(struct AppWindowMessage)); + message->Msg.mn_Node.ln_Type = NT_MESSAGE; + message->Msg.mn_Length = sizeof(struct AppWindowMessage); + message->Msg.mn_ReplyPort = reply; + message->Type = type; + message->Text = NULL; + PutMsg(dest, (struct Message *)message); + } + Permit(); +} diff --git a/message.h b/message.h new file mode 100644 index 0000000..3fa976e --- /dev/null +++ b/message.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 MESSAGE_H_INCLUDED +#define MESSAGE_H_INCLUDED + +#include "config.h" + +#define ATK_LOGERROR 1 +#define ATK_LOGWARN 2 +#define ATK_LOGINFO 3 +#define ATK_LOGTRACE 4 +#define ATK_RESTART 10 +#define ATK_REFRESH 11 +#define ATK_STORE 13 +#define ATK_APPLY 14 +#define ATK_UNDO 15 +#define ATK_ENABLE 20 +#define ATK_DISABLE 21 +#define ATK_READONLY 22 +#define ATK_READWRITE 23 + +struct AppWindowMessage +{ + struct Message Msg; + long Type; + char *Text; +}; + +void SendMessage(long); +void SendErrorMessage(char *); +void SendWarningMessage(char *); +void SendInfoMessage(char *); +void SendTraceMessage(char *); +void SendMessageTo(struct MsgPort *, struct MsgPort *, long); + +#endif diff --git a/net.c b/net.c new file mode 100644 index 0000000..a5970fc --- /dev/null +++ b/net.c @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" +#include "net_getaddrinfo.h" +#include "message.h" + +int errno; +int gai_h_errno; + +#ifdef AOS3 +int h_errno; +#endif + +static const char *bsdSocketName = "bsdsocket.library"; +static const char *openSocketLibraryError = "Cannot open %s %ld.0"; +static const char *openSocketResourceError = "Cannot open %s"; +struct Library *SocketBase = NULL; + +#define BSDLIB_NAME ((STRPTR)bsdSocketName) +#define BSDLIB_REV 03L + +int OpenSocketLibrary(void) +{ + char message[SETTINGMESSAGELEN]; + + if (SocketBase != NULL) + { + return LIB_OK; + } + + if (!(SocketBase = OpenLibrary((STRPTR)BSDLIB_NAME, BSDLIB_REV))) + { + SNPrintf(message, SETTINGMESSAGELEN, openSocketLibraryError, BSDLIB_NAME, BSDLIB_REV); + SendErrorMessage(message); + return LIB_ERROR; + } + + SNPrintf(message, SETTINGMESSAGELEN, "Opened %s", (char *)SocketBase->lib_IdString); + SendTraceMessage(message); + + if (SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (int)&errno, + SBTM_SETVAL(SBTC_HERRNOLONGPTR), (int)&h_errno, TAG_DONE)) + { + SNPrintf(message, SETTINGMESSAGELEN, openSocketResourceError, BSDLIB_NAME); + SendErrorMessage(message); + CloseLibrary(SocketBase); + return LIB_ERROR; + } + + return LIB_OK; +} + +void CloseSocketLibrary(void) +{ + if (SocketBase != NULL) + { + char message[SETTINGMESSAGELEN]; + SNPrintf(message, SETTINGMESSAGELEN, "Closing %s", (char *)SocketBase->lib_IdString); + SendTraceMessage(message); + CloseLibrary(SocketBase); + SocketBase = NULL; + } +} + +const char *GetErrorText(void) +{ + switch (errno) + { + case ENOTSOCK: + return "Socket operation on non-socket"; + case EDESTADDRREQ: + return "Destination address required"; + case EMSGSIZE: + return "Message too long"; + case EPROTOTYPE: + return "Protocol wrong type for socket"; + case ENOPROTOOPT: + return "Protocol not available"; + case EPROTONOSUPPORT: + return "Protocol not supported"; + case ESOCKTNOSUPPORT: + return "Socket type not supported"; + case EOPNOTSUPP: + return "Operation not supported"; + case EPFNOSUPPORT: + return "Protocol family not supported"; + case EAFNOSUPPORT: + return "Address family not supported by protocol family"; + case EADDRINUSE: + return "Address already in use"; + case EADDRNOTAVAIL: + return "Can't assign requested address"; + case ENETDOWN: + return "Network is down"; + case ENETUNREACH: + return "Network is unreachable"; + case ENETRESET: + return "Network dropped connection on reset"; + case ECONNABORTED: + return "Software caused connection abort"; + case ECONNRESET: + return "Connection reset by peer"; + case ENOBUFS: + return "No buffer space available"; + case EISCONN: + return "Socket is already connected"; + case ENOTCONN: + return "Socket is not connected"; + case ESHUTDOWN: + return "Can't send after socket shutdown"; + case ETIMEDOUT: + return "Operation timed out"; + case ECONNREFUSED: + return "Connection refused"; + case EHOSTDOWN: + return "Host is down"; + case EHOSTUNREACH: + return "No route to host"; + default: + return "Socket error"; + } +} + +const char *GetHostErrorText(void) +{ + if (gai_h_errno != 0) + { + return gai_h_errno == EAI_SYSTEM + ? GetErrorText() + : gai_strerror(gai_h_errno); + } + + switch (h_errno) + { + case EAI_BADFLAGS: + return "Invalid value for ai_flags"; + case EAI_NONAME: + return "Name or service is not known"; + case EAI_AGAIN: + return "Temporary failure in name resolution"; + case EAI_FAIL: + return "Non-recoverable failure in name resolution"; + case EAI_FAMILY: + return "ai_family not supported"; + case EAI_SOCKTYPE: + return "ai_socktype not supported"; + case EAI_SERVICE: + return "Service not supported for ai_socktype"; + case EAI_ADDRFAMILY: + return "Address family for name not supported"; + case EAI_MEMORY: + return "Memory allocation failure"; + case EAI_SYSTEM: + return GetErrorText(); + default: + return "DNS error"; + } +} diff --git a/net_getaddrinfo.c b/net_getaddrinfo.c new file mode 100644 index 0000000..147cc16 --- /dev/null +++ b/net_getaddrinfo.c @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2001, 02 Motoyuki Kasahara + * Copyright (c) 2017-2018 Carsten Sonne Larsen + * + * 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 also provides freeaddrinfo() and gai_strerror(). + * + * Restriction: + * getaddrinfo() and getnameinfo() of this program are NOT thread + * safe, unless the cpp macro ENABLE_THREAD is defined. + */ + +#include "config.h" +#include "net_getaddrinfo.h" +#include "mem.h" + +#define gettext(string) (string) +#define _(string) (string) +#define N_(string) (string) + +extern int gai_h_errno; + +#ifdef AOS3 +extern int h_errno; +#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_THREAD +struct SignalSemaphore getaddrinfoSemaphore; +#endif + +/* + * gai_strerror(). + */ +#if defined(__CLIB2__) +STRPTR gai_strerror(LONG ecode) +#else +const char *gai_strerror(int ecode) +#endif +{ + if (ecode < 0 || ecode > EAI_SYSTEM) + return _("Unknown error"); + + return gettext(eai_errlist[ecode]); +} + +/* + * freeaddrinfo(). + */ +void freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *next_ai; + + while (ai != NULL) + { + if (ai->ai_canonname != NULL) + FreeMemSafe(ai->ai_canonname); + if (ai->ai_addr != NULL) + FreeMemSafe(ai->ai_addr); + next_ai = ai->ai_next; + FreeMemSafe(ai); + ai = next_ai; + } +} + +/* + * Return 1 if the string `s' represents an integer. + */ +static int is_integer(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(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; +} + +/* + * getaddrinfo(). + */ +#if defined(__CLIB2__) +LONG getaddrinfo( + STRPTR nodename, + STRPTR servname, + struct addrinfo *hints, + struct addrinfo **res) +#else +int getaddrinfo( + const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res) +#endif +{ + 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; + LONG port_parse; + int saved_h_errno; + int result = 0; + +#ifdef ENABLE_THREAD + ObtainSemaphore(&getaddrinfoSemaphore); +#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)) + { + StrToLong((STRPTR)servname, &port_parse); + port = htons(port_parse); + } + 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 *)AllocMemSafe(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 *) + AllocMemSafe(sizeof(struct sockaddr_in)); + if (new_res->ai_addr == NULL) + { + FreeMemSafe(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 *)AllocMemSafe(StrLen(canonname) + 1); + if (head_res->ai_canonname != NULL) + StrCopy(head_res->ai_canonname, canonname); + } + + *res = head_res; + +end: + h_errno = saved_h_errno; + gai_h_errno = result; +#ifdef ENABLE_THREAD + ReleaseSemaphore(&getaddrinfoSemaphore); +#endif + return result; +} + +#if 0 +/* + * Calcurate length of the string `s', where `s' is set by + * sprintf(s, "%d", n). + */ +static int +itoa_length(int n) +{ + int result = 1; + + if (n < 0) + { + n = -n; + result++; + } + + while (n >= 10) + { + result++; + n /= 10; + } + + return result; +} + +#if defined(__CLIB2__) +LONG getnameinfo( + struct sockaddr *sa, + ULONG salen, + STRPTR node, + ULONG nodelen, + STRPTR serv, + ULONG servlen, + ULONG flags) +#else +int getnameinfo( + const struct sockaddr *sa, + socklen_t salen, + char *node, + socklen_t nodelen, + char *serv, + socklen_t servlen, + int flags) +#endif +{ + 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; + } + StrCopy(serv, servent->s_name); + } + else + { + if (servlen <= itoa_length(ntohs(sa_in->sin_port))) + { + result = EAI_OVERFLOW; + goto end; + } + LongToStr((long)ntohs(sa_in->sin_port), serv); + } + } + + 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; + } + StrCopy(node, hostent->h_name); + } + else + { + if (flags & NI_NAMEREQD) + { + result = EAI_NONAME; + goto end; + } +#ifndef __libnix__ + ntoa_address = inet_ntoa(sa_in->sin_addr); +#else + ntoa_address = inet_ntoa((LONG)sa_in->sin_addr.s_addr); +#endif + if (nodelen <= StrLen(ntoa_address)) + { + result = EAI_OVERFLOW; + goto end; + } + StrCopy(node, ntoa_address); + } + } + +end: + h_errno = saved_h_errno; + gai_h_errno = result; +#ifdef ENABLE_PTHREAD + pthread_mutex_unlock(&gai_mutex); +#endif + return result; +} +#endif diff --git a/net_getaddrinfo.h b/net_getaddrinfo.h new file mode 100644 index 0000000..526f85e --- /dev/null +++ b/net_getaddrinfo.h @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2001, 02 Motoyuki Kasahara + * Copyright (c) 2017-2018 Carsten Sonne Larsen + * + * 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_INCLUDED +#define GETADDRINFO_H_INCLUDED + +#include "config.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 + +/* + * Undefine Roadshow macros. + */ +#ifdef gai_strerror +#undef gai_strerror +#endif +#ifdef freeaddrinfo +#undef freeaddrinfo +#endif +#ifdef getaddrinfo +#undef getaddrinfo +#endif +#ifdef getnameinfo +#undef 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 service 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 + +#if defined(AROS) +typedef uint16_t in_port_t; +#endif + +#if defined(__CLIB2__) +STRPTR gai_strerror(LONG); +LONG getaddrinfo(STRPTR, STRPTR, struct addrinfo *, struct addrinfo **); +LONG getnameinfo(struct sockaddr *, ULONG, STRPTR, ULONG, STRPTR, ULONG, ULONG); +#else +const char *gai_strerror(int); +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 + +void freeaddrinfo(struct addrinfo *); + +#endif diff --git a/net_poll.c b/net_poll.c new file mode 100644 index 0000000..5b80bac --- /dev/null +++ b/net_poll.c @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" + +#if !defined(HAVE_POLL) +#if defined(__CLIB2__) +#include +#endif + +int poll(struct pollfd *fds, nfds_t nfds, int timeout) +{ + unsigned int i; + int maxfds = -1, ret; + fd_set readSet, writeSet, errorSet; + struct timeval timeout_tv, *tvp = NULL; + + if (timeout >= 0) + { + timeout_tv.tv_secs = (timeout / 1000); + timeout_tv.tv_micro = (timeout % 1000) * 1000; + tvp = &timeout_tv; + } + + FD_ZERO(&readSet); + FD_ZERO(&writeSet); + FD_ZERO(&errorSet); + + for (i = 0; i < nfds; i++) + { + fds[i].revents = 0; + + if (fds[i].events == 0) + continue; + + if (fds[i].fd > maxfds) + maxfds = fds[i].fd; + + if (fds[i].events & POLLIN) + FD_SET(fds[i].fd, &readSet); + } + + ret = WaitSelect(maxfds + 1, &readSet, &writeSet, &errorSet, tvp, NULL); + + if (ret == -1) + return ret; + + for (i = 0; i < nfds; i++) + { + if (fds[i].events == 0) + continue; + + if (FD_ISSET(fds[i].fd, &readSet)) + fds[i].revents |= POLLIN; + } + + return ret; +} +#endif \ No newline at end of file diff --git a/sntp.c b/sntp.c new file mode 100644 index 0000000..0b54c42 --- /dev/null +++ b/sntp.c @@ -0,0 +1,466 @@ +/*- + * Copyright (c) 2007 TANDBERG Telecom AS + * Copyright (c) 2008-2009 Dag-Erling Smørgrav + * Copyright (c) 2017-2018 Carsten Sonne 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 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 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. + * + */ + +#include "config.h" +#include "time.h" +#include "sntp.h" +#include "mem.h" +#include "net_getaddrinfo.h" +#include "message.h" + +/* + * Convert a struct timeval to an NTP timestamp + */ +void tv2nt(struct timeval *tv, struct ntptime *nt) +{ + uint64_t frac; + + nt->sec = tv->tv_secs + UNIX_EPOCH; + frac = tv->tv_micro; + frac <<= 32; + frac /= 1000 * 1000; + nt->frac = frac; +} + +/* + * Convert an NTP timestamp to a struct timeval + */ +void nt2tv(struct ntptime *nt, struct timeval *tv) +{ + uint64_t frac; + + tv->tv_sec = nt->sec - UNIX_EPOCH; + frac = nt->frac; + frac *= 1000 * 1000; + frac >>= 32; + tv->tv_usec = frac; +} + +/* + * Convert struct ntptime in-place from network to host order + */ +void n2h_ntp(struct ntptime *nt) +{ + nt->sec = ntohl(nt->sec); + nt->frac = ntohl(nt->frac); +} + +/* + * Convert struct ntptime in-place from host to network order + */ +void h2n_ntp(struct ntptime *nt) +{ + nt->sec = htonl(nt->sec); + nt->frac = htonl(nt->frac); +} + +/* + * SNTP client state + */ +struct sntp +{ + /* parameters from sntp_create() */ + char *srcaddr; + char *srcport; + char *dstaddr; + char *dstport; + + /* DNS data */ + int family; + int socktype; + int protocol; + struct sockaddr *laddr; + socklen_t laddrlen; + struct sockaddr *raddr; + socklen_t raddrlen; + + /* socket and poll structure */ + int sd; + struct pollfd pfd; + + /* protocol state */ + struct ntptime last_send; + struct ntptime last_recv; +}; + +/* + * Initialize an SNTP client context + * + * Multiple contexts can coexist as long as they do not use the same + * source port. + * + * NOTICE: Consider adding support for binding to a specific source address. + */ +struct sntp * +sntp_create(const char *dstaddr, const char *dstport, + const char *srcaddr, const char *srcport) +{ + struct sntp *sntp; + sntp = AllocMemSafe(sizeof(struct sntp)); + sntp->sd = -1; + + sntp->srcaddr = srcaddr ? StrDupSafe(srcaddr) : NULL; + sntp->srcport = StrDupSafe(srcport ? srcport : "123"); + sntp->dstaddr = StrDupSafe(dstaddr); + sntp->dstport = StrDupSafe(dstport ? dstport : "123"); + + /* good to go */ + return (sntp); +} + +/* + * Look up local and remote addresses and set up the socket + */ +int sntp_open(struct sntp *sntp) +{ + struct addrinfo hints; + struct addrinfo *aiv, *ai; + int ret; + + if (sntp->sd != -1) + return (SNTP_OK); + + /* resolve the server address */ + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + if ((ret = getaddrinfo(sntp->dstaddr, sntp->dstport, &hints, &aiv)) != 0) + return (SNTP_DNSERR); + + /* Something went wrong */ + if (aiv == NULL) + return (SNTP_SYSERR); + + /* + * Iterate over the results until we find one we can use. This is + * sometimes necessary on systems with partial IPv6 support, where + * the resolver may return IPv6 addresses which the network stack + * can't handle. + */ + for (ai = aiv; ai; ai = ai->ai_next) + { + sntp->sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sntp->sd >= 0) + break; + } + + if (sntp->sd == -1) + { + SendWarningMessage("Could not get socket descriptor"); + freeaddrinfo(aiv); + return (SNTP_SYSERR); + } + + sntp->raddr = MemDupSafe(ai->ai_addr, ai->ai_addrlen); + sntp->raddrlen = ai->ai_addrlen; + sntp->family = ai->ai_family; + sntp->socktype = ai->ai_socktype; + sntp->protocol = ai->ai_protocol; + freeaddrinfo(aiv); + + /* get a matching local address */ + memset(&hints, 0, sizeof hints); + hints.ai_family = sntp->family; + hints.ai_socktype = sntp->socktype; + hints.ai_protocol = sntp->protocol; + hints.ai_flags = AI_PASSIVE; + if ((ret = getaddrinfo(sntp->srcaddr, sntp->srcport, &hints, &aiv)) != 0) + { + sntp_close(sntp); + return (SNTP_DNSERR); + } + + /* Something went wrong */ + if (aiv == NULL) + return (SNTP_SYSERR); + + /* NOTICE: Consider asserting that results match expectations */ + sntp->laddr = MemDupSafe(aiv->ai_addr, aiv->ai_addrlen); + sntp->laddrlen = aiv->ai_addrlen; + freeaddrinfo(aiv); + + /* prepare our socket */ + /* NOTICE: Sometimes AmigaOS do not like bindings. Just leave it for now. + if (bind(sntp->sd, sntp->laddr, sntp->laddrlen) != 0) { + LogError("Could not bind socket"); + sntp_close(sntp); + return (SNTP_SYSERR); + } + */ + + if (connect(sntp->sd, sntp->raddr, sntp->raddrlen) != 0) + { + SendWarningMessage("Could not connect socket"); + sntp_close(sntp); + return (SNTP_SYSERR); + } + + /* prepare our pollfd */ + sntp->pfd.fd = sntp->sd; + sntp->pfd.events = POLLIN; + sntp->pfd.revents = 0; + + return (SNTP_OK); +} + +/* + * Destroy an SNTP client context + * + * This is called several times during error handling in other parts of + * the code, so we should save and restore errno + */ +void sntp_close(struct sntp *sntp) +{ + int serrno; + + serrno = errno; + + sntp->family = 0; + sntp->socktype = 0; + sntp->protocol = 0; + + if (sntp->laddr) + FreeMemSafe(sntp->laddr); + sntp->laddrlen = 0; + + if (sntp->raddr) + FreeMemSafe(sntp->raddr); + sntp->raddrlen = 0; + + if (sntp->sd != -1) + CloseSocket(sntp->sd); + memset(&sntp->pfd, 0, sizeof sntp->pfd); + + nt_zero(sntp->last_send); + nt_zero(sntp->last_recv); + + errno = serrno; +} + +/* + * Destroy an SNTP client context + */ +void sntp_destroy(struct sntp *sntp) +{ + (void)sntp_close(sntp); + + if (sntp->srcaddr) + FreeMemSafe(sntp->srcaddr); + sntp->srcaddr = 0; + + if (sntp->srcport) + FreeMemSafe(sntp->srcport); + sntp->srcport = 0; + + if (sntp->dstaddr) + FreeMemSafe(sntp->dstaddr); + sntp->dstaddr = 0; + + if (sntp->dstport) + FreeMemSafe(sntp->dstport); + sntp->dstport = 0; + + FreeMemSafe(sntp); +} + +/* + * Structure of an NTP message without authenticator + */ +struct ntp_msg +{ + uint8_t flags; + uint8_t stratum; + uint8_t poll; + uint8_t precision; + uint32_t root_delay; + uint32_t root_dispersion; + uint8_t reference_id[4]; + struct ntptime reference; + struct ntptime originate; + struct ntptime receive; + struct ntptime transmit; +}; + +/* + * Send an SNTP request + */ +sntp_err_t +sntp_send(struct sntp *sntp) +{ + struct timeval tv; + struct ntp_msg msg; + ssize_t ret; + sntp_err_t se; + + if ((se = sntp_open(sntp)) != SNTP_OK) + return (se); + + memset(&msg, 0, sizeof msg); + msg.flags = 0x23; /* version 4, client */ + + GetTimeOfDay(&tv); + tv2nt(&tv, &msg.transmit); + + h2n_ntp(&msg.transmit); + ret = send(sntp->sd, (void *)&msg, sizeof(struct ntp_msg), 0); + + if (ret < 0) + return (SNTP_SYSERR); + + tv2nt(&tv, &sntp->last_send); + + return (SNTP_OK); +} + +/* + * Have we sent a request to which we're still expecting a response? + */ +sntp_err_t +sntp_pending(struct sntp *sntp) +{ + + /* not currently open */ + if (sntp->sd == -1) + return (SNTP_NOREQ); + + /* last request predates last response */ + if (nt_lt(sntp->last_send, sntp->last_recv)) + return (SNTP_NOREQ); + + return (SNTP_OK); +} + +/* + * Poll for the arrival of an SNTP reply + */ +sntp_err_t +sntp_poll(struct sntp *sntp, int timeout) +{ + sntp_err_t se; + + if ((se = sntp_pending(sntp)) != SNTP_OK) + return (se); + + switch (poll(&sntp->pfd, 1, timeout)) + { + case -1: + sntp_close(sntp); + return (SNTP_SYSERR); + case 0: + return (SNTP_NORESP); + case 1: + return (SNTP_OK); + } + + return 0; +} + +/* + * Receive and process an SNTP reply + */ +sntp_err_t +sntp_recv(struct sntp *sntp, struct ntptime *nt) +{ + struct timeval tv; + struct ntp_msg msg; + sntp_err_t se; + int res; + + if ((se = sntp_pending(sntp)) != SNTP_OK) + return (se); + + /* NOTICE: Consider using recvmsg() instead */ + res = recv(sntp->sd, (void *)&msg, sizeof(struct ntp_msg), MSG_DONTWAIT); + switch (res) + { + case -1: + if (errno == EAGAIN) + return (SNTP_NORESP); + sntp_close(sntp); + return (SNTP_SYSERR); + case 0: + /* can this actually occur? */ + return (SNTP_NORESP); + case sizeof msg: + /* good! */ + break; + default: + /* we got something, but bob knows what */ + return (SNTP_BADRESP); + } + + /* record time of arrival */ + GetTimeOfDay(&tv); + + /* convert to host order */ + n2h_ntp(&msg.originate); + n2h_ntp(&msg.receive); + n2h_ntp(&msg.transmit); + + /* look for kiss packet */ + if (msg.flags == 0xe4 && msg.stratum == 0) + { + char message[SETTINGMESSAGELEN]; + SNPrintf(message, SETTINGMESSAGELEN, + "KoD: %.4s", msg.reference_id); + SendWarningMessage(message); + /* NOTICE: Consider taking a closer look at the kiss code */ + return (SNTP_BACKOFF); + } + + /* check validity: synchronized NTPv4 server */ + switch (msg.flags) + { + case 0x23: /* version 4 client */ + /* we're probably accidentally querying ourselves */ + return (SNTP_BADRESP); + + case 0x24: /* no warning, version 4, server */ + case 0x64: /* subtract leap second, version 4, server */ + case 0xa4: /* add leap second, version 4, server */ + /* these are the normal, useful cases */ + break; + + case 0xe4: /* unsynchronized, version 4, server */ + /* server not usable (yet?) */ + return (SNTP_LAME); + + default: + return (SNTP_BADRESP); + } + + /* check if this is the response we were expecting */ + if (!nt_eq(msg.originate, sntp->last_send)) + /* probably delayed response to old request */ + return (SNTP_NORESP); + + tv2nt(&tv, &sntp->last_recv); + *nt = msg.transmit; + return (SNTP_OK); +} diff --git a/sntp.h b/sntp.h new file mode 100644 index 0000000..41c6213 --- /dev/null +++ b/sntp.h @@ -0,0 +1,105 @@ +/*- + * Copyright (c) 2007 TANDBERG Telecom AS + * Copyright (c) 2008-2009 Dag-Erling Smørgrav + * Copyright (c) 2017-2018 Carsten Sonne 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 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 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. + * + */ + +#ifndef SNTP_H_INCLUDED +#define SNTP_H_INCLUDED + +#include "config.h" + +struct sntp; + +/* + * Structure of an NTP timestamp + */ +struct ntptime +{ + uint32_t sec; + uint32_t frac; +}; + +/* + * Useful epochs, in seconds since NTP epoch + */ +#define UNIX_EPOCH 2208988800UL /* 1970-01-01 00:00:00 UTC */ +#define UTC_EPOCH 2272060800UL /* 1972-01-01 00:00:00 UTC */ + +/* clear a struct ntptime */ +#define nt_zero(nt) \ + (void)((nt).sec = (nt).frac = 0) + +/* comparison macros */ +#define nt_cmp(nt1, op, nt2) \ + ((nt1).sec op(nt2).sec && (nt1).frac op(nt2).frac) +#define nt_lt(nt1, nt2) \ + nt_cmp(nt1, <, nt2) +#define nt_le(nt1, nt2) \ + nt_cmp(nt1, <=, nt2) +#define nt_eq(nt1, nt2) \ + nt_cmp(nt1, ==, nt2) +#define nt_ge(nt1, nt2) \ + nt_cmp(nt1, >=, nt2) +#define nt_gt(nt1, nt2) \ + nt_cmp(nt1, >, nt2) + +/* + * Conversion functions + */ +void tv2nt(struct timeval *, struct ntptime *); +void nt2tv(struct ntptime *, struct timeval *); +void h2n_nt(struct ntptime *); +void n2h_nt(struct ntptime *); + +/* + * Error codes + */ +typedef enum sntp_err +{ + SNTP_OK, /* fine */ + SNTP_SYSERR, /* check errno */ + SNTP_DNSERR, /* dns error */ + SNTP_NOREQ, /* no request sent */ + SNTP_NORESP, /* no response received */ + SNTP_BADRESP, /* invalid response received */ + SNTP_LAME, /* server is lame / unsynchronized */ + SNTP_BACKOFF, /* polling too frequently */ +} sntp_err_t; + +/* + * SNTP client + */ +struct sntp *sntp_create(const char *, const char *, const char *, const char *); +int sntp_open(struct sntp *); +void sntp_close(struct sntp *); +void sntp_destroy(struct sntp *); +sntp_err_t sntp_send(struct sntp *); +sntp_err_t sntp_pending(struct sntp *); +sntp_err_t sntp_poll(struct sntp *, int); +sntp_err_t sntp_recv(struct sntp *, struct ntptime *); + +#endif diff --git a/state.c b/state.c new file mode 100644 index 0000000..781790f --- /dev/null +++ b/state.c @@ -0,0 +1,880 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "state.h" +#include "mem.h" + +struct AppState *Globals; +struct AppSettingKeys *SettingKeys; + +static const struct AppSettingKeys SettingKeyStruct = { + .DestinationAddress = KEYWORD_SERVER, + .DestinationPort = KEYWORD_PORT, + .Threshold = KEYWORD_THRESHOLD, + .Interval = KEYWORD_INTERVAL, + .Priority = KEYWORD_PRIORITY, + .Readonly = KEYWORD_READONLY, + .Timeout = KEYWORD_TIMEOUT, + .Verbose = KEYWORD_VERBOSE, + .LogFile = KEYWORD_LOGFILE}; + +const struct AppSettings DefaultSettings = { + .Type = DefaultSettingType, + .DestinationAddress = (char *)SERVER_DEF, + .DestinationPort = (char *)PORT_DEF, + .Timeout = TIMEOUT_DEF, + .Interval = INTERVAL_DEF, + .Verbose = VERBOSE_DEF, + .Readonly = READONLY_DEF, + .Priority = PRIORITY_DEF, + .Threshold = THRESHOLD_DEF, + .LogFile = (char *)LOGFILE_DEF, + .Values = 0xFFFF}; + +static void SetPrioritySetting(struct AppSettings *, void *); +static void SetIntervalSetting(struct AppSettings *, void *); +static void SetVerboseSetting(struct AppSettings *, void *); +static void SetTimeoutSetting(struct AppSettings *, void *); +static void SetThresholdSetting(struct AppSettings *, void *); +static void SetDestinationAddressSetting(struct AppSettings *, void *); +static void SetDestinationPortSetting(struct AppSettings *, void *); +static void SetReadOnlySetting(struct AppSettings *, void *); +static void SetLogFileSetting(struct AppSettings *, void *); + +// Keyword order in settingFunctions needs to match order in keyword template +const struct SettingFunc settingFunctions[] = { + {KEYWORD_READONLY, SetReadOnlySetting}, + {KEYWORD_SERVER, SetDestinationAddressSetting}, + {KEYWORD_PORT, SetDestinationPortSetting}, + {KEYWORD_TIMEOUT, SetTimeoutSetting}, + {KEYWORD_THRESHOLD, SetThresholdSetting}, + {KEYWORD_INTERVAL, SetIntervalSetting}, + {KEYWORD_VERBOSE, SetVerboseSetting}, + {KEYWORD_PRIORITY, SetPrioritySetting}, + {KEYWORD_LOGFILE, SetLogFileSetting}}; + +static const char *prefsFile = "ENV:timekeeper.prefs"; +static const char *persistentPrefsFile = "ENVARC:timekeeper.prefs"; +static const char *prefsFileSearch = "Searching for preference in %s"; +static const char *prefsFileFound = "Found preference file"; +static const char *prefsFileNotFound = "Preference file not found"; +static const char *prefsFileSave = "Saving preferences in %s"; +static const char *fileOpenError = "Could not open preference file"; +static const char *fileSaveError = "Could not save preference file"; +static const char *fileReadError = "Error while reading file"; +static const char *fileWriteError = "Error while writing file"; +static const char *unknownSetting = "Found unknown setting in preference file: %s"; +static const char *foundSetting = "Found %s in preference file"; +static const char *foundWbSetting = "Found tooltype from icon: %s"; +static const char *foundCliSetting = "Got %s from CLI"; +static const char *integerError = "Value should be an integer: %s"; +static const char *applyDefaultSettings = "Applying default values"; +static const char *applyFileSettings = "Applying values from preference file"; +static const char *applyCliSettings = "Applying values from CLI"; +static const char *applyWbSettings = "Applying values from tooltypes"; +static const char *effectiveSettings = "Listing runtime values"; +static const char *noLogFile = "(none)"; +static const char *settingTooLow = "%s < %ld (too low)"; +static const char *settingTooHigh = "%s > %ld (too high)"; +static const char *settingGreaterThan = "%s > %s"; +static const char *settingChangedLong = "%s changed: %ld -> %ld"; +static const char *settingChangedString = "%s changed: %s -> %s"; +static const char *settingSetLong = "%s already set to %ld"; +static const char *settingSetString = "%s already set to %s"; +static const char *settingValueLong = "%s=%ld"; +static const char *settingValueString = "%s=%s"; +static const char *saveValueLong = "%s=%ld\n"; +static const char *saveValueString = "%s=%s\n"; + +#define MAXSETTINGLINELEN 256 + +static struct AppSettings *fileSettings; +static struct AppSettings *cachedSettings; + +void InitState(void) +{ + Globals = (struct AppState *)AllocMemSafe(sizeof(struct AppState)); + Globals->Broker = (struct AppBroker *)AllocMemSafe(sizeof(struct AppBroker)); + Globals->Window = (struct AppSettingWindow *)AllocMemSafe(sizeof(struct AppSettingWindow)); + Globals->Settings = CreateSettings(GlobalSettingType); + Globals->Locale = OpenLocale(NULL); + SettingKeys = (struct AppSettingKeys *)&SettingKeyStruct; +} + +void DestroyState(void) +{ + if (Globals->Syncer != NULL) + { + FreeMemSafe(Globals->Syncer); + Globals->Syncer = NULL; + } + + FreeSettings(Globals->Settings); + CloseLocale(Globals->Locale); + FreeMemSafe((void *)Globals->Window); + FreeMemSafe((void *)Globals->Broker); + FreeMemSafe((void *)Globals); +} + +void ShowAppSettings(struct AppSettings *settings) +{ + char low[MAXLONGLONGCHARSIZE]; + + LongLongToStr(settings->Threshold, low); + LogTrace(settingValueLong, SettingKeys->Priority, settings->Priority); + LogTrace(settingValueString, SettingKeys->Threshold, low); + LogTrace(settingValueString, SettingKeys->DestinationAddress, settings->DestinationAddress); + LogTrace(settingValueString, SettingKeys->DestinationPort, settings->DestinationPort); + LogTrace(settingValueLong, SettingKeys->Timeout, settings->Timeout); + LogTrace(settingValueLong, SettingKeys->Interval, settings->Interval); + LogTrace(settingValueLong, SettingKeys->Verbose, settings->Verbose); + LogTrace(settingValueLong, SettingKeys->Readonly, settings->Readonly); + LogTrace(settingValueString, SettingKeys->LogFile, + settings->LogFile ? settings->LogFile : noLogFile); +} + +void ShowSettings(void) +{ + LogTrace(effectiveSettings); + ShowAppSettings(Globals->Settings); +} + +void LogFoundSetting(long type, const char *name) +{ + switch (type) + { + case FileSettingType: + LogTrace(foundSetting, name); + break; + case CliSettingType: + LogTrace(foundCliSetting, name); + break; + case WbSettingType: + LogTrace(foundWbSetting, name); + break; + default: + break; + } +} + +static void SetPrioritySetting(struct AppSettings *setting, void *value) +{ + LogFoundSetting(setting->Type, SettingKeys->Priority); + if (setting->Type == CliSettingType) + { + setting->Priority = *(long *)value; + setting->Values |= PrioritySet; + return; + } + + if (TryParseLong((char *)value, &setting->Priority)) + { + setting->Values |= PrioritySet; + return; + } + + LogWarning(integerError, value); +} + +static void SetVerboseSetting(struct AppSettings *setting, void *value) +{ + LogFoundSetting(setting->Type, SettingKeys->Verbose); + if (setting->Type == CliSettingType) + { + setting->Verbose = *(long *)value; + setting->Values |= VerboseSet; + return; + } + + if (TryParseLong((char *)value, &setting->Verbose)) + { + setting->Values |= VerboseSet; + return; + } + + LogWarning(integerError, value); +} + +static void SetIntervalSetting(struct AppSettings *setting, void *value) +{ + LogFoundSetting(setting->Type, SettingKeys->Interval); + if (setting->Type == CliSettingType) + { + setting->Interval = *(long *)value; + setting->Values |= IntervalSet; + return; + } + + if (TryParseLong((char *)value, &setting->Interval)) + { + setting->Values |= IntervalSet; + return; + } + + LogWarning(integerError, value); +} + +static void SetTimeoutSetting(struct AppSettings *setting, void *value) +{ + LogFoundSetting(setting->Type, SettingKeys->Timeout); + if (setting->Type == CliSettingType) + { + setting->Timeout = *(long *)value; + setting->Values |= TimeoutSet; + return; + } + + if (TryParseLong((char *)value, &setting->Timeout)) + { + setting->Values |= TimeoutSet; + return; + } + + LogWarning(integerError, value); +} + +static void SetThresholdSetting(struct AppSettings *setting, void *value) +{ + LogFoundSetting(setting->Type, SettingKeys->Threshold); + if (TryParseLongLong((char *)value, &setting->Threshold)) + { + setting->Values |= ThresholdSet; + return; + } + + LogWarning(integerError, value); +} + +static void SetDestinationAddressSetting(struct AppSettings *setting, void *value) +{ + LogFoundSetting(setting->Type, SettingKeys->DestinationAddress); + setting->DestinationAddress = StrDupSafe((const char *)value); + setting->Values |= DestinationAddressSet; +} + +static void SetDestinationPortSetting(struct AppSettings *setting, void *value) +{ + LogFoundSetting(setting->Type, SettingKeys->DestinationPort); + setting->DestinationPort = StrDupSafe((const char *)value); + setting->Values |= DestinationPortSet; +} + +static void SetReadOnlySetting(struct AppSettings *setting, void *value) +{ + LogFoundSetting(setting->Type, SettingKeys->Readonly); + if (setting->Type == CliSettingType) + { + setting->Readonly = value != 0 ? true : false; + setting->Values |= ReadonlySet; + return; + } + + if (TryParseLong((char *)value, &setting->Readonly)) + { + setting->Readonly = setting->Readonly != 0 ? true : false; + setting->Values |= ReadonlySet; + return; + } + + LogWarning(integerError, value); +} + +static void SetLogFileSetting(struct AppSettings *setting, void *value) +{ + static const char *no = "no"; + LogFoundSetting(setting->Type, SettingKeys->LogFile); + + if (value == NULL || *((const char *)value) == '\0' || + Stricmp((STRPTR)no, (STRPTR)value) == 0 || + Stricmp((STRPTR)noLogFile, (STRPTR)value) == 0) + { + setting->LogFile = NULL; + } + else + { + setting->LogFile = StrDupSafe((const char *)value); + } + setting->Values |= LogFileSet; +} + +static void ParseSetting(struct AppSettings *settings, char *line) +{ + char *value; + char *end; + int i; + + value = StrChr(line, '=', MAXSETTINGLINELEN); + if (value == NULL) + { + LogWarning(unknownSetting, "No assignment"); + return; + } + + end = StrChr(value, '\n', MAXSETTINGLINELEN); + if (end == NULL) + { + LogWarning(unknownSetting, "No end of line"); + return; + } + + *value++ = '\0'; + *end = '\0'; + + for (i = 0; i < KEYWORD_COUNT; i++) + { + if (Stricmp((STRPTR)settingFunctions[i].Name, (STRPTR)line) == 0) + { + settingFunctions[i].Function(settings, (void *)value); + return; + } + } + + LogWarning(unknownSetting, line); +} + +void LoadSettings(void) +{ + struct AppSettings *settings; + const int maxLines = 25; + char line[MAXSETTINGLINELEN]; + char message[MAXDOSERRORLEN]; + bool eof = false; + int count = 0; + long error; + BPTR file; + + LogTrace(prefsFileSearch, prefsFile); + file = Open((STRPTR)prefsFile, MODE_OLDFILE); + + if (!file) + { + error = IoErr(); + if (error == ERROR_OBJECT_NOT_FOUND) + { + LogWarning(prefsFileNotFound); + } + else + { + Fault(error, (STRPTR)fileOpenError, (STRPTR)message, MAXDOSERRORLEN); + LogWarning(message); + } + return; + } + + LogInfo(prefsFileFound); + + settings = CreateSettings(FileSettingType); + + do + { + char *c = (char *)FGets(file, (STRPTR)line, MAXSETTINGLINELEN); + eof = (c == NULL); + + if (!eof) + { + ParseSetting(settings, line); + count++; + } + } while (!eof && count < maxLines); + + // If NULL is returned for an EOF, IoErr() will return 0. + error = IoErr(); + if (error != 0) + { + Fault(error, (STRPTR)fileReadError, (STRPTR)message, MAXDOSERRORLEN); + LogError(message); + } + + Close(file); + fileSettings = settings; +} + +static void WriteSetting(BPTR file, const char *format, ...) +{ + long count; + va_list args; + va_start(args, format); + count = VFPrintf(file, (void *)format, (void *)args); + va_end(args); + + if (count <= 0) + { + long error = IoErr(); + if (error != 0) + { + char message[MAXDOSERRORLEN]; + Fault(error, (STRPTR)fileWriteError, (STRPTR)message, MAXDOSERRORLEN); + LogError(message); + } + } +} + +void SaveSettings(bool persist) +{ + char low[MAXLONGLONGCHARSIZE]; + const char *fileName = persist ? persistentPrefsFile : prefsFile; + BPTR file = Open((STRPTR)fileName, MODE_NEWFILE); + if (!file) + { + char message[MAXDOSERRORLEN]; + long error = IoErr(); + Fault(error, (STRPTR)fileSaveError, (STRPTR)message, MAXDOSERRORLEN); + LogWarning(message); + return; + } + + LogInfo(prefsFileSave, fileName); + + LongLongToStr(Globals->Settings->Threshold, low); + WriteSetting(file, saveValueLong, SettingKeys->Priority, Globals->Settings->Priority); + WriteSetting(file, saveValueString, SettingKeys->Threshold, low); + WriteSetting(file, saveValueString, SettingKeys->DestinationAddress, Globals->Settings->DestinationAddress); + WriteSetting(file, saveValueString, SettingKeys->DestinationPort, Globals->Settings->DestinationPort); + WriteSetting(file, saveValueLong, SettingKeys->Timeout, Globals->Settings->Timeout); + WriteSetting(file, saveValueLong, SettingKeys->Interval, Globals->Settings->Interval); + WriteSetting(file, saveValueLong, SettingKeys->Verbose, Globals->Settings->Verbose); + WriteSetting(file, saveValueLong, SettingKeys->Readonly, Globals->Settings->Readonly); + WriteSetting(file, saveValueString, SettingKeys->LogFile, Globals->Settings->LogFile); + + Close(file); +} + +struct AppSettings *CreateSettings(long type) +{ + struct AppSettings *settings; + settings = (struct AppSettings *)AllocMemSafe(sizeof(struct AppSettings)); + settings->Type = type; + return settings; +} + +struct AppSettings *CopySettings(const struct AppSettings *settings) +{ + struct AppSettings *s = CreateSettings(settings->Type); + CopyMem((void *)settings, s, sizeof(struct AppSettings)); + s->DestinationAddress = StrDupSafe(settings->DestinationAddress); + s->DestinationPort = StrDupSafe(settings->DestinationPort); + if (s->LogFile != NULL) + { + s->LogFile = StrDupSafe(settings->LogFile); + } + s->Values = 0xFFFF; + return s; +} + +void FreeSettings(struct AppSettings *settings) +{ + if (settings->DestinationAddress != NULL) + { + FreeMemSafe(settings->DestinationAddress); + } + + if (settings->DestinationPort != NULL) + { + FreeMemSafe(settings->DestinationPort); + } + + if (settings->LogFile != NULL) + { + FreeMemSafe(settings->LogFile); + } + + FreeMemSafe(settings); +} + +void ApplyAppSettings(struct AppSettings *settings, bool quiet) +{ + switch (settings->Type) + { + case DefaultSettingType: + LogInfo(applyDefaultSettings); + break; + case FileSettingType: + LogInfo(applyFileSettings); + break; + case CliSettingType: + LogInfo(applyCliSettings); + break; + case WbSettingType: + LogInfo(applyWbSettings); + break; + default: + break; + } + + if ((settings->Values & PrioritySet) == PrioritySet) + { + if (settings->Type == DefaultSettingType) + { + LogTrace(settingValueLong, SettingKeys->Priority, settings->Priority); + } + else if (Globals->Settings->Priority != settings->Priority) + { + LogInfo(settingChangedLong, SettingKeys->Priority, Globals->Settings->Priority, + settings->Priority); + } + else if (!quiet) + { + LogTrace(settingSetLong, SettingKeys->Priority, settings->Priority); + } + Globals->Settings->Priority = settings->Priority; + } + + if ((settings->Values & VerboseSet) == VerboseSet) + { + if (settings->Type == DefaultSettingType) + { + LogTrace(settingValueLong, SettingKeys->Verbose, settings->Verbose); + } + else if (Globals->Settings->Verbose != settings->Verbose) + { + LogInfo(settingChangedLong, SettingKeys->Verbose, Globals->Settings->Verbose, + settings->Verbose); + } + else if (!quiet) + { + LogTrace(settingSetLong, SettingKeys->Verbose, settings->Verbose); + } + Globals->Settings->Verbose = settings->Verbose; + } + + if ((settings->Values & TimeoutSet) == TimeoutSet) + { + if (settings->Type == DefaultSettingType) + { + LogTrace(settingValueLong, SettingKeys->Timeout, settings->Timeout); + } + else if (Globals->Settings->Timeout != settings->Timeout) + { + LogInfo(settingChangedLong, SettingKeys->Timeout, Globals->Settings->Timeout, + settings->Timeout); + } + else if (!quiet) + { + LogTrace(settingSetLong, SettingKeys->Timeout, settings->Timeout); + } + Globals->Settings->Timeout = settings->Timeout; + } + + if ((settings->Values & IntervalSet) == IntervalSet) + { + if (settings->Type == DefaultSettingType) + { + LogTrace(settingValueLong, SettingKeys->Interval, settings->Interval); + } + else if (Globals->Settings->Interval != settings->Interval) + { + LogInfo(settingChangedLong, SettingKeys->Interval, Globals->Settings->Interval, + settings->Interval); + } + else if (!quiet) + { + LogTrace(settingSetLong, SettingKeys->Interval, settings->Interval); + } + Globals->Settings->Interval = settings->Interval; + } + + if ((settings->Values & ReadonlySet) == ReadonlySet) + { + if (settings->Type == DefaultSettingType) + { + LogTrace(settingValueLong, SettingKeys->Readonly, settings->Readonly); + } + else if (Globals->Settings->Readonly != settings->Readonly) + { + LogInfo(settingChangedLong, SettingKeys->Readonly, Globals->Settings->Readonly, + settings->Readonly); + } + else if (!quiet) + { + LogTrace(settingSetLong, SettingKeys->Readonly, settings->Readonly); + } + Globals->Settings->Readonly = settings->Readonly; + } + + if ((settings->Values & DestinationAddressSet) == DestinationAddressSet) + { + if (settings->Type == DefaultSettingType) + { + LogTrace(settingValueString, SettingKeys->DestinationAddress, + settings->DestinationAddress); + } + else if (Stricmp((STRPTR)Globals->Settings->DestinationAddress, + (STRPTR)settings->DestinationAddress) != 0) + { + LogInfo(settingChangedString, SettingKeys->DestinationAddress, + Globals->Settings->DestinationAddress, settings->DestinationAddress); + } + else if (!quiet) + { + LogTrace(settingSetString, SettingKeys->DestinationAddress, settings->DestinationAddress); + } + + if (Globals->Settings->DestinationAddress != NULL) + { + FreeMemSafe(Globals->Settings->DestinationAddress); + } + Globals->Settings->DestinationAddress = StrDupSafe(settings->DestinationAddress); + } + + if ((settings->Values & DestinationPortSet) == DestinationPortSet) + { + if (settings->Type == DefaultSettingType) + { + LogTrace(settingValueString, SettingKeys->DestinationPort, + settings->DestinationPort); + } + else if (Stricmp((STRPTR)Globals->Settings->DestinationPort, + (STRPTR)settings->DestinationPort) != 0) + { + LogInfo(settingChangedString, SettingKeys->DestinationPort, + Globals->Settings->DestinationPort, settings->DestinationPort); + } + else if (!quiet) + { + LogTrace(settingSetString, SettingKeys->DestinationPort, settings->DestinationPort); + } + + if (Globals->Settings->DestinationPort != NULL) + { + FreeMemSafe(Globals->Settings->DestinationPort); + } + Globals->Settings->DestinationPort = StrDupSafe(settings->DestinationPort); + } + + if ((settings->Values & ThresholdSet) == ThresholdSet) + { + char before[MAXLONGLONGCHARSIZE]; + char after[MAXLONGLONGCHARSIZE]; + + if (settings->Type == DefaultSettingType) + { + LongLongToStr(settings->Threshold, after); + LogTrace(settingValueString, SettingKeys->Threshold, after); + } + else if (Globals->Settings->Threshold != settings->Threshold) + { + LongLongToStr(Globals->Settings->Threshold, before); + LongLongToStr(settings->Threshold, after); + LogInfo(settingChangedString, SettingKeys->Threshold, before, after); + } + else if (!quiet) + { + LongLongToStr(Globals->Settings->Threshold, before); + LogTrace(settingSetString, SettingKeys->Threshold, before); + } + Globals->Settings->Threshold = settings->Threshold; + } + + if ((settings->Values & LogFileSet) == LogFileSet) + { + if (settings->Type == DefaultSettingType) + { + LogTrace(settingValueString, SettingKeys->LogFile, + settings->LogFile != NULL ? settings->LogFile : noLogFile); + } + else if (!(Globals->Settings->LogFile == NULL && settings->LogFile == NULL) || + StrnCmp(Globals->Locale, + (STRPTR)Globals->Settings->LogFile, + (STRPTR)settings->LogFile, + (LONG)MAXSETTINGLINELEN, SC_ASCII) != 0) + { + LogInfo(settingChangedString, SettingKeys->LogFile, + Globals->Settings->LogFile != NULL ? Globals->Settings->LogFile : noLogFile, + settings->LogFile != NULL ? settings->LogFile : noLogFile); + } + else if (!quiet) + { + LogTrace(settingSetString, SettingKeys->LogFile, + settings->LogFile != NULL ? settings->LogFile : noLogFile); + } + + if (Globals->Settings->LogFile != NULL) + { + FreeMemSafe(Globals->Settings->LogFile); + } + Globals->Settings->LogFile = settings->LogFile != NULL + ? StrDupSafe(settings->LogFile) + : NULL; + } +} + +void CacheSettings(struct AppSettings *settings) +{ + if (cachedSettings != NULL) + { + FreeSettings(cachedSettings); + } + cachedSettings = settings; +} + +void ApplySettings() +{ + ApplyAppSettings((struct AppSettings *)&DefaultSettings, false); + + if (fileSettings != NULL) + { + ApplyAppSettings(fileSettings, false); + FreeSettings(fileSettings); + } + + if (cachedSettings != NULL) + { + ApplyAppSettings(cachedSettings, false); + FreeSettings(cachedSettings); + } +} + +static void ValidateInterval(void) +{ + if (Globals->Settings->Interval < INTERVAL_MIN) + { + LogInfo(settingTooLow, + SettingKeys->Interval, + INTERVAL_MIN); + LogInfo(settingChangedLong, + SettingKeys->Interval, + Globals->Settings->Interval, + INTERVAL_MIN); + Globals->Settings->Interval = INTERVAL_MIN; + } +} + +static void ValidateTimeout(void) +{ + if (Globals->Settings->Timeout < TIMEOUT_MIN) + { + LogInfo(settingTooLow, + SettingKeys->Timeout, + TIMEOUT_MIN); + LogInfo(settingChangedLong, + SettingKeys->Timeout, + Globals->Settings->Timeout, + TIMEOUT_MIN); + Globals->Settings->Timeout = TIMEOUT_MIN; + } + + if (Globals->Settings->Timeout > Globals->Settings->Interval) + { + LogInfo(settingGreaterThan, + SettingKeys->Timeout, + SettingKeys->Interval); + LogInfo(settingChangedLong, + SettingKeys->Timeout, + Globals->Settings->Timeout, + Globals->Settings->Interval); + Globals->Settings->Timeout = Globals->Settings->Interval; + } + + if (Globals->Settings->Timeout > TIMEOUT_MAX) + { + LogInfo(settingTooHigh, + SettingKeys->Timeout, + TIMEOUT_MAX); + LogInfo(settingChangedLong, + SettingKeys->Timeout, + Globals->Settings->Timeout, + TIMEOUT_MAX); + Globals->Settings->Timeout = TIMEOUT_MAX; + } +} + +static void ValidatePriority(void) +{ + if (Globals->Settings->Priority < PRIORITY_MIN) + { + LogInfo(settingTooLow, + SettingKeys->Priority, + PRIORITY_MIN); + LogInfo(settingChangedLong, + SettingKeys->Priority, + Globals->Settings->Priority, + PRIORITY_MIN); + Globals->Settings->Priority = PRIORITY_MIN; + } + + if (Globals->Settings->Priority > PRIORITY_MAX) + { + LogInfo(settingTooHigh, + SettingKeys->Priority, + PRIORITY_MAX); + LogInfo(settingChangedLong, + SettingKeys->Priority, + Globals->Settings->Priority, + PRIORITY_MAX); + Globals->Settings->Priority = PRIORITY_MAX; + } +} + +static void ValidateThreshold(void) +{ + if (Globals->Settings->Threshold < THRESHOLD_MIN) + { + LogInfo(settingTooLow, + SettingKeys->Threshold, + THRESHOLD_MIN); + LogInfo(settingChangedLong, + SettingKeys->Threshold, + Globals->Settings->Threshold, + THRESHOLD_MIN); + Globals->Settings->Threshold = THRESHOLD_MIN; + } +} + +static void ValidateVerbose(void) +{ + if (Globals->Settings->Verbose < VERBOSE_MIN) + { + LogInfo(settingTooLow, + SettingKeys->Verbose, + VERBOSE_MIN); + LogInfo(settingChangedLong, + SettingKeys->Verbose, + Globals->Settings->Verbose, + VERBOSE_MIN); + Globals->Settings->Verbose = VERBOSE_MIN; + } + + if (Globals->Settings->Verbose > VERBOSE_MAX) + { + LogInfo(settingTooHigh, + SettingKeys->Verbose, + VERBOSE_MAX); + LogInfo(settingChangedLong, + SettingKeys->Verbose, + Globals->Settings->Verbose, + VERBOSE_MAX); + Globals->Settings->Verbose = VERBOSE_MAX; + } +} + +void SanitizeSettings(void) +{ + ValidateInterval(); + ValidateTimeout(); + ValidatePriority(); + ValidateThreshold(); + ValidateVerbose(); +} diff --git a/state.h b/state.h new file mode 100644 index 0000000..edba8fd --- /dev/null +++ b/state.h @@ -0,0 +1,146 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 STATE_H_INCLUDED +#define STATE_H_INCLUDED + +#include "config.h" + +#define PrioritySet 0x001 +#define VerboseSet 0x002 +#define TimeoutSet 0x004 +#define IntervalSet 0x008 +#define ReadonlySet 0x010 +#define DestinationAddressSet 0x020 +#define DestinationPortSet 0x040 +#define ThresholdSet 0x080 +#define LogFileSet 0x200 + +#define DefaultSettingType 0x01 +#define FileSettingType 0x02 +#define CliSettingType 0x03 +#define WbSettingType 0x04 +#define GlobalSettingType 0x10 + +struct AppBroker +{ + CxObj *Object; + short ShutdownSigBit; + struct Task *Task; + struct MsgPort *BrokerPort; + struct MsgPort *UserPort; + struct MsgPort *ReplyPort; +}; + +struct AppCom; +struct AppSettingWindowGadgets; + +struct AppSettingWindow +{ + struct Process *Task; + struct Screen *Screen; + struct Window *SettingWindow; + struct Gadget *GadgetList; + struct MsgPort *UserPort; + void *VisualInfo; + char *PriorityText; + char *ThresholdText; + char *TimeZoneText; + long Width; + long Height; + struct AppSettings *Settings; + struct AppSettingWindowGadgets *Gadgets; +}; + +struct AppSettings +{ + long Priority; + long Verbose; + long Timeout; + long Interval; + long Readonly; + long long Threshold; + char *DestinationAddress; + char *DestinationPort; + char *LogFile; + long Values; + long Type; +}; + +struct AppState +{ + bool Active; + bool ShuttingDown; + struct timeval LastNtpSync; + struct Locale *Locale; + struct AppCom *Syncer; + struct AppBroker *Broker; + struct AppSettingWindow *Window; + struct AppSignals *Signals; + struct AppSettings *Settings; +}; + +struct AppSettingKeys +{ + const char *Priority; + const char *Verbose; + const char *Timeout; + const char *Interval; + const char *Readonly; + const char *DestinationAddress; + const char *DestinationPort; + const char *Threshold; + const char *LogFile; +}; + +typedef void (*ParseSettingFunction)(struct AppSettings *, void *); + +struct SettingFunc +{ + const char *Name; + ParseSettingFunction Function; +}; + +extern struct AppState *Globals; +extern struct AppSettingKeys *SettingKeys; +extern const struct SettingFunc settingFunctions[]; +extern const struct AppSettings DefaultSettings; + +void InitState(void); +void DestroyState(void); +void SanitizeSettings(void); +void ShowSettings(void); +void LoadSettings(void); +void SaveSettings(bool); + +struct AppSettings *CreateSettings(long); +struct AppSettings *CopySettings(const struct AppSettings *); +void ApplyAppSettings(struct AppSettings *, bool); +void FreeSettings(struct AppSettings *); +void CacheSettings(struct AppSettings *); +void ApplySettings(void); + +#endif diff --git a/string.c b/string.c new file mode 100644 index 0000000..22f795e --- /dev/null +++ b/string.c @@ -0,0 +1,391 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" + +static const char *alphaNumerics = "0123456789"; +static const int base = 10; + +struct RawDoFmtStream +{ + char *buf; + int size; +}; + +/* + * Get the length of a null terminated string. + */ +int StrLen(const char *string) +{ + char *i = (char *)string; + char *s = i; + while (*i) + i++; + return (int)(i - s); +} + +/* + * Copies the string pointed to by src to dest. + */ +char *StrCopy(char *dest, const char *src) +{ + char *q = (char *)src; + char *p = dest; + + while ((*p++ = *q++)) + ; + + *p = '\0'; + return dest; +} + +char *AppendText(char *start, const char *text) +{ + char *p = start; + char *q = (char *)text; + + while (*q != '\0') + *p++ = *q++; + + *p = '\0'; + return p; +} + +int TrimRight(char *string) +{ + char *i = string; + char *s = i; + + while (*i) + i++; + + if (i == s) + return 0; + + i--; + while (*i == ' ' || *i == '\r' || *i == '\n' || *i == '\t') + *i-- = '\0'; + + return (int)(i - s + 1); +} + +/* + * Find the first occurrence of a character. + */ +char *StrChr(const char *start, const char c, int len) +{ + char *i = (char *)start; + int j = 0; + + if (i == NULL) + return NULL; + + do + { + if (*i == c) + return i; + + i++; + j++; + } while (j < len); + + return NULL; +} + +/* + * Find the last occurrence of a character. + */ +char *StrRChr(const char *start, const char c, int len) +{ + char *i = (char *)start; + char *l = NULL; + int j = 0; + + if (i == NULL) + return NULL; + + do + { + if (*i == c) + l = i; + + i++; + j++; + } while (j < len); + + return l; +} + +/* + * Convert a long to a null terminated string. + */ +int LongToStr(signed long value, char *string) +{ + unsigned int len, count = 0; + unsigned long current = value; + char chars[12]; + char *p = chars; + char *q = string; + bool negative = false; + + if (value < 0) + { + current = -value; + negative = true; + } + + do + { + unsigned long remainder = current % base; + *p++ = alphaNumerics[remainder]; + current /= base; + count++; + } while (current >= 1); + + p--; + len = count; + + if (negative) + { + *q++ = '-'; + len++; + } + + while (count-- != 0) + *q++ = *p--; + + *q = '\0'; + return len; +} + +/* + * Convert a long long to a null terminated string. + */ +int LongLongToStr(signed long long value, char *string) +{ + unsigned int len, count = 0; + unsigned long long current = value; + char chars[MAXLONGLONGCHARSIZE]; + char *p = chars; + char *q = string; + bool negative = false; + + if (value < 0) + { + current = -value; + negative = true; + } + + do + { + unsigned long long remainder = current % base; + *p++ = alphaNumerics[remainder]; + current /= base; + count++; + } while (current >= 1); + + p--; + len = count; + + if (negative) + { + *q++ = '-'; + len++; + } + + while (count-- != 0) + *q++ = *p--; + + *q = '\0'; + return len; +} + +/* + * Convert a null terminated string to a long long. + */ +int StrToLongLong(char *string, unsigned long long *value) +{ + signed long long result = 0; + bool negative = false; + char *p = string; + int count = 0; + + if (*p == '-') + { + negative = true; + p++; + } + + while (*p != '\0') + { + if (*p < '0' || *p > '9' || count > 20) + { + return -1; + } + + result *= 10; + result += (*p++) - '0'; + } + + *value = negative ? -result : result; + return count; +} + +/* + * Try to parse a null terminated string to a long. + */ +bool TryParseLong(char *string, long *value) +{ + LONG characters, parsedValue; + characters = StrToLong((STRPTR)string, &parsedValue); + if (characters != -1) + { + *value = parsedValue; + return true; + } + + *value = 0; + return false; +} + +/* + * Try to parse a null terminated string to a long. + */ +bool TryParseLongLong(char *string, long long *value) +{ + unsigned long long parsedValue; + long characters; + characters = StrToLongLong(string, &parsedValue); + if (characters != -1) + { + *value = parsedValue; + return true; + } + + *value = 0; + return false; +} + +#ifdef AOS3 + +static void RawDoFmtChar(REG(d0, UBYTE c), REG(a3, struct RawDoFmtStream *s)) +{ + if (s->size > 0) + { + *(s->buf)++ = c; + (s->size)--; + + if (s->size == 1) + { + *(s->buf) = '\0'; + s->size = 0; + } + } +} + +/* + * Formats and stores a series of characters and values. + */ +int VSNPrintf(char *str, size_t size, const char *format, va_list ap) +{ + int result = 0; + + if (str != NULL) + { + struct RawDoFmtStream s; + + s.buf = str; + s.size = size; + + RawDoFmt(format, (void *)ap, (void (*)())RawDoFmtChar, (void *)&s); + + if ((result = (size - s.size)) != size) + --result; + } + + return result; +} + +/* + * Formats and stores a series of characters and values in the array buffer. + */ +int SNPrintf(char *str, size_t size, const char *format, ...) +{ + va_list args; + int result; + + va_start(args, format); + result = VSNPrintf(str, size, format, args); + va_end(args); + + return result; +} + +#endif + +/* + * Split filename in path and filename. + */ +void SplitFileName(const char *s, char *path, char *name) +{ + int len, x, y; + char *c; + + if (s == NULL || *s == '\0') + { + *path = '\0'; + *name = '\0'; + return; + } + + len = StrLen(s); + c = StrRChr(s, '/', len); + if (c == NULL) + { + c = StrChr(s, ':', len); + if (c == NULL) + { + *path = '\0'; + CopyMem((char *)s, name, len); + return; + } + else + { + // Include : + x = (c - s + 1); + } + } + else + { + x = (c - s); + } + + y = len - (c - s); + + *(char *)(path + x) = '\0'; + CopyMem((char *)s, path, x); + CopyMem(++c, name, y); +} \ No newline at end of file diff --git a/string.h b/string.h new file mode 100644 index 0000000..4feca53 --- /dev/null +++ b/string.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 STRING_H_INCLUDED +#define STRING_H_INCLUDED + +#include "compiler.h" +#include +#include + +int StrLen(const char *); +char *StrCopy(char *, const char *); +char *AppendText(char *, const char *); +int TrimRight(char *); +char *StrChr(const char *, const char, int); +char *StrRChr(const char *, const char, int); +int LongToStr(signed long, char *); +int LongLongToStr(signed long long, char *); +int StrToLongLong(char *, unsigned long long *); +bool TryParseLong(char *, long *); +bool TryParseLongLong(char *, long long *); +int VSNPrintf(char *, size_t, const char *, va_list); +int SNPrintf(char *, size_t, const char *, ...); +void SplitFileName(const char *, char *, char *); + +#endif diff --git a/time.c b/time.c new file mode 100644 index 0000000..bba0e21 --- /dev/null +++ b/time.c @@ -0,0 +1,235 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" +#include "time.h" +#include "mem.h" + +#include + +/* + * 2922 is the number of days between 1.1.1970 and 1.1.1978 + * (2 leap years and 6 normal) + * 2922 * 24 * 60 * 60 = 252460800 + */ +#define AMIGA_OFFSET 252460800 +#define TIMER_ERROR 10 +#define TIMER_OK 0 + +struct TimerInfo +{ + bool TimerTrigged; + struct MsgPort *TimerPort; + struct timerequest *TimerIO; +}; + +struct Device *TimerBase = NULL; +static struct timerequest *TimerIO = NULL; +static long utcOffset = 0; + +/* + * Set up pointer for timer functions. + */ +struct Device *OpenTimerBase(void) +{ + LONG error; + + TimerIO = (struct timerequest *)AllocMemSafe(sizeof(struct timerequest)); + if (TimerIO == NULL) + { + return NULL; + } + + error = OpenDevice((STRPTR)TIMERNAME, UNIT_MICROHZ, (struct IORequest *)TimerIO, 0); + if (error != 0) + { + FreeMemSafe(TimerIO); + TimerIO = NULL; + return NULL; + } + + TimerBase = TimerIO->tr_node.io_Device; + return TimerBase; +} + +void CloseTimerBase(void) +{ + if (TimerBase != NULL && TimerIO != NULL) + { + CloseDevice((struct IORequest *)TimerIO); + } + + if (TimerIO != NULL) + { + FreeMemSafe(TimerIO); + } +} + +/* + * Open a timer device with UNIT_VBLANK. + */ +struct TimerInfo *CreateTimer(bool setTimerBase) +{ + LONG error; + static const char *name = APP_SHORT_NAME " Timer Message Port"; + struct TimerInfo *info = (struct TimerInfo *)AllocMemSafe(sizeof(struct TimerInfo)); + if (info == NULL) + return NULL; + + info->TimerPort = CreateMsgPort(); + if (info->TimerPort == NULL) + { + DeleteTimer(info); + return NULL; + } + + info->TimerPort->mp_Node.ln_Name = (char *)name; + info->TimerPort->mp_Node.ln_Pri = 0; + + info->TimerIO = (struct timerequest *)CreateExtIO(info->TimerPort, sizeof(struct timerequest)); + if (info->TimerIO == NULL) + { + DeleteTimer(info); + return NULL; + } + + error = OpenDevice( + (STRPTR)TIMERNAME, UNIT_MICROHZ, + (struct IORequest *)info->TimerIO, 0); + + if (error != 0) + { + DeleteTimer(info); + return NULL; + } + + return info; +} + +void SetTimer(struct TimerInfo *info) +{ + info->TimerIO->tr_node.io_Command = TR_ADDREQUEST; + info->TimerIO->tr_time.tv_secs = Globals->Settings->Interval / 1000; + info->TimerIO->tr_time.tv_micro = Globals->Settings->Interval % 1000; + SendIO((struct IORequest *)info->TimerIO); + info->TimerTrigged = true; +} + +ULONG GetTimerSigMask(struct TimerInfo *info) +{ + return (1 << info->TimerPort->mp_SigBit); +} + +void DeleteTimer(struct TimerInfo *info) +{ + if (info->TimerIO != NULL) + { + AbortIO((struct IORequest *)info->TimerIO); + if (info->TimerTrigged) + { + WaitIO((struct IORequest *)info->TimerIO); + } + CloseDevice((struct IORequest *)info->TimerIO); + DeleteExtIO((struct IORequest *)info->TimerIO); + info->TimerIO = NULL; + } + + if (info->TimerPort != NULL) + { + DeleteMsgPort(info->TimerPort); + } + + FreeMemSafe(info); +} + +void InitUtcOffset(void) +{ + char timeZone[10]; + int gmtoffset = Globals->Locale->loc_GMTOffset * 60; + utcOffset = gmtoffset + AMIGA_OFFSET; + GetTimeZoneText(timeZone); + LogWarning("Local time zone is %s", timeZone); +} + +void GetTimeZoneText(char *text) +{ + SNPrintf(text, 10, "UTC%s%ld:%02ld", + -Globals->Locale->loc_GMTOffset > 0 ? "+" : "", + (long)-Globals->Locale->loc_GMTOffset / 60, + (long)-Globals->Locale->loc_GMTOffset % 60); +} + +void Unix2Amiga(struct timeval *unix, struct timeval *tv) +{ + tv->tv_secs = unix->tv_secs + AMIGA_OFFSET; + tv->tv_micro = unix->tv_micro; +} + +void Utc2Local(struct timeval *utc, struct timeval *tv) +{ + int gmtoffset = Globals->Locale->loc_GMTOffset * 60; + tv->tv_secs = utc->tv_secs - gmtoffset; + tv->tv_micro = utc->tv_micro; +} + +void GetTimeOfDay(struct timeval *tv) +{ + GetSysTime(tv); + tv->tv_secs = tv->tv_secs + utcOffset; +} + +void GetLocalTimeOfDay(struct timeval *tv) +{ + GetSysTime(tv); +} + +void SetTimeOfDay(const struct TimerInfo *info, const struct timeval *tv) +{ + info->TimerIO->tr_node.io_Command = TR_SETSYSTIME; + info->TimerIO->tr_time.tv_secs = (long)tv->tv_secs - utcOffset; + info->TimerIO->tr_time.tv_micro = tv->tv_micro; + DoIO((struct IORequest *)info->TimerIO); +} + +void SaveTimeOfDay(const struct timeval *tv) +{ + WriteBattClock((long)tv->tv_secs - utcOffset); +} + +void SystemTimeString(char *time, char *date, char *day) +{ + struct DateTime dt; + + DateStamp(&dt.dat_Stamp); + + dt.dat_Format = FORMAT_DOS; + dt.dat_Flags = 0; + dt.dat_StrDay = (void *)day; + dt.dat_StrDate = (void *)date; + dt.dat_StrTime = (void *)time; + + DateToStr(&dt); +} diff --git a/time.h b/time.h new file mode 100644 index 0000000..e4eced5 --- /dev/null +++ b/time.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 TIME_H_INCLUDED +#define TIME_H_INCLUDED + +#include "config.h" + +struct TimerInfo; + +struct Device *OpenTimerBase(void); +void CloseTimerBase(void); +struct TimerInfo *CreateTimer(bool); +void SetTimer(struct TimerInfo *); +void DeleteTimer(struct TimerInfo *); +ULONG GetTimerSigMask(struct TimerInfo *info); + +void InitUtcOffset(void); +void GetTimeZoneText(char *text); +void GetTimeOfDay(struct timeval *tv); +void SetTimeOfDay(const struct TimerInfo *, const struct timeval *tv); +void SaveTimeOfDay(const struct timeval *tv); +void GetLocalTimeOfDay(struct timeval *tv); +void Unix2Amiga(struct timeval *unix, struct timeval *tv); +void Utc2Local(struct timeval *utc, struct timeval *tv); +void SystemTimeString(char *time, char *date, char *day); + +#endif diff --git a/win.h b/win.h new file mode 100644 index 0000000..725c966 --- /dev/null +++ b/win.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 WIN_H_INCLUDED +#define WIN_H_INCLUDED + +#include +#include +#include +#include + +#define GID_SERVER 1001 +#define GID_PORT 1002 +#define GID_TIMEOUT 1003 +#define GID_INTERVAL 1004 +#define GID_THRESHOLD 1005 +#define GID_VERBOSE 1006 +#define GID_READONLY 1007 +#define GID_PRIORITY 1008 +#define GID_SAVE 1009 +#define GID_USE 1010 +#define GID_CANCEL 1011 + +/* win_main.c */ +void ShowSettingWindow(void); +void HideSettingWindow(void); +bool CheckSettingWindowClosed(void); + +/* win_gad.c */ +bool CreateGadgets(void); +void UseSettings(void); +void SetServer(void); +void SetPort(void); +void SetTimeout(void); +void SetInterval(void); +void SetThreshold(void); +void SetVerbose(void); +void SetCxPriority(void); +void ShowLastSync(void); +void SetDefaultSettings(void); + +#endif diff --git a/win_gad.c b/win_gad.c new file mode 100644 index 0000000..329c60a --- /dev/null +++ b/win_gad.c @@ -0,0 +1,686 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" +#include "message.h" +#include "state.h" +#include "time.h" +#include "mem.h" +#include "win.h" + +struct AppSettingWindowGadgets +{ + struct Gadget *ServerGadget; + struct Gadget *PortGadget; + struct Gadget *TimeoutGadget; + struct Gadget *IntervalGadget; + struct Gadget *ThresholdGadget; + struct Gadget *VerboseGadget; + struct Gadget *PriorityGadget; + struct Gadget *TimeZoneGadget; + struct Gadget *LastSyncGadget; +}; + +static const char *serverLabel = "Server address"; +static const char *portLabel = "Server port"; +static const char *timeoutLabel = "Timeout (ms)"; +static const char *intervalLabel = "Interval (ms)"; +static const char *thresholdLabel = "Threshold (us)"; +static const char *verboseLabel = "Verbose level"; +static const char *priorityLabel = "CX priority"; +static const char *timeZoneLabel = "Time zone"; +static const char *lastSyncLabel = "Last sync"; +static const char *saveLabel = "Save"; +static const char *useLabel = "Use"; +static const char *cancelLabel = "Cancel"; + +static char *verboseLevel[] = { + "Show none (0)", + "Show some (1)", + "Show more (2)", + "Show all (3)", + NULL}; + +bool CreateGadgets(void) +{ + struct Gadget *gadget; + struct NewGadget *ng; + long x, y, w, h; + long textWidth, boxWidth; + long col1, col2; + long labelId; + long tmp1, tmp2; + + Globals->Window->Gadgets = (struct AppSettingWindowGadgets *) + AllocMemSafe(sizeof(struct AppSettingWindowGadgets)); + + ng = (struct NewGadget *)AllocMemSafe(sizeof(struct NewGadget)); + if (!ng) + return false; + + gadget = CreateContext(&Globals->Window->GadgetList); + if (!gadget) + return false; + + ng->ng_VisualInfo = Globals->Window->VisualInfo; + ng->ng_TextAttr = Globals->Window->Screen->Font; + ng->ng_Flags = 0; + + w = Globals->Window->Screen->RastPort.TxWidth; + h = Globals->Window->Screen->RastPort.TxHeight; + + x = Globals->Window->Screen->WBorLeft + 8; + y = Globals->Window->Screen->WBorTop + h + 9; + + col1 = x; + textWidth = 13 + VARSIZE; + + col2 = col1 + w * textWidth; + boxWidth = 13 + VARSIZE * 2; + + ng->ng_TopEdge = y; + ng->ng_Height = h + 6; + + labelId = 5000; + + // Server + ng->ng_LeftEdge = col1; + ng->ng_Width = textWidth * w + 20; + ng->ng_GadgetID = labelId++; + gadget = CreateGadget( + TEXT_KIND, gadget, ng, + GTTX_Text, (IPTR)serverLabel, + TAG_END); + if (!gadget) + return false; + + ng->ng_LeftEdge = col2; + ng->ng_Width = boxWidth * w + 20; + ng->ng_GadgetID = GID_SERVER; + gadget = CreateGadget( + STRING_KIND, gadget, ng, + GTST_String, (IPTR)Globals->Settings->DestinationAddress, + TAG_END); + if (!gadget) + return false; + + Globals->Window->Gadgets->ServerGadget = gadget; + + // Port + ng->ng_LeftEdge = col1; + ng->ng_TopEdge += ng->ng_Height + 4; + ng->ng_Width = textWidth * w + 20; + ng->ng_GadgetID = labelId++; + gadget = CreateGadget( + TEXT_KIND, gadget, ng, + GTTX_Text, (IPTR)portLabel, + TAG_END); + if (!gadget) + return false; + + ng->ng_LeftEdge = col2; + ng->ng_Width = boxWidth * w + 20; + ng->ng_GadgetID = GID_PORT; + gadget = CreateGadget( + STRING_KIND, gadget, ng, + GTST_String, (IPTR)Globals->Settings->DestinationPort, + TAG_END); + if (!gadget) + return false; + + Globals->Window->Gadgets->PortGadget = gadget; + + // Interval + ng->ng_LeftEdge = col1; + ng->ng_TopEdge += ng->ng_Height + 4; + ng->ng_Width = textWidth * w + 20; + ng->ng_GadgetID = labelId++; + gadget = CreateGadget( + TEXT_KIND, gadget, ng, + GTNM_MaxNumberLen, 8, + GTTX_Text, (IPTR)intervalLabel, + TAG_END); + if (!gadget) + return false; + + ng->ng_LeftEdge = col2; + ng->ng_Width = boxWidth * w + 20; + ng->ng_GadgetID = GID_INTERVAL; + gadget = CreateGadget( + INTEGER_KIND, gadget, ng, + GTNM_MaxNumberLen, 8, + GTIN_Number, Globals->Settings->Interval, + TAG_END); + if (!gadget) + return false; + + gadget->Flags |= GFLG_TABCYCLE; + Globals->Window->Gadgets->IntervalGadget = gadget; + + // Timeout + ng->ng_LeftEdge = col1; + ng->ng_TopEdge += ng->ng_Height + 4; + ng->ng_Width = textWidth * w + 20; + ng->ng_GadgetID = labelId++; + gadget = CreateGadget( + TEXT_KIND, gadget, ng, + GTTX_Text, (IPTR)timeoutLabel, + TAG_END); + if (!gadget) + return false; + + ng->ng_LeftEdge = col2; + ng->ng_Width = boxWidth * w + 20; + ng->ng_GadgetID = GID_TIMEOUT; + gadget = CreateGadget( + INTEGER_KIND, gadget, ng, + GTNM_MaxNumberLen, 8, + GTIN_Number, Globals->Settings->Timeout, + TAG_END); + if (!gadget) + return false; + + gadget->Flags |= GFLG_TABCYCLE; + Globals->Window->Gadgets->TimeoutGadget = gadget; + + // Threshold + ng->ng_LeftEdge = col1; + ng->ng_TopEdge += ng->ng_Height + 4; + ng->ng_Width = textWidth * w + 20; + ng->ng_GadgetID = labelId++; + gadget = CreateGadget( + TEXT_KIND, gadget, ng, + GTTX_Text, (IPTR)thresholdLabel, + TAG_END); + if (!gadget) + return false; + + ng->ng_LeftEdge = col2; + ng->ng_Width = boxWidth * w + 20; + ng->ng_GadgetID = GID_THRESHOLD; + gadget = CreateGadget( + STRING_KIND, gadget, ng, + GTST_String, (IPTR)Globals->Window->ThresholdText, + TAG_END); + if (!gadget) + return false; + + gadget->Flags |= GFLG_TABCYCLE; + Globals->Window->Gadgets->ThresholdGadget = gadget; + + // Verbose + ng->ng_LeftEdge = col1; + ng->ng_TopEdge += ng->ng_Height + 4; + ng->ng_Width = textWidth * w + 20; + ng->ng_GadgetID = labelId++; + gadget = CreateGadget( + TEXT_KIND, gadget, ng, + GTTX_Text, (IPTR)verboseLabel, + TAG_END); + if (!gadget) + return false; + + ng->ng_LeftEdge = col2; + ng->ng_Width = boxWidth * w + 20; + ng->ng_GadgetID = GID_VERBOSE; + gadget = CreateGadget( + CYCLE_KIND, gadget, ng, + GTCY_Labels, (IPTR)verboseLevel, + GTCY_Active, Globals->Settings->Verbose, + TAG_END); + if (!gadget) + return false; + + gadget->Flags |= GFLG_TABCYCLE; + Globals->Window->Gadgets->VerboseGadget = gadget; + + // Priority + ng->ng_LeftEdge = col1; + ng->ng_TopEdge += ng->ng_Height + 4; + ng->ng_Width = textWidth * w + 20; + ng->ng_GadgetID = labelId++; + gadget = CreateGadget( + TEXT_KIND, gadget, ng, + GTTX_Text, (IPTR)priorityLabel, + TAG_END); + if (!gadget) + return false; + + ng->ng_LeftEdge = col2; + ng->ng_Width = (boxWidth * w + 20) / 2; + ng->ng_GadgetID = GID_PRIORITY; + + gadget = CreateGadget( + STRING_KIND, gadget, ng, + GTST_String, (IPTR)Globals->Window->PriorityText, + TAG_END); + if (!gadget) + return false; + + gadget->Flags |= GFLG_TABCYCLE; + Globals->Window->Gadgets->PriorityGadget = gadget; + + // Time zone + ng->ng_LeftEdge = col1; + ng->ng_TopEdge += ng->ng_Height + 4; + ng->ng_Width = textWidth * w + 20; + ng->ng_GadgetID = labelId++; + gadget = CreateGadget( + TEXT_KIND, gadget, ng, + GTTX_Text, (IPTR)timeZoneLabel, + TAG_END); + if (!gadget) + return false; + + ng->ng_LeftEdge = col2; + ng->ng_Width = boxWidth * w + 20; + ng->ng_GadgetID = labelId++; + gadget = CreateGadget( + TEXT_KIND, gadget, ng, + GTTX_Text, (IPTR)Globals->Window->TimeZoneText, + TAG_END); + if (!gadget) + return false; + + Globals->Window->Gadgets->TimeZoneGadget = gadget; + + // Last sync + ng->ng_LeftEdge = col1; + ng->ng_TopEdge += ng->ng_Height + 4; + ng->ng_Width = textWidth * w + 20; + ng->ng_GadgetID = labelId++; + gadget = CreateGadget( + TEXT_KIND, gadget, ng, + GTTX_Text, (IPTR)lastSyncLabel, + TAG_END); + if (!gadget) + return false; + + ng->ng_LeftEdge = col2; + ng->ng_Width = boxWidth * w + 20; + ng->ng_GadgetID = labelId++; + gadget = CreateGadget( + TEXT_KIND, gadget, ng, + TAG_END); + if (!gadget) + return false; + + Globals->Window->Gadgets->LastSyncGadget = gadget; + + tmp1 = ng->ng_LeftEdge + ng->ng_Width - 18; // Why is this 18? + tmp2 = tmp1 / 3; + + ng->ng_TopEdge += ng->ng_Height + 6; + ng->ng_Width = tmp2; + ng->ng_LeftEdge = col1; + ng->ng_GadgetText = (STRPTR)saveLabel; + ng->ng_GadgetID = GID_SAVE; + ng->ng_Flags = 0; + gadget = CreateGadget(BUTTON_KIND, gadget, ng, TAG_END); + if (!gadget) + return false; + + ng->ng_LeftEdge += ng->ng_Width + 4; + ng->ng_GadgetText = (STRPTR)useLabel; + ng->ng_GadgetID = GID_USE; + gadget = CreateGadget(BUTTON_KIND, gadget, ng, TAG_END); + if (!gadget) + return false; + + ng->ng_LeftEdge += ng->ng_Width + 4; + ng->ng_GadgetText = (STRPTR)cancelLabel; + ng->ng_GadgetID = GID_CANCEL; + gadget = CreateGadget(BUTTON_KIND, gadget, ng, TAG_END); + if (!gadget) + return false; + + Globals->Window->Height = ng->ng_TopEdge + ng->ng_Height; + Globals->Window->Width = textWidth * w + boxWidth * w; + + FreeMemSafe(ng); + return true; +} + +static char *BuildLogText(const char *setting, char *oldValue, char *newValue) +{ + static const char *txt1 = " changed: "; + static const char *txt2 = " -> "; + char *p = AllocMemSafe(SETTINGMESSAGELEN); + char *s = p; + p = AppendText(p, (char *)setting); + p = AppendText(p, (char *)txt1); + p = AppendText(p, oldValue); + p = AppendText(p, (char *)txt2); + p = AppendText(p, newValue); + return s; +} + +void UseSettings(void) +{ + SetServer(); + SetPort(); + SetInterval(); + SetTimeout(); + SetThreshold(); + SetVerbose(); + SetCxPriority(); +} + +void SetServer(void) +{ + char *server, *text; + + GT_GetGadgetAttrs( + Globals->Window->Gadgets->ServerGadget, + Globals->Window->SettingWindow, NULL, + GTST_String, (IPTR)&server, + TAG_END); + + if (Stricmp((STRPTR)server, (STRPTR)Globals->Settings->DestinationAddress) == 0) + return; + + text = BuildLogText(SettingKeys->DestinationAddress, + Globals->Settings->DestinationAddress, + server); + FreeMemSafe(Globals->Settings->DestinationAddress); + Globals->Settings->DestinationAddress = StrDupSafe(server); + SendInfoMessage(text); + SendMessage(ATK_RESTART); +} + +void SetPort(void) +{ + char *port, *text; + + GT_GetGadgetAttrs( + Globals->Window->Gadgets->PortGadget, + Globals->Window->SettingWindow, NULL, + GTST_String, (IPTR)&port, + TAG_END); + + if (Stricmp((STRPTR)port, (STRPTR)Globals->Settings->DestinationPort) == 0) + return; + + text = BuildLogText(SettingKeys->DestinationPort, + Globals->Settings->DestinationPort, + port); + FreeMemSafe(Globals->Settings->DestinationPort); + Globals->Settings->DestinationPort = StrDupSafe(port); + SendInfoMessage(text); + SendMessage(ATK_RESTART); +} + +void SetInterval(void) +{ + unsigned long value; + + GT_GetGadgetAttrs( + Globals->Window->Gadgets->IntervalGadget, + Globals->Window->SettingWindow, NULL, + GTIN_Number, (IPTR)&value, + TAG_END); + + if (value < INTERVAL_MIN) + value = INTERVAL_MIN; + + if (Globals->Settings->Interval != value) + { + char *text; + char newValue[MAXLONGCHARSIZE]; + char oldValue[MAXLONGCHARSIZE]; + + LongToStr(Globals->Settings->Interval, oldValue); + LongToStr(value, newValue); + Globals->Settings->Interval = value; + text = BuildLogText(SettingKeys->Interval, oldValue, newValue); + SendInfoMessage(text); + } +} + +void SetTimeout(void) +{ + unsigned long value; + GT_GetGadgetAttrs( + Globals->Window->Gadgets->TimeoutGadget, + Globals->Window->SettingWindow, NULL, + GTIN_Number, (IPTR)&value, + TAG_END); + + if (value < TIMEOUT_MIN) + value = TIMEOUT_MIN; + else if (value > TIMEOUT_MAX) + value = TIMEOUT_MAX; + + if (Globals->Settings->Timeout != value) + { + char *text; + char newValue[MAXLONGCHARSIZE]; + char oldValue[MAXLONGCHARSIZE]; + + LongToStr(Globals->Settings->Timeout, oldValue); + LongToStr(value, newValue); + Globals->Settings->Timeout = value; + text = BuildLogText(SettingKeys->Timeout, oldValue, newValue); + SendInfoMessage(text); + } +} + +void SetThreshold(void) +{ + unsigned long long value; + char *tempString; + int result; + + GT_GetGadgetAttrs( + Globals->Window->Gadgets->ThresholdGadget, + Globals->Window->SettingWindow, NULL, + GTST_String, (IPTR)&tempString, + TAG_END); + + result = StrToLongLong(tempString, &value); + if (result != -1 && Globals->Settings->Threshold != value) + { + char *text; + char newValue[MAXLONGLONGCHARSIZE]; + char oldValue[MAXLONGLONGCHARSIZE]; + + LongLongToStr(Globals->Settings->Threshold, oldValue); + LongLongToStr(value, newValue); + Globals->Settings->Threshold = value; + text = BuildLogText(SettingKeys->Threshold, oldValue, newValue); + SendInfoMessage(text); + SendMessage(ATK_RESTART); + } +} + +void SetVerbose(void) +{ + long value; + GT_GetGadgetAttrs( + Globals->Window->Gadgets->VerboseGadget, + Globals->Window->SettingWindow, NULL, + GTCY_Active, (IPTR)&value, + TAG_END); + + if (value < VERBOSE_MIN) + value = VERBOSE_MIN; + else if (value > VERBOSE_MAX) + value = VERBOSE_MAX; + + if (Globals->Settings->Verbose != value) + { + char *text; + char newValue[MAXLONGCHARSIZE]; + char oldValue[MAXLONGCHARSIZE]; + + LongToStr(Globals->Settings->Verbose, oldValue); + LongToStr(value, newValue); + text = BuildLogText(SettingKeys->Verbose, oldValue, newValue); + SendInfoMessage(text); + Globals->Settings->Verbose = value; + } +} + +void SetCxPriority(void) +{ + LONG value; + char *tempString; + int result; + + GT_GetGadgetAttrs( + Globals->Window->Gadgets->PriorityGadget, + Globals->Window->SettingWindow, NULL, + GTST_String, (IPTR)&tempString, + TAG_END); + + result = StrToLong((STRPTR)tempString, &value); + if (result != -1) + { + if (value < PRIORITY_MIN) + value = PRIORITY_MIN; + else if (value > PRIORITY_MAX) + value = PRIORITY_MAX; + + if (Globals->Settings->Priority != value) + { + char *text; + char newValue[MAXLONGCHARSIZE]; + char oldValue[MAXLONGCHARSIZE]; + + LongToStr(Globals->Settings->Priority, oldValue); + LongToStr(value, newValue); + Globals->Settings->Priority = value; + text = BuildLogText(SettingKeys->Priority, oldValue, newValue); + SetBrokerPriority(value); + SendInfoMessage(text); + } + } +} + +void ShowLastSync(void) +{ + static char label[10]; + struct timeval nowLocal, last, lastLocal; + struct ClockData clockdata; + struct DateTime dateTime = { + .dat_Stamp = {.ds_Days = 0}, + .dat_Format = FORMAT_DOS, + .dat_Flags = 0, + .dat_StrDay = NULL, + .dat_StrDate = NULL, + .dat_StrTime = (STRPTR)label}; + long seconds; + + if (Globals->LastNtpSync.tv_secs == 0) + { + static const char *never = "Not synced yet"; + GT_SetGadgetAttrs( + Globals->Window->Gadgets->LastSyncGadget, + Globals->Window->SettingWindow, NULL, + GTTX_Text, (IPTR)never, + TAG_END); + + return; + } + + GetLocalTimeOfDay(&nowLocal); + Unix2Amiga(&Globals->LastNtpSync, &last); + Utc2Local(&last, &lastLocal); + seconds = nowLocal.tv_secs - lastLocal.tv_secs; + + if (seconds > 60 * 60 * 24) + { + static const char *tooOld = "> 24 hours"; + GT_SetGadgetAttrs( + Globals->Window->Gadgets->LastSyncGadget, + Globals->Window->SettingWindow, NULL, + GTTX_Text, (IPTR)tooOld, + TAG_END); + + return; + } + + Amiga2Date(lastLocal.tv_secs, &clockdata); + dateTime.dat_Stamp.ds_Minute = clockdata.hour * 60 + clockdata.min; + dateTime.dat_Stamp.ds_Tick = clockdata.sec * 50; + DateToStr(&dateTime); + + GT_SetGadgetAttrs( + Globals->Window->Gadgets->LastSyncGadget, + Globals->Window->SettingWindow, NULL, + GTTX_Text, (IPTR)label, + TAG_END); +} + +void SetDefaultSettings(void) +{ + static char priorityText[MAXLONGCHARSIZE]; + static char thresholdText[MAXLONGLONGCHARSIZE]; + + GT_SetGadgetAttrs( + Globals->Window->Gadgets->ServerGadget, + Globals->Window->SettingWindow, NULL, + GTST_String, (IPTR)DefaultSettings.DestinationAddress, + TAG_END); + + GT_SetGadgetAttrs( + Globals->Window->Gadgets->PortGadget, + Globals->Window->SettingWindow, NULL, + GTST_String, (IPTR)DefaultSettings.DestinationPort, + TAG_END); + + GT_SetGadgetAttrs( + Globals->Window->Gadgets->TimeoutGadget, + Globals->Window->SettingWindow, NULL, + GTIN_Number, DefaultSettings.Timeout, + TAG_END); + + GT_SetGadgetAttrs( + Globals->Window->Gadgets->IntervalGadget, + Globals->Window->SettingWindow, NULL, + GTIN_Number, DefaultSettings.Interval, + TAG_END); + + LongLongToStr(DefaultSettings.Threshold, thresholdText); + GT_SetGadgetAttrs( + Globals->Window->Gadgets->ThresholdGadget, + Globals->Window->SettingWindow, NULL, + GTST_String, (IPTR)thresholdText, + TAG_END); + + GT_SetGadgetAttrs( + Globals->Window->Gadgets->VerboseGadget, + Globals->Window->SettingWindow, NULL, + GTCY_Active, DefaultSettings.Verbose, + TAG_END); + + LongToStr(DefaultSettings.Priority, priorityText); + GT_SetGadgetAttrs( + Globals->Window->Gadgets->PriorityGadget, + Globals->Window->SettingWindow, NULL, + GTST_String, (IPTR)priorityText, + TAG_END); +} diff --git a/win_main.c b/win_main.c new file mode 100644 index 0000000..23c35d6 --- /dev/null +++ b/win_main.c @@ -0,0 +1,343 @@ +/*- + * Copyright (c) 2017-2018 Carsten Sonne 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 "config.h" +#include "message.h" +#include "state.h" +#include "time.h" +#include "mem.h" +#include "win.h" + +static void SettingsProc(void); +static void ProcessMsg(void); +static void HandleGadgetUp(struct Gadget *); + +void ShowSettingWindow(void) +{ + bool running; + + Forbid(); + running = Globals->Window->Task != NULL; + if (!running) + { + Globals->Window->Task = CreateNewProcTags( + NP_Entry, (IPTR)SettingsProc, + NP_Name, (IPTR)APP_SHORT_NAME " Window", + NP_StackSize, 64 * 1024, + TAG_DONE); + } + Permit(); + + if (running) + { + LogTrace("Setting process is already running"); + return; + } + + if (Globals->Window->Task != NULL) + { + LogTrace("Created setting process"); + } + else + { + LogError("Failed to create setting process"); + } +} + +void HideSettingWindow(void) +{ + Forbid(); + if (Globals->Window->Task != NULL) + { + Signal((void *)Globals->Window->Task, SIGBREAKF_CTRL_C); + } + Permit(); +} + +bool CheckSettingWindowClosed(void) +{ + return (Globals->Window->Task == NULL); +} + +static bool InitWindow(void) +{ + Globals->Window->Screen = LockPubScreen(NULL); + if (!Globals->Window->Screen) + { + return false; + } + + Globals->Window->UserPort = CreateMsgPort(); + if (Globals->Window->UserPort == NULL) + { + return false; + } + + Globals->Window->VisualInfo = GetVisualInfo(Globals->Window->Screen, NULL); + if (Globals->Window->VisualInfo == NULL) + { + return false; + } + + Globals->Window->PriorityText = AllocMemSafe(15); + Globals->Window->TimeZoneText = AllocMemSafe(10); + Globals->Window->ThresholdText = AllocMemSafe(MAXLONGLONGCHARSIZE); + if (Globals->Window->PriorityText == NULL || + Globals->Window->TimeZoneText == NULL || + Globals->Window->ThresholdText == NULL) + { + return false; + } + + LongToStr(Globals->Settings->Priority, Globals->Window->PriorityText); + LongLongToStr(Globals->Settings->Threshold, Globals->Window->ThresholdText); + GetTimeZoneText(Globals->Window->TimeZoneText); + + return true; +} + +static void DestroyWindow(void) +{ + if (Globals->Window->SettingWindow != NULL) + { + struct Message *msg; + while ((msg = GetMsg(Globals->Window->SettingWindow->UserPort))) + ReplyMsg(msg); + + CloseWindow(Globals->Window->SettingWindow); + Globals->Window->SettingWindow = NULL; + } + + if (Globals->Window->GadgetList != NULL) + { + FreeGadgets(Globals->Window->GadgetList); + Globals->Window->GadgetList = NULL; + } + + if (Globals->Window->VisualInfo != NULL) + { + FreeVisualInfo(Globals->Window->VisualInfo); + Globals->Window->VisualInfo = NULL; + } + + if (Globals->Window->UserPort != NULL) + { + struct Message *msg; + while ((msg = GetMsg(Globals->Window->UserPort))) + ReplyMsg(msg); + + DeleteMsgPort(Globals->Window->UserPort); + Globals->Window->UserPort = NULL; + } + + if (Globals->Window->Screen != NULL) + { + UnlockPubScreen(NULL, Globals->Window->Screen); + Globals->Window->Screen = NULL; + } + + FreeSettings(Globals->Window->Settings); + FreeMemSafe(Globals->Window->Gadgets); + FreeMemSafe(Globals->Window->PriorityText); + FreeMemSafe(Globals->Window->ThresholdText); + FreeMemSafe(Globals->Window->TimeZoneText); + Globals->Window->Gadgets = NULL; + Globals->Window->PriorityText = NULL; + Globals->Window->ThresholdText = NULL; + Globals->Window->TimeZoneText = NULL; + + Forbid(); + Globals->Window->Task = NULL; + Permit(); +} + +static bool CreateWindow(void) +{ + long w = Globals->Window->Screen->WBorLeft + Globals->Window->Screen->WBorRight + Globals->Window->Width + 38; // Why is this 38? + long h = Globals->Window->Height + 8 + Globals->Window->Screen->WBorBottom; + struct Window *x = OpenWindowTags(NULL, + WA_Width, w, + WA_Height, h, + WA_Left, (Globals->Window->Screen->Width - w) / 2, + WA_Top, (Globals->Window->Screen->Height - h) / 2, + WA_PubScreen, (IPTR)Globals->Window->Screen, + WA_Title, (IPTR)APP_LONG_NAME, + WA_Flags, WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_ACTIVATE | WFLG_SIMPLE_REFRESH, + WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW | IDCMP_VANILLAKEY | IDCMP_GADGETUP | IDCMP_MENUPICK, + WA_Gadgets, (IPTR)Globals->Window->GadgetList, + TAG_END); + Globals->Window->SettingWindow = x; + if (!x) + { + return false; + } + + return true; +} + +static void InitWindowSettings() +{ + if (Globals->Window->Settings != NULL) + { + FreeSettings(Globals->Window->Settings); + } + Globals->Window->Settings = CopySettings(Globals->Settings); +} + +static void SyncExit() +{ + if (!Globals->ShuttingDown) + { + struct MsgPort *replyPort = CreateMsgPort(); + if (replyPort) + { + SendMessageTo(Globals->Broker->UserPort, replyPort, ATK_UNDO); + WaitPort(replyPort); + GetMsg(replyPort); + DeleteMsgPort(replyPort); + } + } +} + +static void SettingsProc(void) +{ + if (!InitWindow() || !CreateGadgets() || !CreateWindow()) + { + DestroyWindow(); + return; + } + + InitWindowSettings(); + ShowLastSync(); + ProcessMsg(); + SyncExit(); + DestroyWindow(); +} + +static void ProcessMsg(void) +{ + bool loop = true; + + GT_RefreshWindow(Globals->Window->SettingWindow, NULL); + + do + { + ULONG sigrcvd = Wait(SIGBREAKF_CTRL_C | + (1 << Globals->Window->UserPort->mp_SigBit) | + (1 << Globals->Window->SettingWindow->UserPort->mp_SigBit)); + + if (sigrcvd & (1 << Globals->Window->SettingWindow->UserPort->mp_SigBit)) + { + struct IntuiMessage *msg; + while ((msg = GT_GetIMsg(Globals->Window->SettingWindow->UserPort))) + { + switch (msg->Class) + { + case IDCMP_REFRESHWINDOW: + GT_BeginRefresh(Globals->Window->SettingWindow); + GT_EndRefresh(Globals->Window->SettingWindow, TRUE); + break; + case IDCMP_GADGETUP: + HandleGadgetUp((struct Gadget *)msg->IAddress); + break; + case IDCMP_VANILLAKEY: + if (msg->Code == 0x1b) + loop = false; + break; + case IDCMP_CLOSEWINDOW: + loop = false; + break; + } + + GT_ReplyIMsg(msg); + } + } + + if (sigrcvd & (1 << Globals->Window->UserPort->mp_SigBit)) + { + struct AppWindowMessage *msg; + while ((msg = (struct AppWindowMessage *)GetMsg(Globals->Window->UserPort))) + { + switch (msg->Type) + { + case ATK_REFRESH: + ShowLastSync(); + break; + default: + break; + } + ReplyMsg((struct Message *)msg); + } + } + + if (sigrcvd & SIGBREAKF_CTRL_C) + { + loop = false; + } + } while (loop); +} + +static void HandleGadgetUp(struct Gadget *gadget) +{ + switch (gadget->GadgetID) + { + case GID_SERVER: + SetServer(); + break; + case GID_PORT: + SetPort(); + break; + case GID_INTERVAL: + SetInterval(); + break; + case GID_TIMEOUT: + SetTimeout(); + break; + case GID_THRESHOLD: + SetThreshold(); + break; + case GID_VERBOSE: + SetVerbose(); + break; + case GID_PRIORITY: + SetCxPriority(); + break; + case GID_SAVE: + SendMessage(ATK_STORE); + break; + case GID_USE: + UseSettings(); + InitWindowSettings(); + SendMessage(ATK_APPLY); + break; + case GID_CANCEL: + SendMessage(ATK_UNDO); + HideSettingWindow(); + break; + default: + break; + } +}