source: source/ariba/utility/addressing/endpoint_set.hpp@ 9992

Last change on this file since 9992 was 6919, checked in by mies, 14 years ago

Fixed tons of warnings when using CXXFLAGS="-Wall"!

File size: 11.0 KB
Line 
1#ifndef ENDPOINT_SET_HPP_
2#define ENDPOINT_SET_HPP_
3
4#include "addressing.hpp"
5#include "tcpip_endpoint.hpp"
6
7#include <sstream>
8#include <boost/unordered_set.hpp>
9#include <boost/foreach.hpp>
10#include <boost/thread.hpp>
11
12namespace ariba {
13namespace addressing {
14
15using boost::unordered_set;
16
17/**
18 * This end-point set shelters known addresses of a device.
19 * Transport protocols use this class to address devices.
20 *
21 * Example of a string representation:
22 * "tcp{500|501};ip{10.11.12.13};bluetooth{01:02:03:04:05:06};rfcomm{1234}"
23 * Inside a address type specification, addresses are separated by a bar (|).
24 *
25 * @author Sebastian Mies <mies@tm.uka.de>
26 */
27class endpoint_set {
28public:
29 // layer 2
30 unordered_set<mac_address> bluetooth;
31
32 // layer 3
33 unordered_set<ip_address> ip;
34
35 // layer 4
36 unordered_set<tcp_port_address> tcp;
37 unordered_set<rfcomm_channel_address> rfcomm;
38
39 // mutex
40 boost::mutex io_mutex;
41 typedef boost::mutex::scoped_lock scoped_lock;
42
43private:
44 template<uint8_t type, class V>
45 size_t to_bytes_dynamic( const unordered_set<V>& set, uint8_t* bytes ) const {
46 size_t size = 0;
47 bytes[0] = type;
48 uint8_t* size_ptr = bytes+1;
49 bytes +=2;
50 size += 2;
51 BOOST_FOREACH( const V& value, set ) {
52 bytes[0] = (uint8_t)value.to_bytes_size();
53 bytes++;
54 size++;
55 value.to_bytes(bytes);
56 bytes += value.to_bytes_size();
57 size += value.to_bytes_size();
58 }
59 *size_ptr = size-2;
60 return size;
61 }
62
63 template<class V>
64 void from_bytes_dynamic( unordered_set<V>& set, const uint8_t* bytes, uint8_t size ) {
65 size_t pos = 0;
66 while (pos < size) {
67 uint8_t length = bytes[0];
68 bytes++; pos++;
69 V obj(bytes,length);
70 set.insert(obj);
71 bytes+=length; pos+=length;
72 }
73 }
74
75 template<uint8_t type, class V>
76 size_t to_bytes_fixed( const unordered_set<V>& set, uint8_t* bytes ) const {
77 size_t fixed_size = V().to_bytes_size();
78 bytes[0] = type;
79 bytes[1] = (uint8_t)(set.size()* fixed_size);
80 bytes+=2;
81 BOOST_FOREACH( const V& value, set ) {
82 value.to_bytes(bytes);
83 bytes += value.to_bytes_size();
84 }
85 return 2 + set.size() * fixed_size;
86 }
87
88 template<class V>
89 void from_bytes_fixed( unordered_set<V>& set, const uint8_t* bytes, uint8_t size ) {
90 size_t fixed_size = V().to_bytes_size();
91 uint8_t num = size/fixed_size;
92 for (uint8_t i=0; i<num; i++) {
93 V obj(bytes, fixed_size);
94 set.insert(obj);
95 bytes += fixed_size;
96 }
97 }
98
99 template<class V>
100 std::string to_string_set( const unordered_set<V>& set, const std::string& type ) const {
101 if (set.size()==0) return std::string("");
102 std::ostringstream buf;
103 buf << type << "{";
104 bool first = true;
105 BOOST_FOREACH( const V& value, set ) {
106 if (!first) {
107 buf << " | ";
108 } else
109 first = false;
110 buf << value.to_string();
111 }
112 buf << "};";
113 return buf.str();
114 }
115
116 static void trim(string& str) {
117 string::size_type pos = str.find_last_not_of(' ');
118 if(pos != string::npos) {
119 str.erase(pos + 1);
120 pos = str.find_first_not_of(' ');
121 if(pos != string::npos) str.erase(0, pos);
122 }
123 else str.erase(str.begin(), str.end());
124 }
125
126 static string::size_type skip( const char* chars, string::size_type pos, const std::string& str ) {
127 bool found = true;
128 while (pos<str.size() && found) {
129 found = false;
130 for (size_t i=0; chars[i]!=0 && !found; i++)
131 if (str.at(pos)==chars[i]) {
132 pos++;
133 found = true;
134 }
135 }
136 return pos;
137 }
138
139 template<class V>
140 size_t from_string_set( unordered_set<V>& set, string::size_type pos, const std::string& str ) {
141 while (pos < str.size() && pos != string::npos) {
142 pos = skip("} |\n\r", pos, str);
143 string::size_type nend1 = str.find('}',pos);
144 string::size_type nend2 = str.find('|',pos);
145 if (nend1==string::npos && nend2==string::npos) break;
146 if (nend1==string::npos) nend1=str.size();
147 if (nend2==string::npos) nend2=str.size();
148 string::size_type nend = nend2 < nend1 ? nend2:nend1;
149 std::string sub = str.substr(pos, min(nend2,nend1)-pos);
150 trim(sub);
151// cout << sub << endl;
152 V obj( sub );
153 set.insert(obj);
154 pos = nend+1;
155 if (nend1<nend2) break;
156 }
157 return pos-1;
158 }
159
160public:
161 enum layers {
162 Layer1 = 1, Layer2 = 2, Layer3 = 4, Layer4 = 8, Layer5 = 16,
163 Layer6 = 32, Layer7 = 64, Layer8 = 128, NoLoopback = 256,AllLayers = ~0,
164 Layer1_3 = Layer1|Layer2|Layer3,
165 Layer1_4 = Layer1|Layer2|Layer3|Layer4,
166 };
167
168 endpoint_set() {
169
170 }
171
172 endpoint_set( const endpoint_set& copy ) :
173 bluetooth(copy.bluetooth), ip(copy.ip), tcp(copy.tcp), rfcomm(copy.rfcomm) {
174 }
175
176 endpoint_set( const std::string& str ) {
177 assign(str);
178 }
179
180 endpoint_set( const uint8_t* bytes, size_t size ) {
181 assign(bytes, size);
182 }
183
184 /// adds an address or endpoint to this set
185 void add( const address_v* address, int layers = AllLayers ) {
186 scoped_lock lock(io_mutex);
187 if ( address->instanceof<tcpip_endpoint> () ) {
188 const tcpip_endpoint& addr = *address;
189 if (layers & Layer3 &&
190 !((layers & NoLoopback) && addr.address().is_loopback()) )
191 ip.insert( addr.address() );
192 if (layers & Layer4) tcp.insert( addr.port() );
193 } else
194 if ( address->instanceof<ip_address>() ) {
195 const ip_address& addr = *address;
196 if ((layers & Layer3) &&
197 !((layers & NoLoopback) && addr.is_loopback()))
198 ip.insert( addr );
199 } else
200 if (address->instanceof<rfcomm_endpoint>() ) {
201 const rfcomm_endpoint& endp = *address;
202 if (layers & Layer2) bluetooth.insert( endp.mac() );
203 if (layers & Layer4) rfcomm.insert( endp.channel() );
204 } else
205 if (address->instanceof<mac_address>() ) {
206 const mac_address& endp = *address;
207 if (layers & Layer2) bluetooth.insert( endp );
208 }
209 }
210
211 /// adds addresses from another endpoint set
212 void add( const endpoint_set& eps, int layers = AllLayers ) {
213 scoped_lock lock(io_mutex);
214
215 // merge layer 2 addresses
216 if (layers & Layer2) {
217 bluetooth.insert(eps.bluetooth.begin(), eps.bluetooth.end() );
218 }
219
220 // merge layer 3 addresses
221 if (layers & Layer3) {
222 ip.insert(eps.ip.begin(), eps.ip.end() );
223 }
224
225 // merge layer 4 addresses
226 if (layers & Layer4) {
227 tcp.insert(eps.tcp.begin(), eps.tcp.end() );
228 rfcomm.insert(eps.rfcomm.begin(), eps.rfcomm.end() );
229 }
230 }
231
232 /// removes an address or endpoint from this set
233 void remove( const address_vf address ) {
234 scoped_lock lock(io_mutex);
235 if ( address->instanceof<tcpip_endpoint> () ) {
236 const tcpip_endpoint& addr = *address;
237 ip.erase( addr.address() );
238 tcp.erase( addr.port() );
239 } else
240 if ( address->instanceof<ip_address>() ) {
241 const ip_address& addr = *address;
242 ip.erase( addr );
243 } else
244 if (address->instanceof<rfcomm_endpoint>() ) {
245 const rfcomm_endpoint& endp = *address;
246 bluetooth.erase( endp.mac() );
247 rfcomm.erase( endp.channel() );
248 }
249 }
250
251 /// checks whether two end-points are disjoint
252 /// (only check lower level addresses)
253 bool disjoint_to( const endpoint_set& set ) const {
254 scoped_lock lock(const_cast<boost::mutex&>(io_mutex));
255 BOOST_FOREACH( const mac_address& mac, bluetooth )
256 if (set.bluetooth.count(mac) !=0 ) return false;
257 BOOST_FOREACH( const ip_address& ip_, ip )
258 if (set.ip.count(ip_) !=0 ) return false;
259 return true;
260 }
261
262 bool intersects_with( const endpoint_set& set ) const {
263 return !disjoint_to(set);
264 }
265
266 bool is_subset_of( const endpoint_set& set ) const {
267 throw "Not implemented!";
268 return false;
269 }
270
271 /// returns true, if this address has a fixed size in bytes
272 bool is_bytes_size_static() const {
273 return false;
274 }
275
276 /// returns the number of bytes used for serialization of this address
277 size_t to_bytes_size() const {
278 scoped_lock lock(const_cast<boost::mutex&>(io_mutex));
279 size_t size = 0;
280
281 // bluetooth mac list (layer 2)
282 size += bluetooth.size() * mac_address().to_bytes_size();
283
284 // ip list (layer 3)
285 BOOST_FOREACH( const ip_address& ip_, ip )
286 size += (ip_.to_bytes_size() + 1 /* =length */);
287
288 // tcp ports (layer 4)
289 size += tcp.size() * tcp_port_address().to_bytes_size();
290
291 // bluetooth rfcomm channels (layer 4)
292 size += rfcomm.size() * rfcomm_channel_address().to_bytes_size();
293
294 // length/type encoding
295 size += 4 /* number of items*/ * 2 /* length of type and length */;
296
297 return size;
298 }
299
300 /// converts this address to a binary representation
301 void to_bytes(uint8_t* bytes) const {
302 scoped_lock lock(const_cast<boost::mutex&>(io_mutex));
303
304 /// bluetooth mac list (layer 2)
305 bytes += to_bytes_fixed<0x21, mac_address>( bluetooth, bytes );
306
307 // ip list (layer 3)
308 bytes += to_bytes_dynamic<0x31, ip_address>(ip, bytes);
309
310 // tcp ports (layer 4)
311 bytes += to_bytes_fixed<0x41, tcp_port_address>( tcp, bytes );
312
313 // rfcomm channels (layer 4)
314 bytes += to_bytes_fixed<0x42, rfcomm_channel_address>( rfcomm, bytes );
315 }
316
317 /// Assigns an address using a bunch of bytes
318 bool assign(const uint8_t* bytes, size_t size) {
319 scoped_lock lock(io_mutex);
320
321 size_t pos = 0;
322 while (pos < size) {
323 uint8_t type = bytes[0];
324 uint8_t length = bytes[1];
325 bytes+=2; pos+=2;
326
327 switch (type) {
328
329 // bluetooth mac
330 case 0x21: {
331 from_bytes_fixed<mac_address>( bluetooth, bytes, length );
332 break;
333 }
334
335 // ip
336 case 0x31: {
337 from_bytes_dynamic<ip_address>( ip, bytes, length );
338 break;
339 }
340 // tcp
341 case 0x41: {
342 from_bytes_fixed<tcp_port_address>( tcp, bytes, length );
343 break;
344 }
345 // rfcomm
346 case 0x42: {
347 from_bytes_fixed<rfcomm_channel_address>( rfcomm, bytes, length );
348 break;
349 }
350
351 default: {
352 pos = size;
353 break;
354 }
355 }
356 bytes += length; pos+=length;
357 }
358 return false;
359 }
360
361 /// generates a string out of this endpoint-set
362 std::string to_string() const {
363 scoped_lock lock(const_cast<boost::mutex&>(io_mutex));
364 std::string smac = to_string_set<mac_address>(bluetooth, "bluetooth");
365 std::string sip = to_string_set<ip_address>(ip, "ip");
366 std::string stcp = to_string_set<tcp_port_address>(tcp, "tcp");
367 std::string srfcomm = to_string_set<rfcomm_channel_address>(rfcomm, "rfcomm");
368 return smac+sip+stcp+srfcomm;
369 }
370
371 /// assigns an endpoint-set out of a string
372 void assign( const std::string& str ) {
373 scoped_lock lock(io_mutex);
374 string::size_type pos = 0;
375 while (pos < str.size() && pos!=string::npos) {
376 pos = skip("}; \n\r", pos, str );
377 string::size_type nend = str.find('{',pos);
378 if (nend == string::npos) break;
379 std::string type = str.substr(pos,nend-pos);
380 pos = nend+1;
381 trim(type);
382 if (type=="bluetooth")
383 pos = from_string_set<mac_address>(bluetooth, pos, str );
384 else if (type=="ip")
385 pos = from_string_set<ip_address>(ip, pos, str );
386 else if (type=="tcp")
387 pos = from_string_set<tcp_port_address>(tcp, pos, str );
388 else if (type=="rfcomm")
389 pos = from_string_set<rfcomm_channel_address>(rfcomm, pos, str );
390 else
391 pos = str.find('}',pos);
392 }
393 }
394
395 endpoint_set& operator=( const endpoint_set& rhs ) {
396 scoped_lock lock(io_mutex);
397 this->bluetooth = rhs.bluetooth;
398 this->ip = rhs.ip;
399 this->rfcomm = rhs.rfcomm;
400 this->tcp = rhs.tcp;
401 return *this;
402 }
403
404 /// checks wheter the two endpoint sets are identical
405 bool operator== ( const endpoint_set& rhs ) const {
406 return (rhs.rfcomm == rfcomm && rhs.ip == ip && rhs.tcp == tcp &&
407 rhs.bluetooth == bluetooth);
408 }
409
410 bool operator!= ( const endpoint_set& rhs ) const {
411 return !(*this==rhs);
412 }
413};
414
415}} // namespace ariba::addressing
416
417#endif /* ENDPOINT_SET_HPP_ */
Note: See TracBrowser for help on using the repository browser.