1 /******************************************************************************
2 (c) 2000-2004 Christine Caulfield christine.caulfield@googlemail.com
3 (c) 2003 Dmitri Popov
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 ******************************************************************************/
15
16 #include <sys/types.h>
17 #include <stdio.h>
18 #include <time.h>
19 #include <netinet/in.h>
20 #include <string.h>
21 #include <list>
22 #include <string>
23 #include <map>
24 #include <iterator>
25 #include <sstream>
26 #include <iomanip>
27
28 #include "lat.h"
29 #include "utils.h"
30 #include "services.h"
31 #include "dn_endian.h"
32
33 // Add or replace a node in the service table
add_service(const std::string & node,const std::string & service,const std::string & ident,int rating,int interface,unsigned char * macaddr)34 bool LATServices::add_service(const std::string &node, const std::string &service, const std::string &ident,
35 int rating, int interface, unsigned char *macaddr)
36 {
37 debuglog(("Got service. Node: %s, service %s, rating: %d\n",
38 node.c_str(), service.c_str(), rating));
39
40 std::map<std::string, serviceinfo, std::less<std::string> >::iterator test = servicelist.find(service);
41 if (test == servicelist.end())
42 {
43 servicelist[service] = serviceinfo(node, ident, macaddr, rating, interface);
44 }
45 else
46 {
47 servicelist[test->first].add_or_replace_node(node, ident, macaddr, rating, interface);
48 }
49 return true;
50 }
51
52 // Return the highest rated node providing a named service
get_highest(const std::string & service,std::string & node,unsigned char * macaddr,int * interface)53 bool LATServices::get_highest(const std::string &service, std::string &node, unsigned char *macaddr,
54 int *interface)
55 {
56 std::map<std::string, serviceinfo, std::less<std::string> >::iterator test = servicelist.find(service);
57 if (test != servicelist.end())
58 {
59 return servicelist[test->first].get_highest(node, macaddr, interface);
60 }
61 return false; // Not found
62 }
63
64 // Return the highest rated node providing this service
get_highest(std::string & node,unsigned char * macaddr,int * interface)65 bool LATServices::serviceinfo::get_highest(std::string &node, unsigned char *macaddr, int *interface)
66 {
67 int highest_rating=0;
68 std::string highest_node;
69 const unsigned char *highest_macaddr = NULL;
70
71 std::map<std::string, nodeinfo, std::less<std::string> >::iterator i;
72 for (i=nodes.begin(); i != nodes.end(); i++)
73 {
74 if (nodes[i->first].is_available() &&
75 nodes[i->first].get_rating() > highest_rating)
76 {
77 highest_rating = nodes[i->first].get_rating();
78 highest_node = i->first; // Just note the pointer
79 highest_macaddr = nodes[i->first].get_macaddr();
80 *interface = nodes[i->first].get_interface();
81 }
82 }
83
84 if (highest_macaddr)
85 {
86 // OK copy it now.
87 memcpy(macaddr, highest_macaddr, 6);
88 node = highest_node;
89 return true;
90 }
91 else
92 {
93 return false;
94 }
95 }
96
97
98 // Return the node macaddress if the node provides this service
get_node(const std::string & service,const std::string & node,unsigned char * macaddr,int * interface)99 bool LATServices::get_node(const std::string &service, const std::string &node,
100 unsigned char *macaddr, int *interface)
101 {
102 std::map<std::string, serviceinfo, std::less<std::string> >::iterator test = servicelist.find(service);
103 std::map<std::string, serviceinfo, std::less<std::string> >::iterator c =
104 servicelist.begin();
105 int i =0;
106 for(;c != servicelist.end();c++) {
107 i++;
108 debuglog(("LATServices::get_node : service %2d '%s' \n",
109 i, c->first.c_str()));
110 }
111
112 if (test != servicelist.end())
113 {
114 // std::map<std::string, serviceinfo, std::less<std::string> >::iterator c = test;
115 // int i =0;
116 // for(;c != servicelist.end();c++) { i++; };
117 debuglog(("LATServices::get_node : service found '%s', number: %d \n", service.c_str(), i));
118 return servicelist[test->first].get_node(node, macaddr, interface);
119 }
120 debuglog(("LATServices::get_node : no service '%s' \n", service.c_str()));
121
122 return false; // Not found
123 }
124
125
126 // Return the node's macaddress
get_node(const std::string & node,unsigned char * macaddr,int * interface)127 bool LATServices::serviceinfo::get_node(const std::string &node, unsigned char *macaddr, int *interface)
128 {
129 std::map<std::string, nodeinfo, std::less<std::string> >::iterator test = nodes.find(node);
130
131 std::map<std::string, nodeinfo, std::less<std::string> >::iterator c =
132 nodes.begin();
133 int i =0;
134 for(;c != nodes.end();c++) {
135 i++;
136 debuglog(("LATServices::serinfo::get_node :node %2d '%s' \n",
137 i, c->first.c_str()));
138 }
139
140 debuglog(("LATServices::serinfo::get_node looking for '%s' \n",
141 node.c_str()));
142
143
144 if (test != nodes.end())
145 {
146 memcpy(macaddr, nodes[node].get_macaddr(), 6);
147 *interface = nodes[node].get_interface();
148 return true;
149 }
150 else
151 {
152 debuglog(("LATServices::serviceinfo::get_node : no node '%s' \n", node.c_str()));
153 return false;
154 }
155 }
156
157
158 // Remove node from all services...
159 // Actually just mark as unavailable in all services
remove_node(const std::string & node)160 bool LATServices::remove_node(const std::string &node)
161 {
162 bool removed = false;
163 std::map<std::string, serviceinfo, std::less<std::string> >::iterator s(servicelist.begin());
164
165 for (; s != servicelist.end(); s++)
166 {
167 if (servicelist[s->first].remove_node(node))
168 removed=true;
169 }
170 return removed;
171 }
172
173
remove_node(const std::string & node)174 bool LATServices::serviceinfo::remove_node(const std::string &node)
175 {
176 std::map<std::string, nodeinfo, std::less<std::string> >::iterator test = nodes.find(node);
177 if (test != nodes.end())
178 {
179 nodes[test->first].set_available(false);
180 }
181 return false;
182 }
183
184 // Return true if the service is available.
185 // This is the case if one node offering that service is available
is_available()186 bool LATServices::serviceinfo::is_available()
187 {
188 bool avail = true;
189 std::map<std::string, nodeinfo, std::less<std::string> >::iterator n(nodes.begin());
190
191 for (; n != nodes.end(); n++)
192 {
193 if (!nodes[n->first].is_available()) avail=false;
194 }
195 return avail;
196 }
197
198
expire_nodes(time_t current_time)199 void LATServices::serviceinfo::expire_nodes(time_t current_time)
200 {
201 std::map<std::string, nodeinfo, std::less<std::string> >::iterator n(nodes.begin());
202
203 for (; n != nodes.end(); n++)
204 {
205 if (nodes[n->first].has_expired(current_time))
206 nodes[n->first].set_available(false);
207 }
208 }
209
expire_nodes()210 void LATServices::expire_nodes()
211 {
212 std::map<std::string, serviceinfo, std::less<std::string> >::iterator s(servicelist.begin());
213 time_t current_time = time(NULL);
214
215 for (; s != servicelist.end(); s++)
216 {
217 // Skip dummy service
218 if (s->first != "")
219 {
220 servicelist[s->first].expire_nodes(current_time);
221 }
222 }
223 }
224
225
226 // Verbose listing of nodes in this service
list_service(std::ostringstream & output)227 void LATServices::serviceinfo::list_service(std::ostringstream &output)
228 {
229 std::map<std::string, nodeinfo, std::less<std::string> >::iterator n(nodes.begin());
230
231 output << "Node Name Status Rating Identification" << std::endl;
232 for (; n != nodes.end(); n++)
233 {
234 output.width(17);
235 output.setf(std::ios::left, std::ios::adjustfield);
236 output << n->first.c_str() <<
237 (nodes[n->first].is_available()?"Reachable ":"Unreachable") << " ";
238 output.width(4);
239 output.setf(std::ios::right, std::ios::adjustfield);
240 output << nodes[n->first].get_rating() << " " <<
241 nodes[n->first].get_ident() << std::endl;
242 }
243 }
244
list_nodes(std::ostringstream & output)245 void LATServices::serviceinfo::list_nodes(std::ostringstream &output)
246 {
247 std::map<std::string, nodeinfo, std::less<std::string> >::iterator n(nodes.begin());
248 const unsigned char *addr = NULL;
249
250 output << "Node Name Status Address Identification" << std::endl;
251 for (; n != nodes.end(); n++)
252 {
253 addr = n->second.get_macaddr();
254 output.width(17);
255 output.setf(std::ios::left, std::ios::adjustfield);
256 output << n->first.c_str() <<
257 (n->second.check_respond_counter()?"Reachable ":"Unreachable") << " ";
258
259 output.setf(std::ios::hex, std::ios::basefield);
260
261 output << std::setiosflags(std::ios::right | std::ios::uppercase) << std::setfill('0')
262 << std::setw(2) << (int)addr[0] << '-'
263 << std::setw(2) << (int)addr[1] << '-'
264 << std::setw(2) << (int)addr[2] << '-'
265 << std::setw(2) << (int)addr[3] << '-'
266 << std::setw(2) << (int)addr[4] << '-'
267 << std::setw(2) << (int)addr[5]
268 << std::resetiosflags(std::ios::right | std::ios::uppercase) << std::setfill(' ');
269
270 output.setf(std::ios::right, std::ios::adjustfield);
271 output << " " << n->second.get_ident() << std::endl;
272 }
273 }
274
list_dummy_nodes(bool verbose,std::ostringstream & output)275 bool LATServices::list_dummy_nodes(bool verbose, std::ostringstream &output)
276 {
277 std::map<std::string, serviceinfo, std::less<std::string> >::iterator dummies =
278 servicelist.find("");
279
280 if ( dummies == servicelist.end()) {
281 output << "No dummy nodes available." << std::endl;
282 return true;
283 }
284
285 output << std::endl;
286 output << "Service Name: " << "Slave nodes" << std::endl;
287 output << "Service Status: " << (servicelist[dummies->first].is_available()?"Available ":"Unavailable") << " " << std::endl;
288 output << "Service Ident: " << servicelist[dummies->first].get_ident() << std::endl << std::endl;
289 dummies->second.list_nodes(output);
290 output << "--------------------------------------------------------------------------------" << std::endl;
291
292
293 return true;
294 }
295
touch_dummy_node_respond_counter(const std::string & str_name)296 bool LATServices::touch_dummy_node_respond_counter(const std::string &str_name)
297 {
298 std::map<std::string, serviceinfo, std::less<std::string> >::iterator dummies =
299 servicelist.find("");
300
301 if ( dummies == servicelist.end()) {
302 return false; // no node
303 }
304
305 return dummies->second.touch_dummy_node_respond_counter(str_name);
306 }
307
touch_dummy_node_respond_counter(const std::string & str_name)308 bool LATServices::serviceinfo::touch_dummy_node_respond_counter(const std::string &str_name)
309 {
310 std::map<std::string, nodeinfo, std::less<std::string> >::iterator n = nodes.find(str_name);
311
312 if (n == nodes.end()) {
313 return false; // no node
314 }
315
316 debuglog(("touch_respond() : node: %s ", n->first.c_str()));
317 n->second.touch_respond_counter();
318 return true;
319 }
320
321
322 // List all known services
list_services(bool verbose,std::ostringstream & output)323 bool LATServices::list_services(bool verbose, std::ostringstream &output)
324 {
325 std::map<std::string, serviceinfo, std::less<std::string> >::iterator s(servicelist.begin());
326
327 for (; s != servicelist.end(); s++)
328 {
329 // Skip dummy service
330 if (s->first != "")
331 {
332 if (verbose)
333 {
334 output << std::endl;
335 output << "Service Name: " << s->first << std::endl;
336 output << "Service Status: " << (servicelist[s->first].is_available()?"Available ":"Unavailable") << " " << std::endl;
337 output << "Service Ident: " << servicelist[s->first].get_ident() << std::endl << std::endl;
338 servicelist[s->first].list_service(output);
339 output << "--------------------------------------------------------------------------------" << std::endl;
340
341 }
342 else
343 {
344 output.width(28);
345 output.setf(std::ios::left, std::ios::adjustfield);
346 output << s->first.c_str() << (servicelist[s->first].is_available()?"Available ":"Unavailable") << " " <<
347 servicelist[s->first].get_ident() << std::endl;
348 }
349 }
350
351 }
352
353 output << std::ends; // Trailing NUL for latcp's benefit.
354 return true;
355 }
356
357 LATServices *LATServices::instance = NULL;
358