From e9cff619c13c2490471b6144c8d958061215bef6 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 21 Jan 2022 20:46:40 +0000 Subject: [PATCH] MEDIUM: da: new optional data file download scheduler service. New specialized service to daily handle the update of download file without interruption of service and to be preemptively started before HAProxy. It consists on a standalone utility which shared a memory block with the DeviceAtlas module which handles the JSON data file update on a daily basis. Signed-off-by: David Carlier --- addons/deviceatlas/Makefile | 48 +++++++++ addons/deviceatlas/dadwsch.c | 195 +++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 addons/deviceatlas/Makefile create mode 100644 addons/deviceatlas/dadwsch.c diff --git a/addons/deviceatlas/Makefile b/addons/deviceatlas/Makefile new file mode 100644 index 000000000..fbcffca56 --- /dev/null +++ b/addons/deviceatlas/Makefile @@ -0,0 +1,48 @@ +# DEVICEATLAS_SRC : DeviceAtlas API source root path + + +OS := $(shell uname -s) +OBJS := dadwsch.o +CFLAGS := -g -O2 +LDFLAGS := + +CURL_CONFIG := curl-config +CURLDIR := $(shell $(CURL_CONFIG) --prefix 2>/dev/null || echo /usr/local) +CURL_INC := $(CURLDIR)/include +CURL_LIB := $(CURLDIR)/lib +CURL_LDFLAGS := $(shell $(CURL_CONFIG) --libs 2>/dev/null || echo -L /usr/local/lib -lcurl) + +PCRE2_CONFIG := pcre2-config +PCRE2DIR := $(shell $(PCRE2_CONFIG) --prefix 2>/dev/null || echo /usr/local) +PCRE2_INC := $(PCRE2DIR)/include +PCRE2_LIB := $(PCRE2DIR)/lib +PCRE2_LDFLAGS := $(shell $(PCRE2_CONFIG) --libs8 2>/dev/null || echo /usr/local) + +ifeq ($(DEVICEATLAS_SRC),) +dadwsch: dadwsch.c + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +LDFLAGS += -lda +else +DEVICEATLAS_INC = $(DEVICEATLAS_SRC) +DEVICEATLAS_LIB = $(DEVICEATLAS_SRC) +CFLAGS += -DDA_REGEX_HDR=\"dac_pcre2.c\" -DDA_REGEX_TAG=2 +CFLAGS += -DMOBI_CURL -DMOBI_CURLSSET -DMOBI_GZ -DMOBI_ZIP +CFLAGS += -I$(DEVICEATLAS_INC) -I$(CURL_INC) -I$(PCRE2DIR) +LDFLAGS += $(CURL_LDFLAGS) $(PCRE2_LDFLAGS) -lz -lzip -lpthread + +dadwsch: dadwsch.c $(DEVICEATLAS_SRC)/dac.c $(DEVICEATLAS_SRC)/dasch.c $(DEVICEATLAS_SRC)/dadwarc.c $(DEVICEATLAS_SRC)/dadwcom.c $(DEVICEATLAS_SRC)/dadwcurl.c $(DEVICEATLAS_SRC)/json.c $(DEVICEATLAS_SRC)/Os/daunix.c + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) +endif + +ifeq ($(OS), Linux) +LDFLAGS += -lrt +endif +ifeq ($(OS), SunOS) +LDFLAGS += -lrt +endif + +clean: + rm -f *.o + rm -f $(DEVICEATLAS_LIB)*.o + rm -f dadwsch diff --git a/addons/deviceatlas/dadwsch.c b/addons/deviceatlas/dadwsch.c new file mode 100644 index 000000000..e35566a3f --- /dev/null +++ b/addons/deviceatlas/dadwsch.c @@ -0,0 +1,195 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ATLASTOKSZ PATH_MAX +#define ATLASMAPNM "/hapdeviceatlas" + +const char *__pgname; + +static struct { + da_dwatlas_t o; + int ofd; + void* atlasmap; +} global_deviceatlassch = { + .ofd = -1, + .atlasmap = NULL +}; + + +void usage(void) +{ + fprintf(stderr, "%s -u download URL [-d hour (in H:M:S format) current hour by default] [-p path for the downloaded file, /tmp by default]\n", __pgname); + exit(EXIT_FAILURE); +} + +static size_t jsonread(void *ctx, size_t count, char *buf) +{ + return fread(buf, 1, count, ctx); +} + +static da_status_t jsonseek(void *ctx, off_t pos) +{ + return fseek(ctx, pos, SEEK_SET) != -1 ? DA_OK : DA_SYS; +} + +static void dadwlog(dw_config_t cfg, const char* msg) +{ + time_t now = time(NULL); + char buf[26] = {0}; + ctime_r(&now, buf); + buf[24] = 0; + fprintf(stderr, "%s: %s\n", buf, msg); +} + +static dw_status_t dadwnot(void *a, dw_config_t *cfg) +{ + da_dwatlas_t *o = (da_dwatlas_t *)a; + if (!o) + return DW_ERR; + char *e; + char jsondbuf[26] = {0}, buf[26] = {0}, atlasp[ATLASTOKSZ] = {0}; + time_t now = time(NULL); + time_t jsond; + int fd = -1; + (void)a; + jsond = da_getdatacreation(&o->atlas); + dwgetfinalp(o->dcfg.info, atlasp, sizeof(atlasp)); + ctime_r(&jsond, jsondbuf); + ctime_r(&now, buf); + jsondbuf[24] = 0; + buf[24] = 0; + + printf("%s: data file generated on `%s`\n", buf, jsondbuf); + int val = 1; + unsigned char *ptr = (unsigned char *)global_deviceatlassch.atlasmap; + memset(ptr, 0, sizeof(atlasp)); + strcpy(ptr, atlasp); + return DW_OK; +} + +static da_status_t dadwinit(void) +{ + if ((global_deviceatlassch.ofd = shm_open(ATLASMAPNM, O_RDWR | O_CREAT, 0660)) == -1) { + fprintf(stderr, "%s\n", strerror(errno)); + return DA_SYS; + } + + if (ftruncate(global_deviceatlassch.ofd, ATLASTOKSZ) == -1) { + close(global_deviceatlassch.ofd); + return DA_SYS; + } + lseek(global_deviceatlassch.ofd, 0, SEEK_SET); + global_deviceatlassch.atlasmap = mmap(0, ATLASTOKSZ, PROT_READ | PROT_WRITE, MAP_SHARED, global_deviceatlassch.ofd, 0); + if (global_deviceatlassch.atlasmap == MAP_FAILED) { + fprintf(stderr, "%s\n", strerror(errno)); + return DA_SYS; + } else { + memset(global_deviceatlassch.atlasmap, 0, ATLASTOKSZ); + return DA_OK; + } +} + +static void dadwexit(int sig __attribute__((unused)), siginfo_t *s __attribute__((unused)), void *ctx __attribute__((unused))) +{ + ssize_t w; + + fprintf(stderr, "%s: exit\n", __pgname); + dw_daatlas_close(&global_deviceatlassch.o); + da_fini(); + munmap(global_deviceatlassch.atlasmap, ATLASTOKSZ); + close(global_deviceatlassch.ofd); + shm_unlink(ATLASMAPNM); + exit(EXIT_SUCCESS); +} + +int main(int argc, char **argv) +{ + const char *opts = "u:p:d:h"; + bool dset = false; + size_t i; + int ch; + + da_property_decl_t extraprops[1] = { + { 0, 0 } + }; + + __pgname = argv[0]; + + dw_df_dainit_fn = curldwinit; + dw_df_dacleanup_fn = curldwcleanup; + + da_init(); + memset(&global_deviceatlassch.o.dcfg, 0, sizeof(global_deviceatlassch.o.dcfg)); + while ((ch = getopt(argc, argv, opts)) != -1) { + switch (ch) { + case 'u': + global_deviceatlassch.o.dcfg.info.url = strdup(optarg); + break; + case 'p': + global_deviceatlassch.o.dcfg.info.path = strdup(optarg); + break; + case 'd': + if (strptime(optarg, "%H:%M:%S", &global_deviceatlassch.o.dcfg.info.rtm) != NULL) + dset = true; + else + usage(); + break; + case 'h': + default: + usage(); + } + } + + if (!dset) { + time_t now = time(NULL); + struct tm *cnow = gmtime(&now); + memcpy(&global_deviceatlassch.o.dcfg.info.rtm, cnow, offsetof(struct tm, tm_mday)); + } + + if (!global_deviceatlassch.o.dcfg.info.url) + usage(); + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_SIGINFO | SA_RESTART; + sa.sa_sigaction = dadwexit; + + global_deviceatlassch.o.dcfg.info.datatm = 1; + global_deviceatlassch.o.dcfg.info.chksum = 1; + global_deviceatlassch.o.dcfg.info.reload = 1; + global_deviceatlassch.o.dcfg.info.tobin = 1; + global_deviceatlassch.o.dcfg.ep = extraprops; + global_deviceatlassch.o.dcfg.dwproc = curldwproc; + global_deviceatlassch.o.dcfg.dwextract = dadwextract; + global_deviceatlassch.o.dcfg.lptr = (void *)stderr; + global_deviceatlassch.o.dcfg.dwlog = &dadwlog; + global_deviceatlassch.o.dcfg.dwnotify_n = &dadwnot; + global_deviceatlassch.o.rfn = jsonread; + global_deviceatlassch.o.posfn = jsonseek; + + if (dadwinit() != DA_OK) { + fprintf(stderr, "%s init failed\n", __pgname); + exit(EXIT_FAILURE); + } + + if (da_atlas_open_schedule(&global_deviceatlassch.o) != DA_OK) { + fprintf(stderr, "%s scheduling failed\n", __pgname); + exit(EXIT_FAILURE); + } + + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + while (true) sleep(1); + + return 0; +}