source: Evidence/Bridge.cc@ 229

Last change on this file since 229 was 229, checked in by ogrimm, 16 years ago
Config requests non-blocking if not made from main thread, adapted all servers to GetConfig() returning std::string, workaround for erroneous SERVICE_LIST
File size: 5.8 KB
Line 
1/********************************************************************\
2
3 Bridge between two networks
4
5 Subscription to top-level server list DIS_DNS/SERVER_LIST not via
6 AddService() ensures AddService() only called from infoHandler(),
7 thus serialized by DIM and no Mutex is necessary.
8
9 Remote procedure calls are bridged through their underlying services
10 and commands.
11
12 Oliver Grimm, June 2010
13
14\********************************************************************/
15
16#define SERVER_NAME "Bridge"
17#include "Evidence.h"
18
19#include <string>
20#include <vector>
21
22const int DEFAULT_PORT = 2505;
23
24using namespace std;
25
26// Class declaration
27class Bridge: public DimClient, public EvidenceServer {
28
29 struct Item {
30 DimCommand *Command;
31 DimStampedInfo *DataItem;
32 DimService *Service;
33 char *Data;
34 };
35 map<string, struct Item> Map;
36
37 DimInfo *ServerList;
38
39 void infoHandler();
40 void commandHandler();
41 public:
42 void AddService(string, char *, int);
43 void RemoveService(string);
44 void BugFix();
45
46 public:
47 Bridge(char *, int);
48 ~Bridge();
49};
50
51// Constructor
52Bridge::Bridge(char *Name, int Port): EvidenceServer(SERVER_NAME) {
53
54 // Set primary DIM network to subscribe from
55 DimClient::setDnsNode(Name, Port);
56
57 // Subsribe to top-level server list
58 ServerList = new DimInfo((char *) "DIS_DNS/SERVER_LIST", NO_LINK, this);
59}
60
61
62// Destructor: Delete all subscriptions and services
63Bridge::~Bridge() {
64
65 while (Map.size() != 0) RemoveService((*Map.begin()).first);
66 delete ServerList;
67}
68
69
70// Service subscription and repeating
71void Bridge::infoHandler() {
72
73 DimInfo *I = getInfo();
74
75 // Check if service available
76 if (!ServiceOK(I)) return;
77
78 // If service is DIS_DNS/SERVER_LIST, subscribe to all SERVICE_LIST services
79 if (strcmp(I->getName(), "DIS_DNS/SERVER_LIST") == 0) {
80 printf("DIS_DNS/SERVER_LIST: '%s'\n", I->getString());
81 char *Token = strtok(I->getString(), "+-!@");
82 while (Token != NULL) {
83 if (*I->getString() == '-' || *I->getString() == '!') {
84 RemoveService(string(Token)+"/SERVICE_LIST");
85 }
86 else AddService(string(Token)+"/SERVICE_LIST", (char *) "C", DimSERVICE);
87
88 // Skip server IP address and process ID
89 Token = strtok(NULL, "|");
90 Token = strtok(NULL, "@");
91 }
92 return;
93 }
94
95 // If service is SERVICE_LIST, scan and subscribe/unsubscribe to services
96 if (strstr(I->getName(), "/SERVICE_LIST") != NULL) {
97
98 // Bug fix for empty SERVICE_LIST
99 if (strlen(I->getString()) == 0) {
100 string Tmp(I->getName());
101 RemoveService(I->getName());
102 AddService(Tmp.c_str(), (char *) "C", DimSERVICE);
103 return;
104 }
105
106 char *Format, *Name = strtok(I->getString(), "+-!|");
107 while (Name != NULL) {
108 if ((Format = strtok(NULL, "\n")) != NULL) {
109 // Check if service added or removed/unavailable
110 if (*I->getString() == '-' || *I->getString() == '!') {
111 if (strstr(Format, "|RPC") != NULL) {
112 RemoveService(string(Name)+"/RpcIn");
113 RemoveService(string(Name)+"/RpcOut");
114 }
115 else RemoveService(Name);
116 }
117 else {
118 // Determine type of service
119 if (strstr(Format, "|CMD") != NULL) {
120 *(strstr(Format, "|CMD")) = '\0';
121 AddService(Name, Format, DimCOMMAND);
122 }
123 else if (strstr(Format, "|RPC") != NULL) {
124 *(strstr(Format, "|RPC")) = '\0';
125 if (strchr(Format, ',') != NULL) {
126 *strchr(Format, ',') = '\0';
127 AddService(string(Name)+"/RpcIn", Format, DimCOMMAND);
128 AddService(string(Name)+"/RpcOut", Format+strlen(Format)+1, DimSERVICE);
129 }
130
131 }
132 else {
133 Format[strlen(Format)-1] = '\0';
134 AddService(Name, Format, DimSERVICE);
135 }
136 }
137 }
138 Name = strtok(NULL, "|");
139 }
140 return;
141 }
142
143 // Check if service known and repeat to secondary DNS
144 if (Map.count(I->getName()) == 0) return;
145
146 // Copy service data
147 delete[] Map[I->getName()].Data;
148 Map[I->getName()].Data = new char [I->getSize()];
149 memcpy(Map[I->getName()].Data, I->getData(), I->getSize());
150
151 // Set new service properties and update service
152 Map[I->getName()].Service->setQuality(I->getQuality());
153 Map[I->getName()].Service->setTimestamp(I->getTimestamp(), I->getTimestampMillisecs());
154 Map[I->getName()].Service->updateService(Map[I->getName()].Data, I->getSize());
155}
156
157
158// Command repeating
159void Bridge::commandHandler() {
160
161 sendCommandNB(getCommand()->getName(), getCommand()->getData(), getCommand()->getSize());
162}
163
164
165// Service subscription
166void Bridge::AddService(string Name, char *Format, int Type) {
167
168 // Do not forward DIS_DNS and History services
169 if ((Name.find("DIS_DNS/") != string::npos) || (Name.find("History/") != string::npos)) return;
170
171 // Check if already subscribed to this service
172 if (Map.count(Name) != 0) return;
173
174 // Create subscription and service to secondary DNS or new command
175 Map[Name].Command = NULL;
176 Map[Name].DataItem = NULL;
177 Map[Name].Service = NULL;
178 Map[Name].Data = NULL;
179
180 if (Type == DimSERVICE) {
181 Map[Name].Service = new DimService(Name.c_str(), (char *) Format, Map[Name].Data, 0);
182 Map[Name].DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
183 }
184 else if (Type == DimCOMMAND) Map[Name].Command = new DimCommand(Name.c_str(), Format, this);
185}
186
187
188// Remove service from watch list (unused pointer are NULL)
189void Bridge::RemoveService(string Name) {
190
191 // Check if actually subscribed to service
192 if (Map.count(Name) == 0) return;
193
194 delete Map[Name].DataItem;
195 delete Map[Name].Service;
196 delete[] Map[Name].Data;
197 delete Map[Name].Command;
198
199 Map.erase(Name);
200}
201
202
203// Main program
204int main(int argc, char *argv[]) {
205
206 // Check command line argument
207 if (argc == 1) {
208 printf("Usage: %s <address of primary DNS> [port] (default port %d)\n", argv[0], DEFAULT_PORT);
209 exit(EXIT_FAILURE);
210 }
211
212 // Static ensures calling of destructor by exit()
213 static Bridge Class(argv[1], argc>2 ? atoi(argv[2]) : DEFAULT_PORT);
214
215 // Sleep until signal caught
216 while (!Class.ExitRequest) pause();
217}
Note: See TracBrowser for help on using the repository browser.