An Overlay-based
Virtual Network Substrate
SpoVNet

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

Last change on this file since 5406 was 5406, checked in by mies, 14 years ago
File size: 10.9 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, 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) ip.insert( addr.address() );
190                        if (layers & Layer4) tcp.insert( addr.port() );
191                } else
192                if ( address->instanceof<ip_address>() ) {
193                        const ip_address& addr = *address;
194                        if (layers & Layer3) ip.insert( addr );
195                } else
196                if (address->instanceof<rfcomm_endpoint>() ) {
197                        const rfcomm_endpoint& endp = *address;
198                        if (layers & Layer2) bluetooth.insert( endp.mac() );
199                        if (layers & Layer4) rfcomm.insert( endp.channel() );
200                } else
201                if (address->instanceof<mac_address>() ) {
202                        const mac_address& endp = *address;
203                        if (layers & Layer2) bluetooth.insert( endp );
204                }
205        }
206
207        /// adds addresses from another endpoint set
208        void add( const endpoint_set& eps, int layers = AllLayers ) {
209                scoped_lock lock(io_mutex);
210
211                // merge layer 2 addresses
212                if (layers & Layer2) {
213                        bluetooth.insert(eps.bluetooth.begin(), eps.bluetooth.end() );
214                }
215
216                // merge layer 3 addresses
217                if (layers & Layer3) {
218                        ip.insert(eps.ip.begin(), eps.ip.end() );
219                }
220
221                // merge layer 4 addresses
222                if (layers & Layer4) {
223                        tcp.insert(eps.tcp.begin(), eps.tcp.end() );
224                        rfcomm.insert(eps.rfcomm.begin(), eps.rfcomm.end() );
225                }
226        }
227
228        /// removes an address or endpoint from this set
229        void remove( const address_vf address ) {
230                scoped_lock lock(io_mutex);
231                if ( address->instanceof<tcpip_endpoint> () ) {
232                        const tcpip_endpoint& addr = *address;
233                        ip.erase( addr.address() );
234                        tcp.erase( addr.port() );
235                } else
236                if ( address->instanceof<ip_address>() ) {
237                        const ip_address& addr = *address;
238                        ip.erase( addr );
239                } else
240                if (address->instanceof<rfcomm_endpoint>() ) {
241                        const rfcomm_endpoint& endp = *address;
242                        bluetooth.erase( endp.mac() );
243                        rfcomm.erase( endp.channel() );
244                }
245        }
246
247        /// checks whether two end-points are disjoint
248        /// (only check lower level addresses)
249        bool disjoint_to( const endpoint_set& set ) const {
250                scoped_lock lock(const_cast<boost::mutex&>(io_mutex));
251                BOOST_FOREACH( const mac_address& mac, bluetooth )
252                        if (set.bluetooth.count(mac) !=0 ) return false;
253                BOOST_FOREACH( const ip_address& ip_, ip )
254                        if (set.ip.count(ip_) !=0 ) return false;
255                return true;
256        }
257
258        bool intersects_with( const endpoint_set& set ) const {
259                return !disjoint_to(set);
260        }
261
262        bool is_subset_of( const endpoint_set& set ) const {
263                throw "Not implemented!";
264                return false;
265        }
266
267        /// returns true, if this address has a fixed size in bytes
268        bool is_bytes_size_static() const {
269                return false;
270        }
271
272        /// returns the number of bytes used for serialization of this address
273        size_t to_bytes_size() const {
274                scoped_lock lock(const_cast<boost::mutex&>(io_mutex));
275                size_t size = 0;
276
277                // bluetooth mac list (layer 2)
278                size += bluetooth.size() * mac_address().to_bytes_size();
279
280                // ip list (layer 3)
281                BOOST_FOREACH( const ip_address& ip_, ip )
282                        size += (ip_.to_bytes_size() + 1 /* =length */);
283
284                // tcp ports (layer 4)
285                size += tcp.size() * tcp_port_address().to_bytes_size();
286
287                // bluetooth rfcomm channels (layer 4)
288                size += rfcomm.size() * rfcomm_channel_address().to_bytes_size();
289
290                // length/type encoding
291                size += 4 /* number of items*/ * 2 /* length of type and length */;
292
293                return size;
294        }
295
296        /// converts this address to a binary representation
297        void to_bytes(uint8_t* bytes) const {
298                scoped_lock lock(const_cast<boost::mutex&>(io_mutex));
299
300                /// bluetooth mac list (layer 2)
301                bytes += to_bytes_fixed<0x21, mac_address>( bluetooth, bytes );
302
303                // ip list (layer 3)
304                bytes += to_bytes_dynamic<0x31, ip_address>(ip, bytes);
305
306                // tcp ports (layer 4)
307                bytes += to_bytes_fixed<0x41, tcp_port_address>( tcp, bytes );
308
309                // rfcomm channels (layer 4)
310                bytes += to_bytes_fixed<0x42, rfcomm_channel_address>( rfcomm, bytes );
311        }
312
313        /// Assigns an address using a bunch of bytes
314        bool assign(const uint8_t* bytes, size_t size) {
315                scoped_lock lock(io_mutex);
316
317                size_t pos = 0;
318                while (pos < size) {
319                        uint8_t type = bytes[0];
320                        uint8_t length = bytes[1];
321                        bytes+=2; pos+=2;
322
323                        switch (type) {
324
325                        // bluetooth mac
326                        case 0x21: {
327                                from_bytes_fixed<mac_address>( bluetooth, bytes, length );
328                                break;
329                        }
330
331                        // ip
332                        case 0x31: {
333                                from_bytes_dynamic<ip_address>( ip, bytes, length );
334                                break;
335                        }
336                        // tcp
337                        case 0x41: {
338                                from_bytes_fixed<tcp_port_address>( tcp, bytes, length );
339                                break;
340                        }
341                        // rfcomm
342                        case 0x42: {
343                                from_bytes_fixed<rfcomm_channel_address>( rfcomm, bytes, length );
344                                break;
345                        }
346
347                        default: {
348                                pos = size;
349                                break;
350                        }
351                        }
352                        bytes += length; pos+=length;
353                }
354                return false;
355        }
356
357        /// generates a string out of this endpoint-set
358        std::string to_string() const {
359                scoped_lock lock(const_cast<boost::mutex&>(io_mutex));
360                std::string smac = to_string_set<mac_address>(bluetooth, "bluetooth");
361                std::string sip  = to_string_set<ip_address>(ip, "ip");
362                std::string stcp = to_string_set<tcp_port_address>(tcp, "tcp");
363                std::string srfcomm = to_string_set<rfcomm_channel_address>(rfcomm, "rfcomm");
364                return smac+sip+stcp+srfcomm;
365        }
366
367        /// assigns an endpoint-set out of a string
368        void assign( const std::string& str ) {
369                scoped_lock lock(io_mutex);
370                string::size_type pos = 0;
371                while (pos < str.size() && pos!=string::npos) {
372                        pos = skip("}; \n\r", pos, str );
373                        string::size_type nend = str.find('{',pos);
374                        if (nend == string::npos) break;
375                        std::string type = str.substr(pos,nend-pos);
376                        pos = nend+1;
377                        trim(type);
378                        if (type=="bluetooth")
379                                pos = from_string_set<mac_address>(bluetooth, pos, str );
380                        else if (type=="ip")
381                                pos = from_string_set<ip_address>(ip, pos, str );
382                        else if (type=="tcp")
383                                pos = from_string_set<tcp_port_address>(tcp, pos, str );
384                        else if (type=="rfcomm")
385                                pos = from_string_set<rfcomm_channel_address>(rfcomm, pos, str );
386                        else
387                                pos = str.find('}',pos);
388                }
389        }
390
391        endpoint_set& operator=( const endpoint_set& rhs ) {
392                scoped_lock lock(io_mutex);
393                this->bluetooth = rhs.bluetooth;
394                this->ip = rhs.ip;
395                this->rfcomm = rhs.rfcomm;
396                this->tcp = rhs.tcp;
397        }
398
399        /// checks wheter the two endpoint sets are identical
400        bool operator== ( const endpoint_set& rhs ) const {
401                return (rhs.rfcomm == rfcomm && rhs.ip == ip && rhs.tcp == tcp &&
402                                rhs.bluetooth == bluetooth);
403        }
404
405        bool operator!= ( const endpoint_set& rhs ) const {
406                return !(*this==rhs);
407        }
408};
409
410}} // namespace ariba::addressing
411
412#endif /* ENDPOINT_SET_HPP_ */
Note: See TracBrowser for help on using the repository browser.