An Overlay-based
Virtual Network Substrate
SpoVNet

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

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

+ added new transport modules and adapted ariba to them
+ exchange endpoint descriptors an link establishment
+ clean up of base communication
+ link establishment with in the presence of multiple endpoints
+ local discovery for ipv6, ipv4 and bluetooth mac addresses

File size: 10.4 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 is_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        /// returns true, if this address has a fixed size in bytes
259        bool is_bytes_size_static() const {
260                return false;
261        }
262
263        /// returns the number of bytes used for serialization of this address
264        size_t to_bytes_size() const {
265                scoped_lock lock(const_cast<boost::mutex&>(io_mutex));
266                size_t size = 0;
267
268                // bluetooth mac list (layer 2)
269                size += bluetooth.size() * mac_address().to_bytes_size();
270
271                // ip list (layer 3)
272                BOOST_FOREACH( const ip_address& ip_, ip )
273                        size += (ip_.to_bytes_size() + 1 /* =length */);
274
275                // tcp ports (layer 4)
276                size += tcp.size() * tcp_port_address().to_bytes_size();
277
278                // bluetooth rfcomm channels (layer 4)
279                size += rfcomm.size() * rfcomm_channel_address().to_bytes_size();
280
281                // length/type encoding
282                size += 4 /* number of items*/ * 2 /* length of type and length */;
283
284                return size;
285        }
286
287        /// converts this address to a binary representation
288        void to_bytes(uint8_t* bytes) const {
289                scoped_lock lock(const_cast<boost::mutex&>(io_mutex));
290
291                /// bluetooth mac list (layer 2)
292                bytes += to_bytes_fixed<0x21, mac_address>( bluetooth, bytes );
293
294                // ip list (layer 3)
295                bytes += to_bytes_dynamic<0x31, ip_address>(ip, bytes);
296
297                // tcp ports (layer 4)
298                bytes += to_bytes_fixed<0x41, tcp_port_address>( tcp, bytes );
299
300                // rfcomm channels (layer 4)
301                bytes += to_bytes_fixed<0x42, rfcomm_channel_address>( rfcomm, bytes );
302        }
303
304        /// Assigns an address using a bunch of bytes
305        bool assign(const uint8_t* bytes, size_t size) {
306                scoped_lock lock(io_mutex);
307
308                size_t pos = 0;
309                while (pos < size) {
310                        uint8_t type = bytes[0];
311                        uint8_t length = bytes[1];
312                        bytes+=2; pos+=2;
313
314                        switch (type) {
315
316                        // bluetooth mac
317                        case 0x21: {
318                                from_bytes_fixed<mac_address>( bluetooth, bytes, length );
319                                break;
320                        }
321
322                        // ip
323                        case 0x31: {
324                                from_bytes_dynamic<ip_address>( ip, bytes, length );
325                                break;
326                        }
327                        // tcp
328                        case 0x41: {
329                                from_bytes_fixed<tcp_port_address>( tcp, bytes, length );
330                                break;
331                        }
332                        // rfcomm
333                        case 0x42: {
334                                from_bytes_fixed<rfcomm_channel_address>( rfcomm, bytes, length );
335                                break;
336                        }
337
338                        default: {
339                                pos = size;
340                                break;
341                        }
342                        }
343                        bytes += length; pos+=length;
344                }
345                return false;
346        }
347
348        /// generates a string out of this endpoint-set
349        std::string to_string() const {
350                scoped_lock lock(const_cast<boost::mutex&>(io_mutex));
351                std::string smac = to_string_set<mac_address>(bluetooth, "bluetooth");
352                std::string sip  = to_string_set<ip_address>(ip, "ip");
353                std::string stcp = to_string_set<tcp_port_address>(tcp, "tcp");
354                std::string srfcomm = to_string_set<rfcomm_channel_address>(rfcomm, "rfcomm");
355                return smac+sip+stcp+srfcomm;
356        }
357
358        /// assigns an endpoint-set out of a string
359        void assign( const std::string& str ) {
360                scoped_lock lock(io_mutex);
361                string::size_type pos = 0;
362                while (pos < str.size() && pos!=string::npos) {
363                        pos = skip("}; \n\r", pos, str );
364                        string::size_type nend = str.find('{',pos);
365                        if (nend == string::npos) break;
366                        std::string type = str.substr(pos,nend-pos);
367                        pos = nend+1;
368                        trim(type);
369                        if (type=="bluetooth")
370                                pos = from_string_set<mac_address>(bluetooth, pos, str );
371                        else if (type=="ip")
372                                pos = from_string_set<ip_address>(ip, pos, str );
373                        else if (type=="tcp")
374                                pos = from_string_set<tcp_port_address>(tcp, pos, str );
375                        else if (type=="rfcomm")
376                                pos = from_string_set<rfcomm_channel_address>(rfcomm, pos, str );
377                        else
378                                pos = str.find('}',pos);
379                }
380        }
381
382        endpoint_set& operator=( const endpoint_set& rhs ) {
383                scoped_lock lock(io_mutex);
384                this->bluetooth = rhs.bluetooth;
385                this->ip = rhs.ip;
386                this->rfcomm = rhs.rfcomm;
387                this->tcp = rhs.tcp;
388        }
389};
390
391}} // namespace ariba::addressing
392
393#endif /* ENDPOINT_SET_HPP_ */
Note: See TracBrowser for help on using the repository browser.