aboutsummaryrefslogtreecommitdiff
path: root/daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon.c')
-rw-r--r--daemon.c330
1 files changed, 0 insertions, 330 deletions
diff --git a/daemon.c b/daemon.c
deleted file mode 100644
index ff95353..0000000
--- a/daemon.c
+++ /dev/null
@@ -1,330 +0,0 @@
-#define DEBUG
-/*
- * daemon.c
- * --------
- * A daemon to arbitrate shared access to a serial connection to the HSM.
- *
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - 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.
- *
- * - Neither the name of the NORDUnet 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 COPYRIGHT HOLDERS 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 COPYRIGHT
- * HOLDER 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <poll.h>
-#include <getopt.h> /* required with -std=c99 */
-#include <termios.h> /* for default speed */
-
-#include "hal_internal.h"
-#include "slip_internal.h"
-#include "xdr_internal.h"
-
-static char usage[] =
- "usage: %s [-n socketname] [-d ttydevice] [-s ttyspeed]\n";
-
-/*
- * Work around glibc "feature test" insanity. This isn't the correct
- * definition according to the POSIX, but it does what seems to be the
- * normal hack on Linux (where this is broken more often than not).
- */
-
-#ifndef SUN_LEN
-#define SUN_LEN(_sun_ptr_) (sizeof(*(_sun_ptr_)))
-#endif
-
-/* select() is hopelessly broken, and epoll() is Linux-specific, so we'll use
- * poll() until such a time as libevent or libev seems more appropriate.
- * Unfortunately, poll() doesn't come with any macros or functions to manage
- * the pollfd array, so we have to invent them.
- */
-
-static struct pollfd *pollfds = NULL;
-static nfds_t nfds = 0;
-static nfds_t npollfds = 0;
-
-static void poll_add(int fd)
-{
- /* add 4 entries at a time to avoid having to realloc too often */
-#define NNEW 4
-
- /* expand the array if necessary */
- if (nfds == npollfds) {
- npollfds = nfds + NNEW;
- pollfds = realloc(pollfds, npollfds * sizeof(struct pollfd));
- if (pollfds == NULL) {
- perror("realloc");
- exit(EXIT_FAILURE);
- }
- /* zero the new entries for hygiene */
- memset(&pollfds[nfds], 0, NNEW * sizeof(struct pollfd));
- }
-
- /* populate the new entry */
- pollfds[nfds].fd = fd;
- pollfds[nfds].events = POLLIN;
- ++nfds;
-}
-
-static void poll_remove(int fd)
-{
- nfds_t i;
-
- /* search the pollfd array */
- for (i = 0; i < nfds; ++i) {
- if (pollfds[i].fd == fd) {
- /* shift remainder of the array left by one */
- memmove(&pollfds[i], &pollfds[i + 1], (nfds - i - 1) * sizeof(struct pollfd));
- /* zero the last entry for hygiene */
- memset(&pollfds[nfds - 1], 0, sizeof(struct pollfd));
- --nfds;
- return;
- }
- }
- /* if it's not found, return without an error */
-}
-
-typedef struct {
- size_t len;
- uint8_t buf[HAL_RPC_MAX_PKT_SIZE];
-} rpc_buffer_t;
-static rpc_buffer_t ibuf, obuf;
-
-const char *socket_name = HAL_CLIENT_DAEMON_DEFAULT_SOCKET_NAME;
-
-/* Set up an atexit handler to remove the filesystem entry for the unix domain
- * socket. This will trigger on error exits, but not on the "normal" SIGKILL.
- */
-void atexit_cleanup(void)
-{
- unlink(socket_name);
-}
-
-#ifdef DEBUG
-static void hexdump(uint8_t *buf, uint32_t len)
-{
- for (uint32_t i = 0; i < len; ++i)
- printf("%02x%c", buf[i], ((i & 0x07) == 0x07) ? '\n' : ' ');
- if ((len & 0x07) != 0)
- printf("\n");
-}
-#endif
-
-int main(int argc, char *argv[])
-{
- struct sockaddr_un name;
- int ret;
- int lsock;
- int dsock;
- int opt;
- const char *device = getenv(HAL_CLIENT_SERIAL_DEVICE_ENVVAR);
- const char *speed_ = getenv(HAL_CLIENT_SERIAL_SPEED_ENVVAR);
- uint32_t speed = HAL_CLIENT_SERIAL_DEFAULT_SPEED;
-
- if (device == NULL)
- device = HAL_CLIENT_SERIAL_DEFAULT_DEVICE;
-
- if (speed_ != NULL)
- speed = (uint32_t) strtoul(speed_, NULL, 10);
-
- while ((opt = getopt(argc, argv, "hn:d:s:")) != -1) {
- switch (opt) {
- case 'h':
- printf(usage, argv[0]);
- exit(EXIT_SUCCESS);
- case 'n':
- socket_name = optarg;
- break;
- case 'd':
- device = optarg;
- break;
- case 's':
- speed = (uint32_t) strtoul(optarg, NULL, 10);
- switch (speed) {
- case 115200:
- case 921600:
- break;
- default:
- printf("invalid speed value %s\n", optarg);
- exit(EXIT_FAILURE);
- }
- break;
- default:
- printf(usage, argv[0]);
- exit(EXIT_FAILURE);
- }
- }
-
- if (atexit(atexit_cleanup) != 0) {
- perror("atexit");
- exit(EXIT_FAILURE);
- }
-
- if (hal_serial_init(device, speed) != HAL_OK)
- exit(EXIT_FAILURE);
-
- int serial_fd = hal_serial_get_fd();
- poll_add(serial_fd);
-
- /* Remove the filesystem entry for the unix domain socket. The usual way
- * to stop a daemon is SIGKILL, which we can't catch, so the file remains,
- * and will prevent us from binding the socket.
- *
- * XXX We should also scan the process table, to make sure the daemon
- * isn't already running.
- */
- unlink(socket_name);
-
- /* Create the listening socket.
- */
- lsock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
- if (lsock == -1) {
- perror("socket");
- exit(EXIT_FAILURE);
- }
- poll_add(lsock);
-
- /* For portability, clear the whole address structure, since some
- * implementations have additional (nonstandard) fields in the structure.
- */
- memset(&name, 0, sizeof(struct sockaddr_un));
-
- /* Bind the listening socket. On some platforms, we have to pass the "real"
- * (number of bytes in use) length of the sockaddr_un to get the name bound
- * correctly, so use the SUN_LEN() macro to calculate that.
- */
- name.sun_family = AF_UNIX;
- strncpy(name.sun_path, socket_name, sizeof(name.sun_path) - 1);
- ret = bind(lsock, (const struct sockaddr *) &name, SUN_LEN(&name));
- if (ret == -1) {
- perror("bind");
- exit(EXIT_FAILURE);
- }
-
- /* Prepare to accept connections.
- */
- ret = listen(lsock, 20);
- if (ret == -1) {
- perror("listen");
- exit(EXIT_FAILURE);
- }
-
- /* The main loop.
- */
- for (;;) {
-
- /* Blocking poll on all descriptors of interest.
- */
- ret = poll(pollfds, nfds, -1);
- if (ret == -1) {
- perror("poll");
- exit(EXIT_FAILURE);
- }
-
- for (nfds_t i = 0; i < nfds; ++i) {
- if (pollfds[i].revents != 0) {
- /* XXX POLLERR|POLLHUP|POLLNVAL */
-
- /* serial port */
- if (pollfds[i].fd == serial_fd) {
- int complete;
- hal_slip_recv_char(ibuf.buf, &ibuf.len, sizeof(ibuf.buf), &complete);
- if (complete) {
-#ifdef DEBUG
- printf("serial port received response:\n");
- hexdump(ibuf.buf, ibuf.len);
-#endif
- /* We've got a complete rpc response packet. */
- const uint8_t *bufptr = ibuf.buf + 4;
- const uint8_t * const limit = ibuf.buf + ibuf.len;
- uint32_t sock;
- /* Second word of the response is the client ID. */
- hal_xdr_decode_int(&bufptr, limit, &sock);
- /* Pass response on to the client that requested it. */
- send(sock, ibuf.buf, ibuf.len, 0);
- /* Reinitialize the receive buffer. */
- memset(&ibuf, 0, sizeof(ibuf));
- }
- }
-
- /* listening socket */
- else if (pollfds[i].fd == lsock) {
- /* Accept incoming connection. */
- dsock = accept(lsock, NULL, NULL);
- if (ret == -1) {
- perror("accept");
- exit(EXIT_FAILURE);
- }
- poll_add(dsock);
-#ifdef DEBUG
- printf("listening socket accept data socket %d\n", dsock);
-#endif
- }
-
- /* client data socket */
- else {
- const uint8_t * const limit = obuf.buf + HAL_RPC_MAX_PKT_SIZE;
- /* Get the client's rpc request packet. */
- obuf.len = recv(pollfds[i].fd, obuf.buf, HAL_RPC_MAX_PKT_SIZE, 0);
-#ifdef DEBUG
- printf("data socket %d received request:\n", pollfds[i].fd);
- hexdump(obuf.buf, obuf.len);
-#endif
-
- /* Fill in the client handle arg - first field after opcode. */
- uint8_t *bufptr = obuf.buf + 4;
- hal_xdr_encode_int(&bufptr, limit, pollfds[i].fd);
-
- if (obuf.len > 0) {
-#ifdef DEBUG
- printf("passing to serial port:\n");
- hexdump(obuf.buf, obuf.len);
-#endif
- /* Pass it on to the serial port. */
- hal_slip_send(obuf.buf, obuf.len);
- }
- else {
-#ifdef DEBUG
- printf("closing data socket\n");
-#endif
- /* Client has closed the socket. */
- close(pollfds[i].fd);
- poll_remove(pollfds[i].fd);
- }
- /* Reinitialize the transmit buffer. */
- memset(&obuf, 0, sizeof(obuf));
- }
- }
- }
- }
-
- /*NOTREACHED*/
- exit(EXIT_SUCCESS);
-}