diff options
-rw-r--r-- | Makefile | 71 | ||||
-rw-r--r-- | daemon.c | 553 | ||||
-rw-r--r-- | log.c | 109 | ||||
-rw-r--r-- | log.h | 37 | ||||
-rw-r--r-- | misc.c | 65 | ||||
-rw-r--r-- | misc.h | 58 | ||||
-rw-r--r-- | platform.h | 35 |
7 files changed, 928 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1be6b8e --- /dev/null +++ b/Makefile @@ -0,0 +1,71 @@ +## Copyright (C) 2014-2016 +## Olivier Gayot <ogayot@baylibre.com> +## Bartosz Golaszewski <bgolaszewski@baylibre.com> +## Olivier Gayot <olivier.gayot@sigexec.com> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License along +## with this program; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +CC = $(CROSS_COMPILE)gcc +USERFLAGS = +CFLAGS += -I./include -I/usr/local/include -W -Wall -Wextra +CFLAGS += -D_GNU_SOURCE $(USERFLAGS) +LDFLAGS += -L./lib -L/usr/local/lib -lwebsockets -lconfig $(USERFLAGS) +PROGNAME = caod +OBJS = daemon.o log.o misc.o + +ifdef DEBUG +CFLAGS += -g$(DEBUG) -D CONFIG_DEBUG -O0 +else +CFLAGS += -O2 +endif + +all: $(PROGNAME) + +$(PROGNAME): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) + +clean: + $(RM) $(OBJS) + $(RM) $(PROGNAME) + +mrproper: clean + +help: + @echo "CAO daemon Makefile targets:" + @echo + @echo "Build:" + @echo " all\t\t- build all cao objects, libraries and executables," + @echo + @echo "Cleaning:" + @echo " clean\t\t- remove caod objects and executables," + @echo " libclean\t- remove external library build files," + @echo " mrproper\t- clean everything," + @echo + @echo "Makefile variables:" + @echo " CROSS_COMPILE\t- cross-toolchain prefix," + @echo " ARCH\t\t- build architecture," + @echo " DEBUG\t\t- compile additional debug messages and pass the -g" + @echo " \t\t flag to gcc, you can also specify a level for said flag," + @echo + +.PHONY: all clean mrproper help +.PRECIOUS: %.c +.SUFFIXES: +.SUFFIXES: .o .c +.DEFAULT_GOAL := +.DEFAULT_GOAL := all + +.c.o: + $(CC) -c -o $*.o $(CFLAGS) $(DEBUGFLAGS) $*.c diff --git a/daemon.c b/daemon.c new file mode 100644 index 0000000..dc4cc5a --- /dev/null +++ b/daemon.c @@ -0,0 +1,553 @@ +/* + * Copyright (C) 2014 + * Olivier Gayot <ogayot@baylibre.com> + * Bartosz Golaszewski <bgolaszewski@baylibre.com> + * Olivier Gayot <olivier.gayot@sigexec.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This software is based on Andy Green's test-server available here + * http://git.libwebsockets.org/cgi-bin/cgit/libwebsockets/ + */ + +#include <libwebsockets.h> + +#include <stdio.h> +#include <stdbool.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sysexits.h> +#include <getopt.h> +#include <limits.h> +#include <errno.h> +#include <sys/wait.h> +#include <stdarg.h> +#include <time.h> + +#include "misc.h" +#include "log.h" + +#define DEFAULT_PORT 8080 +#define DEFAULT_PAGES_DIR "/var/www/" +#define DEFAULT_HOMEPAGE "index.html" +#define DEFAULT_CONFIG_FILE "/etc/caod/config.cfg" +#define DEFAULT_SAMPLING_RATE 1 /* one ms */ + +#define DEFAULT_CLIENT_REFRESH_RATE 100 /* in ms */ + +#define USER_DATA_BUFSIZE 1048576 + +struct per_session_data_cao_prot { + bool handshake_ok: 1; + + /* + * libwebsockets requires a padding before and after the buffer. + * Since we want to be able to use sizeof(buffer) anyway, we will + * make a packed structure containing the buffer and its padding. + */ + struct { + unsigned char _pre_padding[LWS_SEND_BUFFER_PRE_PADDING]; + unsigned char buffer[USER_DATA_BUFSIZE]; + unsigned char _post_padding[LWS_SEND_BUFFER_POST_PADDING]; + }; + + unsigned short len; + + struct { + unsigned short sps; /* snaps per second */ + } params; +}; + +struct mime_type { + char *ext; + size_t ext_len; + char *type; +}; + +struct pws_event { + bool set; + int probe_id; + int state; +}; + +static bool daemonize_g = false; +static int verbosity_g = 0; +static volatile bool asked_to_quit_g = false; +static const char *pages_dir_g = DEFAULT_PAGES_DIR; +static const char *homepage_g = DEFAULT_HOMEPAGE; +static const char *config_file_g = DEFAULT_CONFIG_FILE; +static struct lws_context *context_g; + +#define MIME_EXT_ARGS(_ext) _ext, (sizeof(_ext) - 1) + +static struct mime_type mimes_g[] = { + { MIME_EXT_ARGS(".ico"), "image/x-icon", }, + { MIME_EXT_ARGS(".png"), "image/png" }, + { MIME_EXT_ARGS(".html"), "text/html" }, + { MIME_EXT_ARGS(".css"), "text/css" }, + { MIME_EXT_ARGS(".js"), "application/javascript" }, +#define SHORTEST_MIME_EXT 3 /* size of the shortest extension (incl. the dot) */ +}; + +#undef MIME_EXT_ARGS + +/* return a string describing the mime type if supported, otherwise NULL */ +static const char *get_mimetype(const char *filename) +{ + int n, i; + + n = strlen(filename); + if (n < SHORTEST_MIME_EXT + 1) + return NULL; + + for (i = 0; i < countof(mimes_g); ++i) { + const struct mime_type *mimep = &mimes_g[i]; + + if (!strcmp(&filename[n - mimep->ext_len], mimep->ext)) { + return mimep->type; + } + } + + return NULL; +} + +static int callback_http_only(struct lws *wsi, + enum lws_callback_reasons reason, void *user UNUSED_PARAM, + void *in, size_t len) +{ + const char *mimetype; + static char path[PATH_MAX]; + static char real_path[PATH_MAX]; + size_t path_len; + size_t def_path_len; + + switch (reason) { + case LWS_CALLBACK_HTTP: + + if (len < 1) { + lws_return_http_status(wsi, + HTTP_STATUS_BAD_REQUEST, NULL); + return -1; + } + + /* serve either the specified page or the default one */ + if (strcmp(in, "/") != 0) { + snprintf(path, sizeof(path), "%s/%s", pages_dir_g, + (char *)in); + } else { + snprintf(path, sizeof(path), "%s/%s", pages_dir_g, + homepage_g); + } + + /* + * avoid a security issue: "jail" inside pages_dir_g + * XXX: beware, a race condition might occur between realpath() and + * open() which is called by lwss_serve_http_file() + */ + if (realpath(path, real_path) == NULL) { + lws_return_http_status(wsi, + HTTP_STATUS_NOT_FOUND, NULL); + return -1; + } + path_len = strlen(real_path); + def_path_len = strlen(pages_dir_g); + if (path_len <= def_path_len || + strncmp(real_path, pages_dir_g, def_path_len) != 0) + { + lws_return_http_status(wsi, + HTTP_STATUS_FORBIDDEN, NULL); + + return -1; + } + + /* check if the mimetype if supported */ + mimetype = get_mimetype(path); + if (mimetype == NULL) { + caod_err("Unknown mimetype for %s", path); + lws_return_http_status(wsi, + HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); + + return -1; + } + + if (lws_serve_http_file(wsi, path, mimetype, NULL, 0)) + { + /* + * close the socket if either an error occured or the file has + * been sent completely + */ + return -1; + } + + break; + case LWS_CALLBACK_HTTP_BODY: + break; + case LWS_CALLBACK_HTTP_BODY_COMPLETION: + break; + case LWS_CALLBACK_HTTP_FILE_COMPLETION: + break; + case LWS_CALLBACK_HTTP_WRITEABLE: + break; + case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: + break; + default: + break; + } + + return 0; +} + +static void set_shunt_vals(int *vals) +{ + FILE *shfd; + int numvals = 8; + int i; + FILE *chfd; + char channels[8]; + int hwind = 1; + ssize_t rd; + + chfd = fopen("/etc/caod/channels", "r"); + if (!chfd) + goto err; + + shfd = fopen("/etc/caod/shunt_vals", "w"); + if (!shfd) + goto err; + + for (i = 0; i < numvals; i++) { + if (vals[i] > 0) { + fprintf(shfd, "%d\n", vals[i]); + } + } + fclose(shfd); + + rd = fread(channels, 1, sizeof(channels), chfd); + if (rd != sizeof(channels)) { + goto err; + } + fclose(chfd); + + for (i = 0; i < numvals; i++) { + if (channels[i] == 'I') { + char cmd[256]; + + snprintf(cmd, sizeof(cmd), + "/root/cao-suite/scripts/cao_ctl.py set_shunt %d %d %d", + hwind, i+1, vals[i]); + caod_info("Executing: %s", cmd); + system(cmd); + hwind++; + } else if (channels[i] == 'T') { + hwind++; + } + } + + sync(); + + return; + +err: + caod_err("Error setting shunt values"); +} + +static int callback_cao_prot(struct lws *wsi UNUSED_PARAM, + enum lws_callback_reasons reason, + void *user, void *in UNUSED_PARAM, size_t len UNUSED_PARAM) +{ + struct per_session_data_cao_prot *user_data = user; + + switch (reason) { + case LWS_CALLBACK_ESTABLISHED: + user_data->params.sps = 0; + user_data->handshake_ok = false; + break; + case LWS_CALLBACK_CLOSED: + break; + case LWS_CALLBACK_SERVER_WRITEABLE: + break; + case LWS_CALLBACK_RECEIVE: + set_shunt_vals(in); + break; + case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: + break; + default: + break; + } + + return 0; +} + +static struct lws_context_creation_info info_g = { + .port = DEFAULT_PORT, + .iface = NULL, + /* list the protocols available */ + .protocols = (struct lws_protocols[]) { + { + .name = "http-only", /* name */ + .callback = callback_http_only, + .per_session_data_size = 0, + }, { + .name = "cao-prot", + .callback = callback_cao_prot, + .per_session_data_size = + sizeof(struct per_session_data_cao_prot), + }, { /* empty field needed at the end */ + .name = NULL, + .callback = NULL, + .per_session_data_size = 0, + }, + }, + .options = 0, +}; + +/* display an usage message and exit */ +NORETURN static void usage(const char *progname) +{ + fprintf(stderr, "Usage: %s [OPTIONS]\n" + "\n" + "-p - override the default port (%d),\n" + "-h - display this help and exit,\n" + "-d - fork in the background,\n" + "-v - increase verbosity (1-info, 2-debug),\n" + "-w - set the path to the WWW directory (default: '%s'),\n" + "-H - set the filename of the homepage in the www directory\n" + "-c - specify a custom path to the config file (default: '%s')," + " (default: '%s').\n", + progname, + DEFAULT_PORT, + DEFAULT_PAGES_DIR, + DEFAULT_HOMEPAGE, + DEFAULT_CONFIG_FILE); + + exit(EX_USAGE); +} + +static void errmsg_and_usage(const char *progname, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + vfprintf(stderr, fmt, va); + fprintf(stderr, "\n"); + va_end(va); + + usage(progname); +} + +/* + * search options passed to the program and handle them + * argc will be modified accordingly + * argv will be returned shifted accordingly + */ +static char **parse_opt(int *argc, char *argv[]) +{ + int opt; + char *errptr; + + while ((opt = getopt(*argc, argv, "v:hdp:w:H:c:")) != -1) { + switch (opt) { + case 'p': + /* change the default port */ + info_g.port = strtol(optarg, &errptr, 10); + + if (*errptr != '\0') { + usage(argv[0]); + } + + break; + case 'h': + /* display the help (and exit) */ + usage(argv[0]); + break; + case 'd': + /* fork on the background */ + daemonize_g = true; + break; + case 'v': + /* increase verbosity */ + if ((strcmp(optarg, "1") == 0) || (strcmp(optarg, "2") == 0)) + verbosity_g = atoi(optarg); + else + errmsg_and_usage(argv[0], "Invalid verbosity level\n"); + break; + case 'w': + if (optarg[0] != '/') + errmsg_and_usage(argv[0], + "Must specify an absolute path for -D\n"); + pages_dir_g = optarg; + break; + case 'H': + homepage_g = optarg; + break; + case 'c': + config_file_g = optarg; + break; + default: + /* noreturn */ + usage(argv[0]); + } + } + + *argc -= optind; + + return &(argv[optind]); +} + +static void handle_signal(int sig) +{ + switch (sig) { + case SIGINT: + case SIGTERM: + asked_to_quit_g = true; + break; + } +} + +static int callback_http_on_bug(struct lws *wsi, + enum lws_callback_reasons reason, + void *user UNUSED_PARAM, void *in UNUSED_PARAM, size_t len) +{ + char path[256]; + + memset(path, 0, sizeof(path)); + snprintf(path, sizeof(path), "%s/error.html", pages_dir_g); + + switch (reason) { + case LWS_CALLBACK_HTTP: + + if (len < 1) { + lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); + return -1; + } + + if (lws_serve_http_file(wsi, path, "text/html", NULL, 0)) { + /* + * close the socket if either an error occured or the file has + * been sent completely + */ + return -1; + } + + break; + default: + break; + } + + return 0; +} + +static struct lws_context_creation_info info_bug = { + .port = DEFAULT_PORT, + .iface = NULL, + /* list the protocols available */ + .protocols = (struct lws_protocols[]) { + { + .name = "http-only", /* name */ + .callback = callback_http_on_bug, + .per_session_data_size = 0, + }, { /* empty field needed at the end */ + .name = NULL, + .callback = NULL, + .per_session_data_size = 0, + }, + }, + .options = 0, +}; + +/* + * If an error happened - let this function run eternally to inform users + * about the bug via HTTP on default port. + */ +static void bug_on(void) +{ + struct lws_context *context; + + if ((context = lws_create_context(&info_bug)) == NULL) { + caod_err("lws init failed"); + abort(); + } + + caod_err("Entering bug_on state..."); + while (!asked_to_quit_g) { + if (lws_service(context, 5) < 0) { + caod_err("lws_service() returned with an error"); + } + } +} + +/* + * The general idea is to read the configuration and create the data model, + * then create a pipe and fork. The child process will then try to stick to + * the given sampling rate and perform the measurements on time, feeding all + * the results into the pipe, while the parent will read from it, store these + * values in a buffer and send them periodically to the client. + * + * The buffer size should be (client_refresh_rate / sampling_rate). The buffer + * is only allocated in the parent process, although both processes share + * the rest of the data model. + */ +int main(int argc, char *argv[]) +{ + const char *progname = argv[0]; + int ret = EXIT_SUCCESS; + int dbglvl; + + argv = parse_opt(&argc, argv); + /* XXX argc and argv have been shifted */ + + /* no argument are accepted for now on */ + if (argc > 0) { + usage(progname); + } + + if (daemonize_g && lws_daemonize("/tmp/.caod-lock") != 0) { + caod_err("failed to daemonize"); + return -1; + } + + caod_setup_logs(); + dbglvl = LLL_ERR | LLL_WARN | LLL_NOTICE; + + switch (verbosity_g) { + case 2: dbglvl |= LLL_DEBUG; /* Fall through. */ + case 1: dbglvl |= LLL_INFO; + } + + lws_set_log_level(dbglvl, &caod_log_hook); + + signal(SIGINT, &handle_signal); + signal(SIGTERM, &handle_signal); + + if ((context_g = lws_create_context(&info_g)) == NULL) { + caod_err("lws init failed"); + ret = EXIT_FAILURE; + return ret; + } + + while (!asked_to_quit_g) { + if (lws_service(context_g, 5) < 0) { + caod_err("lws_service() returned with an error"); + ret = EXIT_FAILURE; + break; + } + } + + lws_context_destroy(context_g); + + return ret; +} @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014-2016 + * Olivier Gayot <ogayot@baylibre.com> + * Bartosz Golaszewski <bgolaszewski@baylibre.com> + * Olivier Gayot <olivier.gayot@sigexec.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <libwebsockets.h> + +#include "log.h" + +#define PRINT_FROM_VA(STREAM, LVL, FMT) \ + do { \ + va_list va; \ + va_start(va, FMT); \ + fprintf(STREAM, "caod ["LVL"] PID: %d\t", getpid()); \ + vfprintf(STREAM, FMT, va); \ + fprintf(STREAM, "\n"); \ + va_end(va); \ + } while (0) + +static const char* const logpath = "/tmp/caod.log"; +static FILE* logfd; + +static void close_log(void) +{ + fclose(logfd); +} + +void caod_setup_logs(void) +{ + (void)unlink(logpath); + logfd = fopen(logpath, "w"); + if (logfd) + atexit(&close_log); +} + +void caod_info(const char *fmt, ...) +{ + PRINT_FROM_VA(stdout, "INFO", fmt); + if (logfd) { + PRINT_FROM_VA(logfd, "INFO", fmt); + } +} + +void caod_warn(const char *fmt, ...) +{ + PRINT_FROM_VA(stdout, "WARN", fmt); + if (logfd) { + PRINT_FROM_VA(logfd, "WARN", fmt); + } +} + +void caod_err(const char *fmt, ...) +{ + PRINT_FROM_VA(stdout, "ERR", fmt); + if (logfd) { + PRINT_FROM_VA(logfd, "ERR", fmt); + } +} + +void caod_log_hook(int level, const char *line) +{ + char buf[256]; + int last; + + memset(buf, 0, sizeof(buf)); + strncpy(buf, line, sizeof(buf)); + last = strlen(buf)-1; + if (buf[last] == '\n') { + buf[last] = '\0'; + } + + switch (level) { + case LLL_DEBUG: + case LLL_INFO: + case LLL_NOTICE: + caod_info("%s", buf); + break; + case LLL_WARN: + caod_warn("%s", buf); + break; + case LLL_ERR: + caod_err("%s", buf); + break; + default: + break; + } +} @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014-2016 + * Olivier Gayot <ogayot@baylibre.com> + * Bartosz Golaszewski <bgolaszewski@baylibre.com> + * Olivier Gayot <olivier.gayot@sigexec.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef LOG_H +#define LOG_H + +#include "platform.h" + +/* Message printing helpers. */ + +void caod_setup_logs(void); + +void caod_info(const char *fmt, ...) CAOD_PRINTF_FUNC(1, 2); +void caod_warn(const char *fmt, ...) CAOD_PRINTF_FUNC(1, 2); +void caod_err(const char *fmt, ...) CAOD_PRINTF_FUNC(1, 2); + +void caod_log_hook(int level, const char *line); + +#endif /* LOG_H */ @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014-2016 + * Olivier Gayot <ogayot@baylibre.com> + * Bartosz Golaszewski <bgolaszewski@baylibre.com> + * Olivier Gayot <olivier.gayot@sigexec.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/select.h> + +#include "misc.h" + +#define SELECT_INIT(FDSET, SOCK) \ + do { \ + FD_ZERO(&(FDSET)); \ + FD_SET((SOCK), &(FDSET)); \ + } while (0) + +#define SELECT_LOOP(RETVAL, CALL, TV) \ + do { \ + do { \ + (RETVAL) = (CALL); \ + if ((((RETVAL) < 0) && (errno != EINTR)) || (RETVAL > 0)) { \ + break; \ + } \ + } while ((TV)->tv_sec || (TV)->tv_usec); \ + } while(0) + +int caod_fd_wrready(int sock, struct timeval *tv) +{ + fd_set wr_set; + int r; + + SELECT_INIT(wr_set, sock); + SELECT_LOOP(r, select(sock+1, NULL, &wr_set, NULL, tv), tv); + + return r; +} + +int caod_fd_rdready(int sock, struct timeval *tv) +{ + fd_set rd_set; + int r; + + SELECT_INIT(rd_set, sock); + SELECT_LOOP(r, select(sock+1, &rd_set, NULL, NULL, tv), tv); + + return r; +} @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014-2016 + * Olivier Gayot <ogayot@baylibre.com> + * Bartosz Golaszewski <bgolaszewski@baylibre.com> + * Olivier Gayot <olivier.gayot@sigexec.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MISC_H +#define MISC_H + +#include <sys/time.h> + +#define ssizeof(_foo) ((signed long)(sizeof((_foo)))) +#define countof(_array) (ssizeof((_array)) / ssizeof((_array)[0])) + +#define unsafe_free(_ptr) free((_ptr)) +#define safe_free(_ptr) \ + do { \ + free((_ptr)); \ + (_ptr) = NULL; \ + } while (0) + +#ifdef CONFIG_DEBUG +#define IF_DEBUG(...) __VA_ARGS__ +#else +#define IF_DEBUG(...) +#endif + +#define TV_FMT "(%d.%d)" +#define TV_PRINT(TV) (int)(TV).tv_sec, (int)(TV).tv_usec + +/* + * Returns 1 if a file descriptor is ready for writing, 0 otherwise or -1 + * on error. + */ +int caod_fd_wrready(int sock, struct timeval *tv); + +/* + * Returns 1 if a file descriptor is ready for reading, 0 otherwise or -1 + * on error. + */ +int caod_fd_rdready(int sock, struct timeval *tv); + +#endif /* MISC_H */ diff --git a/platform.h b/platform.h new file mode 100644 index 0000000..0594c59 --- /dev/null +++ b/platform.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014-2016 + * Bartosz Golaszewski <bgolaszewski@baylibre.com> + * Olivier Gayot <olivier.gayot@sigexec.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef PLATFORM_H +#define PLATFORM_H + +#ifdef __GNUC__ +#define UNUSED_PARAM __attribute__((__unused__)) +#define NORETURN __attribute__((noreturn)) +#define CAOD_PRINTF_FUNC(FORMAT, PARAMS) \ + __attribute__((format(printf, FORMAT, PARAMS))) +#else +#define UNUSED_PARAM +#define NORETURN +#define CAOD_PRINTF_FUNC(FORMAT, PARAMS) +#endif + +#endif /* PLATFORM_H */ |