From 2f107f7f288b3d29831c5b457cf349d48e76e83f Mon Sep 17 00:00:00 2001 From: nocturn9x Date: Mon, 27 Dec 2021 11:17:24 +0100 Subject: [PATCH] Added VERY experimental (untested) networking code --- src/core/control.nim | 23 +++++++++++++++++++++++ src/core/mainloop.nim | 40 ++++++++++++++++++++++++++++++++++++++-- src/core/services.nim | 5 +++-- src/core/shutdown.nim | 36 ++++++++++++++++++++++++++++++++++-- 4 files changed, 98 insertions(+), 6 deletions(-) diff --git a/src/core/control.nim b/src/core/control.nim index a19ac77..3e17a2c 100644 --- a/src/core/control.nim +++ b/src/core/control.nim @@ -11,3 +11,26 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import os +import net +import strformat +import shutdown + + +import ../util/logging +import ../util/misc + + +proc initControlSocket*(logger: Logger, path: string = "/var/run/nimd.sock"): Socket = + ## Initializes NimD's control socket (an unbuffered + ## TCP Unix Domain Socket) binding it to the given + ## path (defaults to /var/run/nimd.sock) + try: + logger.info(&"Initializing control socket at '{path}'") + if exists(path): + removeFile(path) + result = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP, buffered=false) + bindUnix(result, path) + except OSError: + logger.error(&"Error when binding unix socket at '{path}': {getCurrentExceptionMsg()}") + nimDExit(logger, code=int(osLastError())) \ No newline at end of file diff --git a/src/core/mainloop.nim b/src/core/mainloop.nim index 214362c..b968141 100644 --- a/src/core/mainloop.nim +++ b/src/core/mainloop.nim @@ -13,10 +13,13 @@ # limitations under the License. import strformat import os +import net import ../util/[logging, misc] import services +import control +import shutdown @@ -27,10 +30,43 @@ proc mainLoop*(logger: Logger) = logger.debug(&"Unblocking signals") unblockSignals(logger) logger.info("System initialization complete, going idle") - logger.switchToFile() + var opType: string try: + logger.trace("Calling initControlSocket()") + var serverSocket = initControlSocket(logger) + serverSocket.listen(5) + var clientSocket = newSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP) + # logger.switchToFile() while true: - sleepSeconds(30) + serverSocket.accept(clientSocket) + if clientSocket.recv(opType, size=1) == 0: + logger.debug(&"Client has disconnected, waiting for new connection") + continue + logger.debug(&"Received operation type '{opType}' via control socket") + # The operation type is a single byte: + # - 'p' -> poweroff + # - 'r' -> reboot + # - 'h' -> halt + # - 's' -> Services-related operations (start, stop, get status, etc.) + case opType: + of "": + logger.debug(&"Empty read from control socket: did the client disconnect?") + continue + of "p": + logger.info("Received shutdown request") + shutdown(logger) + of "r": + logger.info("Received reboot request") + reboot(logger) + of "h": + logger.info("Received halt request") + halt(logger) + of "s": + discard # TODO + else: + logger.warning(&"Received unknown operation type '{opType}' via control socket, ignoring it") + discard + clientSocket.close() except: logger.critical(&"A critical error has occurred while running, restarting the mainloop in 30 seconds! Error -> {getCurrentExceptionMsg()}") sleepSeconds(30) diff --git a/src/core/services.nim b/src/core/services.nim index e4fb00d..cd3fb07 100644 --- a/src/core/services.nim +++ b/src/core/services.nim @@ -327,8 +327,9 @@ proc startService(logger: Logger, service: Service) = elif pid == 0: logger.trace(&"New child has been spawned") supervisorWorker(logger, service, process) - # If the service is unsupervised we just spawn the logger worker - loggerWorker(logger, service, process) + # If the service is unsupervised we just spawn the logger worker (assuming it doesn't use poParentStreams) + if not service.useParentStreams: + loggerWorker(logger, service, process) except: logger.error(&"Error while starting service '{service.name}': {getCurrentExceptionMsg()}") diff --git a/src/core/shutdown.nim b/src/core/shutdown.nim index cb2bd3f..e51cf13 100644 --- a/src/core/shutdown.nim +++ b/src/core/shutdown.nim @@ -18,6 +18,8 @@ import glob import strutils import strformat import times +import tables +import syscall import ../util/logging @@ -29,6 +31,9 @@ type ShutdownHandler* = ref object body*: proc (logger: Logger, code: int) +const reboot_codes = {"poweroff": 0x4321fedc'i64, "restart": 0x01234567'i64, "halt": 0xcdef0123}.toTable() + + proc newShutdownHandler*(body: proc (logger: Logger, code: int)): ShutdownHandler = result = ShutdownHandler(body: body) @@ -80,6 +85,7 @@ proc nimDExit*(logger: Logger, code: int, emerg: bool = true) = ## NimD's exit point. This function tries to shut down ## as cleanly as possible. When emerg equals true, it will ## try to spawn a root shell and exit + logger.switchToConsole() if emerg: # We're in emergency mode: do not crash the kernel, spawn a shell and exit logger.fatal("NimD has entered emergency mode and cannot continue. You will be now (hopefully) dropped in a root shell: you're on your own. May the force be with you") @@ -89,7 +95,7 @@ proc nimDExit*(logger: Logger, code: int, emerg: bool = true) = quit(-1) logger.warning("The system is shutting down") logger.info("Processing shutdown runlevel") - startServices(logger, Shutdown) + startServices(logger, RunLevel.Shutdown) logger.info("Running shutdown handlers") try: for handler in shutdownHandlers: @@ -108,4 +114,30 @@ proc nimDExit*(logger: Logger, code: int, emerg: bool = true) = logger.info("Terminating child processes with SIGKILL") discard posix.kill(-1, SIGKILL) logger.warning("Shutdown procedure complete, sending final termination signal") - quit(code) + + +proc reboot*(logger: Logger) = + ## Reboots the system + logger.debug("Switching logs to console") + logger.switchToConsole() + logger.info("The system is rebooting") + nimDExit(logger, 0, emerg=false) + discard syscall(REBOOT, 0xfee1dead, 537993216, reboot_codes["reboot"]) + + +proc shutdown*(logger: Logger) = + ## Shuts the system off + logger.debug("Switching logs to console") + logger.switchToConsole() + logger.info("The system is powering off") + nimDExit(logger, 0, emerg=false) + discard syscall(REBOOT, 0xfee1dead, 537993216, reboot_codes["poweroff"]) + + +proc halt*(logger: Logger) = + ## Halts the system + logger.debug("Switching logs to console") + logger.switchToConsole() + logger.info("The system is halting") + nimDExit(logger, 0, emerg=false) + discard syscall(REBOOT, 0xfee1dead, 537993216, reboot_codes["halt"])