diff --git a/server/Makefile b/server/Makefile index 0ca0dab1c..dfb991649 100644 --- a/server/Makefile +++ b/server/Makefile @@ -1,7 +1,7 @@ TARGETS = server send random receive test # Common dependencies for all binaries -OBJS = socket.o if.o utils.o msg.o node.o cfg.o tc.o hooks.o list.o path.o hist.o +OBJS = if.o utils.o msg.o node.o cfg.o tc.o hooks.o list.o path.o hist.o socket.o file.o VPATH = src diff --git a/server/include/file.h b/server/include/file.h new file mode 100644 index 000000000..518b45988 --- /dev/null +++ b/server/include/file.h @@ -0,0 +1,41 @@ +/** Node type: File + * + * This file implements the file type for nodes. + * + * @author Steffen Vogel + * @copyright 2015, Institute for Automation of Complex Power Systems, EONERC + */ + +#ifndef _FILE_H_ +#define _FILE_H_ + +#include + +#include "node.h" + +struct file { + FILE *in; + FILE *out; + + const char *path_in; + const char *path_out; + + const char *mode; /**< The mode for fopen() which is used for the out file. */ + + double rate; /**< The sending rate. */ + int tfd; /**< Timer file descriptor. Blocks until 1/rate seconds are elapsed. */ +}; + +int file_print(struct node *n, char *buf, int len); + +int file_parse(config_setting_t *cfg, struct node *n); + +int file_open(struct node *n); + +int file_close(struct node *n); + +int file_read(struct node *n, struct msg *m); + +int file_write(struct node *n, struct msg *m); + +#endif /* _FILE_H_ */ \ No newline at end of file diff --git a/server/include/node.h b/server/include/node.h index d3c186504..066b58fe4 100644 --- a/server/include/node.h +++ b/server/include/node.h @@ -34,6 +34,7 @@ /** Node type: layer, protocol, listen/connect */ enum node_type { + LOG_FILE, /* File IO */ IEEE_802_3, /* BSD socket: AF_PACKET SOCK_DGRAM */ IP, /* BSD socket: AF_INET SOCK_RAW */ UDP, /* BSD socket: AF_INET SOCK_DGRAM */ @@ -77,6 +78,7 @@ struct node struct socket *socket; struct opal *opal; struct gtfpga *gtfpga; + struct file *file; }; /** A pointer to the libconfig object which instantiated this node */ diff --git a/server/src/file.c b/server/src/file.c new file mode 100644 index 000000000..216ec321c --- /dev/null +++ b/server/src/file.c @@ -0,0 +1,107 @@ +/** Node type: File + * + * This file implements the file type for nodes. + * + * @author Steffen Vogel + * @copyright 2015, Institute for Automation of Complex Power Systems, EONERC + */ + +#include +#include + +#include "file.h" +#include "utils.h" + +int file_print(struct node *n, char *buf, int len) +{ + struct file *f = n->file; + + return snprintf(buf, len, "in=%s, out=%s, mode=%s, rate=%f", + f->path_in, f->path_out, f->mode, f->rate); +} + +int file_parse(config_setting_t *cfg, struct node *n) +{ + struct file *f = alloc(sizeof(struct file)); + + config_setting_lookup_string(cfg, "in", &f->path_in); + config_setting_lookup_string(cfg, "out", &f->path_out); + + if (!config_setting_lookup_string(cfg, "mode", &f->mode)) + f->mode = "w+"; + + if (!config_setting_lookup_float(cfg, "rate", &f->rate)) + f->rate = 1; + + n->file = f; + + return 0; +} + +int file_open(struct node *n) +{ + struct file *f = n->file; + + if (f->path_in) { + f->in = fopen(f->path_in, "r"); + if (!f->in) + serror("Failed to open file for reading: '%s'", f->path_in); + + f->tfd = timerfd_create(CLOCK_MONOTONIC, 0); + if (f->tfd < 0) + serror("Failed to create timer"); + + struct itimerspec its = { + .it_interval = timespec_rate(f->rate), + .it_value = { 1, 0 } + }; + int ret = timerfd_settime(f->tfd, 0, &its, NULL); + if (ret) + serror("Failed to start timer"); + } + + if (f->path_out) { + f->out = fopen(f->path_out, f->mode); + if (!f->out) + serror("Failed to open file for writing: '%s'", f->path_out); + } + + return 0; +} + +int file_close(struct node *n) +{ + struct file *f = n->file; + + if (f->tfd) + close(f->tfd); + if (f->in) + fclose(f->in); + if (f->out) + fclose(f->out); + + return 0; +} + +int file_read(struct node *n, struct msg *m) +{ + struct file *f = n->file; + uint64_t runs; + + if (!f->in) + error("Can't read from file node!"); + + read(f->tfd, &runs, sizeof(runs)); /* blocking for 1/f->rate seconds */ + + return msg_fscan(f->in, m); +} + +int file_write(struct node *n, struct msg *m) +{ + struct file *f = n->file; + + if (!f->out) + error("Can't write to file node!"); + + return msg_fprint(f->out, m); +} \ No newline at end of file diff --git a/server/src/node.c b/server/src/node.c index 28a5204c8..7ad615eea 100644 --- a/server/src/node.c +++ b/server/src/node.c @@ -27,6 +27,7 @@ static const struct node_vtable vtables[] = { #ifdef ENABLE_OPAL_ASYNC VTABLE(OPAL_ASYNC, "opal", opal), #endif + VTABLE(LOG_FILE), "file", file), VTABLE(IEEE_802_3, "ieee802.3", socket), VTABLE(IP, "ip", socket), VTABLE(UDP, "udp", socket),