#ifndef ENDPOINT_SET_HPP_ #define ENDPOINT_SET_HPP_ #include "addressing.hpp" #include "tcpip_endpoint.hpp" #include #include #include #include namespace ariba { namespace addressing { using boost::unordered_set; /** * This end-point set shelters known addresses of a device. * Transport protocols use this class to address devices. * * Example of a string representation: * "tcp{500|501};ip{10.11.12.13};bluetooth{01:02:03:04:05:06};rfcomm{1234}" * Inside a address type specification, addresses are separated by a bar (|). * * @author Sebastian Mies */ class endpoint_set { public: // layer 2 unordered_set bluetooth; // layer 3 unordered_set ip; // layer 4 unordered_set tcp; unordered_set rfcomm; // mutex boost::mutex io_mutex; typedef boost::mutex::scoped_lock scoped_lock; private: template size_t to_bytes_dynamic( const unordered_set& set, uint8_t* bytes ) const { size_t size = 0; bytes[0] = type; uint8_t* size_ptr = bytes+1; bytes +=2; size += 2; BOOST_FOREACH( const V& value, set ) { bytes[0] = (uint8_t)value.to_bytes_size(); bytes++; size++; value.to_bytes(bytes); bytes += value.to_bytes_size(); size += value.to_bytes_size(); } *size_ptr = size-2; return size; } template void from_bytes_dynamic( unordered_set& set, const uint8_t* bytes, uint8_t size ) { size_t pos = 0; while (pos < size) { uint8_t length = bytes[0]; bytes++; pos++; V obj(bytes,length); set.insert(obj); bytes+=length; pos+=length; } } template size_t to_bytes_fixed( const unordered_set& set, uint8_t* bytes ) const { size_t fixed_size = V().to_bytes_size(); bytes[0] = type; bytes[1] = (uint8_t)(set.size()* fixed_size); bytes+=2; BOOST_FOREACH( const V& value, set ) { value.to_bytes(bytes); bytes += value.to_bytes_size(); } return 2 + set.size() * fixed_size; } template void from_bytes_fixed( unordered_set& set, const uint8_t* bytes, uint8_t size ) { size_t fixed_size = V().to_bytes_size(); uint8_t num = size/fixed_size; for (uint8_t i=0; i std::string to_string_set( const unordered_set& set, const std::string& type ) const { if (set.size()==0) return std::string(""); std::ostringstream buf; buf << type << "{"; bool first = true; BOOST_FOREACH( const V& value, set ) { if (!first) { buf << " | "; } else first = false; buf << value.to_string(); } buf << "};"; return buf.str(); } static void trim(string& str) { string::size_type pos = str.find_last_not_of(' '); if(pos != string::npos) { str.erase(pos + 1); pos = str.find_first_not_of(' '); if(pos != string::npos) str.erase(0, pos); } else str.erase(str.begin(), str.end()); } static string::size_type skip( const char* chars, string::size_type pos, const std::string& str ) { bool found = true; while (pos size_t from_string_set( unordered_set& set, string::size_type pos, const std::string& str ) { while (pos < str.size() && pos != string::npos) { pos = skip("} |\n\r", pos, str); string::size_type nend1 = str.find('}',pos); string::size_type nend2 = str.find('|',pos); if (nend1==string::npos && nend2==string::npos) break; if (nend1==string::npos) nend1=str.size(); if (nend2==string::npos) nend2=str.size(); string::size_type nend = nend2 < nend1 ? nend2:nend1; std::string sub = str.substr(pos, min(nend2,nend1)-pos); trim(sub); // cout << sub << endl; V obj( sub ); set.insert(obj); pos = nend+1; if (nend1instanceof () ) { const tcpip_endpoint& addr = *address; if (layers & Layer3 && !((layers & NoLoopback) && addr.address().is_loopback()) ) ip.insert( addr.address() ); if (layers & Layer4) tcp.insert( addr.port() ); } else if ( address->instanceof() ) { const ip_address& addr = *address; if ((layers & Layer3) && !((layers & NoLoopback) && addr.is_loopback())) ip.insert( addr ); } else if (address->instanceof() ) { const rfcomm_endpoint& endp = *address; if (layers & Layer2) bluetooth.insert( endp.mac() ); if (layers & Layer4) rfcomm.insert( endp.channel() ); } else if (address->instanceof() ) { const mac_address& endp = *address; if (layers & Layer2) bluetooth.insert( endp ); } } /// adds addresses from another endpoint set void add( const endpoint_set& eps, int layers = AllLayers ) { scoped_lock lock(io_mutex); // merge layer 2 addresses if (layers & Layer2) { bluetooth.insert(eps.bluetooth.begin(), eps.bluetooth.end() ); } // merge layer 3 addresses if (layers & Layer3) { ip.insert(eps.ip.begin(), eps.ip.end() ); } // merge layer 4 addresses if (layers & Layer4) { tcp.insert(eps.tcp.begin(), eps.tcp.end() ); rfcomm.insert(eps.rfcomm.begin(), eps.rfcomm.end() ); } } /// removes an address or endpoint from this set void remove( const address_vf address ) { scoped_lock lock(io_mutex); if ( address->instanceof () ) { const tcpip_endpoint& addr = *address; ip.erase( addr.address() ); tcp.erase( addr.port() ); } else if ( address->instanceof() ) { const ip_address& addr = *address; ip.erase( addr ); } else if (address->instanceof() ) { const rfcomm_endpoint& endp = *address; bluetooth.erase( endp.mac() ); rfcomm.erase( endp.channel() ); } } /// checks whether two end-points are disjoint /// (only check lower level addresses) bool disjoint_to( const endpoint_set& set ) const { scoped_lock lock(const_cast(io_mutex)); BOOST_FOREACH( const mac_address& mac, bluetooth ) if (set.bluetooth.count(mac) !=0 ) return false; BOOST_FOREACH( const ip_address& ip_, ip ) if (set.ip.count(ip_) !=0 ) return false; return true; } bool intersects_with( const endpoint_set& set ) const { return !disjoint_to(set); } bool is_subset_of( const endpoint_set& set ) const { throw "Not implemented!"; return false; } /// returns true, if this address has a fixed size in bytes bool is_bytes_size_static() const { return false; } /// returns the number of bytes used for serialization of this address size_t to_bytes_size() const { scoped_lock lock(const_cast(io_mutex)); size_t size = 0; // bluetooth mac list (layer 2) size += bluetooth.size() * mac_address().to_bytes_size(); // ip list (layer 3) BOOST_FOREACH( const ip_address& ip_, ip ) size += (ip_.to_bytes_size() + 1 /* =length */); // tcp ports (layer 4) size += tcp.size() * tcp_port_address().to_bytes_size(); // bluetooth rfcomm channels (layer 4) size += rfcomm.size() * rfcomm_channel_address().to_bytes_size(); // length/type encoding size += 4 /* number of items*/ * 2 /* length of type and length */; return size; } /// converts this address to a binary representation void to_bytes(uint8_t* bytes) const { scoped_lock lock(const_cast(io_mutex)); /// bluetooth mac list (layer 2) bytes += to_bytes_fixed<0x21, mac_address>( bluetooth, bytes ); // ip list (layer 3) bytes += to_bytes_dynamic<0x31, ip_address>(ip, bytes); // tcp ports (layer 4) bytes += to_bytes_fixed<0x41, tcp_port_address>( tcp, bytes ); // rfcomm channels (layer 4) bytes += to_bytes_fixed<0x42, rfcomm_channel_address>( rfcomm, bytes ); } /// Assigns an address using a bunch of bytes bool assign(const uint8_t* bytes, size_t size) { scoped_lock lock(io_mutex); size_t pos = 0; while (pos < size) { uint8_t type = bytes[0]; uint8_t length = bytes[1]; bytes+=2; pos+=2; switch (type) { // bluetooth mac case 0x21: { from_bytes_fixed( bluetooth, bytes, length ); break; } // ip case 0x31: { from_bytes_dynamic( ip, bytes, length ); break; } // tcp case 0x41: { from_bytes_fixed( tcp, bytes, length ); break; } // rfcomm case 0x42: { from_bytes_fixed( rfcomm, bytes, length ); break; } default: { pos = size; break; } } bytes += length; pos+=length; } return false; } /// generates a string out of this endpoint-set std::string to_string() const { scoped_lock lock(const_cast(io_mutex)); std::string smac = to_string_set(bluetooth, "bluetooth"); std::string sip = to_string_set(ip, "ip"); std::string stcp = to_string_set(tcp, "tcp"); std::string srfcomm = to_string_set(rfcomm, "rfcomm"); return smac+sip+stcp+srfcomm; } /// assigns an endpoint-set out of a string void assign( const std::string& str ) { scoped_lock lock(io_mutex); string::size_type pos = 0; while (pos < str.size() && pos!=string::npos) { pos = skip("}; \n\r", pos, str ); string::size_type nend = str.find('{',pos); if (nend == string::npos) break; std::string type = str.substr(pos,nend-pos); pos = nend+1; trim(type); if (type=="bluetooth") pos = from_string_set(bluetooth, pos, str ); else if (type=="ip") pos = from_string_set(ip, pos, str ); else if (type=="tcp") pos = from_string_set(tcp, pos, str ); else if (type=="rfcomm") pos = from_string_set(rfcomm, pos, str ); else pos = str.find('}',pos); } } endpoint_set& operator=( const endpoint_set& rhs ) { scoped_lock lock(io_mutex); this->bluetooth = rhs.bluetooth; this->ip = rhs.ip; this->rfcomm = rhs.rfcomm; this->tcp = rhs.tcp; return *this; } /// checks wheter the two endpoint sets are identical bool operator== ( const endpoint_set& rhs ) const { return (rhs.rfcomm == rfcomm && rhs.ip == ip && rhs.tcp == tcp && rhs.bluetooth == bluetooth); } bool operator!= ( const endpoint_set& rhs ) const { return !(*this==rhs); } }; }} // namespace ariba::addressing #endif /* ENDPOINT_SET_HPP_ */