source: Evidence/Bridge.cc@ 254

Last change on this file since 254 was 253, checked in by ogrimm, 14 years ago
Added command ResetAlarm, Evidence servers now always safely translate a DIM string into a C string, added documentation, replaced several vectors my maps
File size: 7.2 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 Configuraton changes are automatically tracked through ConfigChanged()
13
14 Oliver Grimm, June 2010
15
16\********************************************************************/
17
18#define SERVER_NAME "Bridge"
19#include "Evidence.h"
20
21#include <string>
22#include <vector>
23#include <regex.h>
24
25const int DEFAULT_PORT = 2505;
26
27using namespace std;
28
29// Class declaration
30class Bridge: public DimClient, public EvidenceServer {
31
32 struct Item {
33 DimCommand *Command;
34 DimStampedInfo *DataItem;
35 DimService *Service;
36 char *Data;
37 };
38
39 map<string, struct Item> Map;
40 vector<regex_t> RegEx;
41 DimInfo *ServerList;
42
43 void infoHandler();
44 void commandHandler();
45 void AddService(string, char *, int);
46 void RemoveService(string);
47 void ConfigChanged();
48 void BugFix();
49 void Undo();
50
51 public:
52 Bridge(char *, int);
53 ~Bridge();
54};
55
56// Constructor
57Bridge::Bridge(char *Name, int Port): EvidenceServer(SERVER_NAME) {
58
59 // Set primary DIM network to subscribe from
60 DimClient::setDnsNode(Name, Port);
61
62 // Initialise and request notification of configuration changes
63 ServerList = NULL;
64 GetConfig("cmdallow", " ");
65 ActivateSignal(SIGUSR2);
66
67 ConfigChanged();
68}
69
70
71// Destructor
72Bridge::~Bridge() {
73
74 Undo();
75}
76
77
78// Undo: Delete all subscriptions and regular expressions
79void Bridge::Undo() {
80
81 while (Map.size() != 0) RemoveService((*Map.begin()).first);
82 delete ServerList;
83 for (int i=0; i<RegEx.size(); i++) regfree(&RegEx[i]);
84 RegEx.clear();
85}
86
87
88// Called by signal handler in case configuration changes and by constructor
89void Bridge::ConfigChanged() {
90
91 static string ExcludeString;
92
93 // Check if configuratiomn changed
94 if (ExcludeString == GetConfig("exclude")) return;
95 ExcludeString = GetConfig("exclude");
96
97 // Remove all previous subscriptions
98 Undo();
99
100 // Compile regular expressions
101 regex_t R;
102 vector<string> Exclude = Tokenize(ExcludeString, " \t");
103 for (int i=0; i<Exclude.size(); i++) {
104 int Ret = regcomp(&R, Exclude[i].c_str(), REG_EXTENDED|REG_NOSUB);
105 if (Ret != 0) {
106 char Err[200];
107 regerror(Ret, &R, Err, sizeof(Err));
108 Message(ERROR, "Error compiling regular expression '%s' (%s)", Exclude[i].c_str(), Err);
109 }
110 else RegEx.push_back(R);
111 }
112
113 // Subscribe to top-level server list
114 ServerList = new DimInfo((char *) "DIS_DNS/SERVER_LIST", NO_LINK, this);
115}
116
117
118// Service subscription and repeating
119void Bridge::infoHandler() {
120
121 DimInfo *I = getInfo();
122
123 // Check if service available
124 if (!ServiceOK(I)) return;
125
126 // If service is DIS_DNS/SERVER_LIST, subscribe to all SERVICE_LIST services
127 if (strcmp(I->getName(), "DIS_DNS/SERVER_LIST") == 0) {
128
129 char *Token = strtok(I->getString(), "+-!@");
130 while (Token != NULL) {
131 if (*I->getString() == '-' || *I->getString() == '!') {
132 RemoveService(string(Token)+"/SERVICE_LIST");
133 }
134 else AddService(string(Token)+"/SERVICE_LIST", (char *) "C", DimSERVICE);
135
136 // Skip server IP address and process ID
137 Token = strtok(NULL, "|");
138 Token = strtok(NULL, "@");
139 }
140 return;
141 }
142
143 // If service is SERVICE_LIST, scan and subscribe/unsubscribe to services
144 if (strstr(I->getName(), "/SERVICE_LIST") != NULL) {
145
146 // Bug fix for empty SERVICE_LIST
147 if (strlen(I->getString()) == 0) {
148 string Tmp(I->getName());
149 RemoveService(I->getName());
150 AddService(Tmp.c_str(), (char *) "C", DimSERVICE);
151 return;
152 }
153
154 char *Format, *Name = strtok(I->getString(), "+-!|");
155 while (Name != NULL) {
156 if ((Format = strtok(NULL, "\n")) != NULL) {
157 // Check if service added or removed/unavailable
158 if (*I->getString() == '-' || *I->getString() == '!') {
159 if (strstr(Format, "|RPC") != NULL) {
160 RemoveService(string(Name)+"/RpcIn");
161 RemoveService(string(Name)+"/RpcOut");
162 }
163 else RemoveService(Name);
164 }
165 else {
166 // Determine type of service
167 if (strstr(Format, "|CMD") != NULL) {
168 *(strstr(Format, "|CMD")) = '\0';
169 AddService(Name, Format, DimCOMMAND);
170 }
171 else if (strstr(Format, "|RPC") != NULL) {
172 *(strstr(Format, "|RPC")) = '\0';
173 if (strchr(Format, ',') != NULL) {
174 *strchr(Format, ',') = '\0';
175 AddService(string(Name)+"/RpcIn", Format, DimCOMMAND);
176 AddService(string(Name)+"/RpcOut", Format+strlen(Format)+1, DimSERVICE);
177 }
178
179 }
180 else {
181 Format[strlen(Format)-1] = '\0';
182 AddService(Name, Format, DimSERVICE);
183 }
184 }
185 }
186 Name = strtok(NULL, "|");
187 }
188 return;
189 }
190
191 // Check if service known and repeat to secondary DNS
192 if (Map.count(I->getName()) == 0) return;
193
194 // Copy service data
195 delete[] Map[I->getName()].Data;
196 Map[I->getName()].Data = new char [I->getSize()];
197 memcpy(Map[I->getName()].Data, I->getData(), I->getSize());
198
199 // Set new service properties and update service
200 Map[I->getName()].Service->setQuality(I->getQuality());
201 Map[I->getName()].Service->setTimestamp(I->getTimestamp(), I->getTimestampMillisecs());
202 Map[I->getName()].Service->updateService(Map[I->getName()].Data, I->getSize());
203}
204
205
206// Command repeating (also handles requests for remote procedure calls)
207void Bridge::commandHandler() {
208
209 // Check if client allowed to send commands
210 vector<string> Client = Tokenize(getClientName(), "@");
211 if (Client.size() == 2 && GetConfig("cmdallow").find(Client[1]) == string::npos) {
212 Message(INFO, "Rejected command/rpc from %s (ID %d)", getClientName(), getClientId());
213 return;
214 }
215
216 // Send command to server
217 sendCommandNB(getCommand()->getName(), getCommand()->getData(), getCommand()->getSize());
218}
219
220
221// Service subscription
222void Bridge::AddService(string Name, char *Format, int Type) {
223
224 // Check if already subscribed to this service
225 if (Map.count(Name) != 0) return;
226
227 // Should service be ignored?
228 for (int i=0; i<RegEx.size(); i++) {
229 if (regexec(&RegEx[i], Name.c_str(), (size_t) 0, NULL, 0) == 0) return;
230 }
231
232 // Create subscription and service to secondary DNS or new command
233 Map[Name].Command = NULL;
234 Map[Name].DataItem = NULL;
235 Map[Name].Service = NULL;
236 Map[Name].Data = NULL;
237
238 if (Type == DimSERVICE) {
239 Map[Name].Service = new DimService(Name.c_str(), (char *) Format, Map[Name].Data, 0);
240 Map[Name].DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
241 }
242 else if (Type == DimCOMMAND) Map[Name].Command = new DimCommand(Name.c_str(), Format, this);
243}
244
245
246// Remove service from watch list (unused pointer are NULL)
247void Bridge::RemoveService(string Name) {
248
249 // Check if actually subscribed to service
250 if (Map.count(Name) == 0) return;
251
252 delete Map[Name].DataItem;
253 delete Map[Name].Service;
254 delete[] Map[Name].Data;
255 delete Map[Name].Command;
256
257 Map.erase(Name);
258}
259
260
261// Main program
262int main(int argc, char *argv[]) {
263
264 // Check command line argument
265 if (argc == 1) {
266 printf("Usage: %s <address of primary DNS> [port] (default port %d)\n", argv[0], DEFAULT_PORT);
267 exit(EXIT_FAILURE);
268 }
269
270 // Static ensures calling of destructor by exit()
271 static Bridge Class(argv[1], argc>2 ? atoi(argv[2]) : DEFAULT_PORT);
272
273 // Sleep until signal caught
274 while (!Class.ExitRequest) pause();
275}
Note: See TracBrowser for help on using the repository browser.