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