An Overlay-based
Virtual Network Substrate
SpoVNet

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

Last change on this file since 6919 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.