2014-07-14 11:49:44 +00:00
|
|
|
/** Nodes.
|
2014-06-05 09:34:29 +00:00
|
|
|
*
|
|
|
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
|
|
|
* @copyright 2014, Institute for Automation of Complex Power Systems, EONERC
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
#include "node.h"
|
2014-06-05 09:34:56 +00:00
|
|
|
#include "cfg.h"
|
2014-06-05 09:34:29 +00:00
|
|
|
#include "utils.h"
|
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
/* Node types */
|
|
|
|
#include "socket.h"
|
|
|
|
#include "gtfpga.h"
|
|
|
|
#include "opal.h"
|
|
|
|
|
|
|
|
#define VTABLE(type, name, fnc) { type, name, config_parse_ ## fnc, \
|
|
|
|
fnc ## _print, \
|
|
|
|
fnc ## _open, \
|
|
|
|
fnc ## _close, \
|
|
|
|
fnc ## _read, \
|
|
|
|
fnc ## _write }
|
|
|
|
|
|
|
|
/** Vtable for virtual node sub types */
|
|
|
|
static const struct node_vtable vtables[] = {
|
2015-03-12 22:56:58 +01:00
|
|
|
#ifdef ENABLE_OPAL_ASYNC
|
2015-03-17 22:46:46 +01:00
|
|
|
VTABLE(OPAL_ASYNC, "opal", opal),
|
2015-03-12 22:56:58 +01:00
|
|
|
#endif
|
2014-12-05 12:39:52 +01:00
|
|
|
VTABLE(IEEE_802_3, "ieee802.3", socket),
|
|
|
|
VTABLE(IP, "ip", socket),
|
|
|
|
VTABLE(UDP, "udp", socket),
|
|
|
|
VTABLE(TCP, "tcp", socket),
|
2015-03-12 22:56:58 +01:00
|
|
|
VTABLE(TCPD, "tcpd", socket)
|
2014-12-05 12:39:52 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Linked list of nodes */
|
|
|
|
struct node *nodes;
|
|
|
|
|
|
|
|
struct node * node_lookup_name(const char *str, struct node *nodes)
|
2014-06-05 09:34:56 +00:00
|
|
|
{
|
2014-12-05 12:39:52 +01:00
|
|
|
for (struct node *n = nodes; n; n = n->next) {
|
|
|
|
if (!strcmp(str, n->name))
|
|
|
|
return n;
|
|
|
|
}
|
2014-09-10 12:22:15 +00:00
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
return NULL;
|
2014-06-05 09:34:35 +00:00
|
|
|
}
|
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
struct node_vtable const * node_lookup_vtable(const char *str)
|
2014-06-05 09:34:29 +00:00
|
|
|
{
|
2014-12-05 12:39:52 +01:00
|
|
|
for (int i = 0; i < ARRAY_LEN(vtables); i++) {
|
|
|
|
if (!strcmp(vtables[i].name, str))
|
|
|
|
return &vtables[i];
|
|
|
|
}
|
2014-06-25 01:53:37 +00:00
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
return NULL;
|
2014-06-05 09:34:29 +00:00
|
|
|
}
|
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
int node_start(struct node *n)
|
2014-06-05 09:34:29 +00:00
|
|
|
{
|
2015-03-18 16:16:44 +01:00
|
|
|
if (!n->refcnt) {
|
|
|
|
warn("Node '%s' is unused. Skipping...", n->name);
|
2015-01-20 13:52:32 +00:00
|
|
|
return -1;
|
2015-03-18 16:16:44 +01:00
|
|
|
}
|
2014-12-05 12:39:52 +01:00
|
|
|
|
|
|
|
char str[256];
|
|
|
|
node_print(n, str, sizeof(str));
|
|
|
|
|
|
|
|
debug(1, "Starting node '%s' of type '%s' (%s)", n->name, n->vt->name, str);
|
|
|
|
|
|
|
|
{ INDENT
|
2015-01-20 13:52:32 +00:00
|
|
|
return n->vt->open(n);
|
2014-06-05 09:34:56 +00:00
|
|
|
}
|
2014-12-05 12:39:52 +01:00
|
|
|
}
|
2014-06-05 09:34:29 +00:00
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
int node_start_defer(struct node *n)
|
|
|
|
{
|
2014-12-09 17:19:07 +00:00
|
|
|
int ret;
|
2014-12-05 12:39:52 +01:00
|
|
|
|
2014-12-09 17:19:07 +00:00
|
|
|
if (node_type(n) == TCPD) {
|
|
|
|
info("Wait for incoming TCP connection from node '%s'...", n->name);
|
|
|
|
|
|
|
|
ret = listen(n->socket->sd2, 1);
|
|
|
|
if (ret < 0)
|
|
|
|
serror("Failed to listen on socket for node '%s'", n->name);
|
|
|
|
|
|
|
|
ret = accept(n->socket->sd2, NULL, NULL);
|
|
|
|
if (ret < 0)
|
|
|
|
serror("Failed to accept on socket for node '%s'", n->name);
|
|
|
|
|
|
|
|
n->socket->sd = ret;
|
2014-12-05 12:39:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int node_stop(struct node *n)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
info("Stopping node '%s'", n->name);
|
|
|
|
|
|
|
|
{ INDENT
|
|
|
|
ret = n->vt->close(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2014-06-05 09:34:29 +00:00
|
|
|
}
|
2015-03-18 16:18:10 +01:00
|
|
|
|
|
|
|
int node_reverse(struct node *n)
|
|
|
|
{
|
|
|
|
switch (n->vt->type) {
|
|
|
|
case IEEE_802_3:
|
|
|
|
case IP:
|
|
|
|
case UDP:
|
|
|
|
case TCP:
|
|
|
|
SWAP(n->socket->remote, n->socket->local);
|
|
|
|
break;
|
|
|
|
default: { }
|
|
|
|
}
|
|
|
|
return n->vt->open == socket_open;
|
|
|
|
}
|