[ASIO] Patch to support ATM sockets

Hi, These classes and examples add basic ATM support to ASIO. It works with MS visual studio 2010 (Windows XP) and gcc 4.1.2 (Linux CentOS 5.8), but it isn't always pretty. I only implemented and tested PVC's. ~Dan --------------------------- // stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #ifndef BOOST_STDAFX_HEAD #define BOOST_STDAFX_HEAD #ifdef _WIN32 #include "targetver.h" #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #endif #ifdef HAVE_ASIO_ATM // I forward declare my version of boost::asio::detail::socket_ops::bind so that // gcc 4.1.2 picks it up and uses it. // Otherwise, gcc doesn't consider my version; I'm not sure why. #include <boost/variant/variant_fwd.hpp> namespace boost { namespace system { class error_code; } } namespace boost { namespace asio { namespace atm { namespace detail { struct atmpvc_endpoint_type; struct atmsvc_endpoint_type; } } } } namespace boost { namespace asio { namespace detail { namespace socket_ops { int bind(int s, const boost::variant<boost::asio::atm::detail::atmpvc_endpoint_type, boost::asio::atm::detail::atmsvc_endpoint_type>* addr, size_t addrlen, boost::system::error_code& ec); } } } } #endif #include <boost/asio.hpp> #endif // BOOST_STDAFX_HEAD // Example echo server with ATM sockets // async_atm_echo_server.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <cstdlib> #include <iostream> #include <string> #include <boost/bind.hpp> #include <boost/asio.hpp> #include "boost/asio/atm/aal.hpp" using namespace boost::asio::atm; class server { public: server(boost::asio::io_service& io_service, const std::string &a) : io_service_(io_service) , socket_(io_service, aal::endpoint(address::from_string(a), qos::ubr_settings(1024u))) , data_() { socket_.async_receive( boost::asio::buffer(data_, max_length), boost::bind(&server::handle_receive_from, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void handle_receive_from(const boost::system::error_code& error, size_t bytes_recvd) { if (!error && bytes_recvd > 0) { socket_.async_send( boost::asio::buffer(data_, bytes_recvd), boost::bind(&server::handle_send_to, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else { socket_.async_receive( boost::asio::buffer(data_, max_length), boost::bind(&server::handle_receive_from, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } } void handle_send_to(const boost::system::error_code& /*error*/, size_t /*bytes_sent*/) { socket_.async_receive( boost::asio::buffer(data_, max_length), boost::bind(&server::handle_receive_from, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } private: boost::asio::io_service& io_service_; aal::socket socket_; enum { max_length = 1024 }; char data_[max_length]; }; int main(int argc, char** argv) { try { if (argc != 2) { std::cerr << "Usage: async_atm_echo_server <address>\n"; return 1; } boost::asio::io_service io_service; server s(io_service, argv[1]); io_service.run(); } catch (const std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; } // Example echo client with ATM sockets // blocking_atm_echo_client.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <cstdlib> #include <cstring> #include <iostream> #include <boost/asio.hpp> #include "boost/asio/atm/aal.hpp" using namespace boost::asio::atm; enum { max_length = 1024 }; int main(int argc, char** argv) { try { if (argc != 2) { std::cerr << "Usage: blocking_atm_echo_client <address>\n"; return 1; } boost::asio::io_service io_service; aal::socket s(io_service, aal::endpoint(address_pvc::from_string(argv[1]), qos::ubr_settings(1024u))); using namespace std; // for strlen std::cout << "Enter message: "; char request[max_length]; std::cin.getline(request, max_length); size_t request_length = strlen(request); s.send(boost::asio::buffer(request, request_length)); char reply[max_length]; size_t reply_length = s.receive(boost::asio::buffer(reply, max_length)); std::cout << "Reply is: "; std::cout.write(reply, reply_length); std::cout << "\n"; } catch (const std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; } /// \file boost/asio/atm/aal.hpp /// UNCLASSIFIED /// \brief Asynchronous Transfer Mode support for Boost ASIO #ifndef BOOST_ASIO_ATM_AAL_HEAD #define BOOST_ASIO_ATM_AAL_HEAD #ifdef HAVE_ASIO_ATM #include <boost/asio.hpp> #include <boost/variant.hpp> #include "basic_endpoint.hpp" namespace boost { namespace asio { using boost::asio::basic_raw_socket; namespace atm { /// \brief ATM Adaptation Layer template <class Implementation> class basic_aal { public: typedef Implementation implementation_type; /// The type of a ATM endpoint. typedef basic_endpoint<basic_aal> endpoint; static basic_aal aal5_pvc() { return basic_aal(implementation_type::aal5_protocol(), implementation_type::pvc_family()); } static basic_aal aal5_svc() { return basic_aal(implementation_type::aal5_protocol(), implementation_type::svc_family()); } /// Obtain an identifier for the type of the protocol. int type() const { // windows only support SOCK_RAW // The Linux examples use SOCK_DGRAM; is there a difference at application // level for AAL5 sockets? Can Linux use SOCK_RAW? return implementation_type::socket_type(); } /// Obtain an identifier for the protocol. int protocol() const { return protocol_; } /// Obtain an identifier for the protocol family. int family() const { return family_; } /// The ATM/AAL socket type. typedef basic_raw_socket<basic_aal> socket; /// The ATM/AAL resolver type. //typedef basic_resolver<atm> resolver; /// Compare two protocols for equality. friend bool operator==(const basic_aal& p1, const basic_aal& p2) { return p1.protocol_ == p2.protocol_ && p1.family_ == p2.family_ ; } /// Compare two protocols for inequality. friend bool operator!=(const basic_aal& p1, const basic_aal& p2) { return p1.protocol_ != p2.protocol_ || p1.family_ != p2.family_ ; } private: // Construct with a specific protocol. explicit basic_aal(const int protocol, const int family) : protocol_(protocol) , family_(family) { } int protocol_; int family_; }; // class basic_aal #if defined BOOST_WINDOWS || defined(__CYGWIN__) struct windows_atm { static int aal5_protocol() { return ATMPROTO_AAL5; } static int socket_type() { return SOCK_RAW; } static int pvc_family() { return AF_ATM; } static int svc_family() { return AF_ATM; } /// is this legal? //typedef template <class Protocol> basic_raw_socket socket_template; }; // windows_atm typedef basic_aal<windows_atm> aal; #else struct bsd_atm { static int aal5_protocol() { return 0; } static int socket_type() { return SOCK_RAW; } static int pvc_family() { return AF_ATMPVC; } static int svc_family() { return AF_ATMSVC; } /// is this legal? //typedef template <class Protocol> basic_raw_socket socket_template; }; // bsd_atm typedef basic_aal<bsd_atm> aal; #endif } // namespace atm } // namespace asio } // namespace boost #endif // HAVE_ASIO_ATM #endif // BOOST_ASIO_ATM_AAL_HEAD /// \file boost/asio/atm/address.hpp /// UNCLASSIFIED /// \brief Asynchronous Transfer Mode address for Boost ASIO #ifndef BOOST_ASIO_ATM_ADDRESS_HEAD #define BOOST_ASIO_ATM_ADDRESS_HEAD #include <string> #include <boost/asio.hpp> #include "address_pvc.hpp" #include "address_svc.hpp" namespace boost { namespace asio { namespace atm { using boost::system::error_code; class address { public: address() : type_(pvc) , pvc_address_() , svc_address_() { } address(const address_pvc &pvc_address) : type_(pvc) , pvc_address_(pvc_address) , svc_address_() { } address(const address_svc &svc_address) : type_(svc) , pvc_address_() , svc_address_(svc_address) { } address(const address &other) : type_(other.type_) , pvc_address_(other.pvc_address_) , svc_address_(other.svc_address_) { } bool is_pvc() const { return type_ == pvc; } bool is_svc() const { return type_ == svc; } const address_pvc& to_pvc() const { return pvc_address_; } const address_svc& to_svc() const { return svc_address_; } std::string to_string() const { if (is_pvc()) { return pvc_address_.to_string(); } return svc_address_.to_string(); } std::string to_string(error_code &error) const { if (is_pvc()) { return pvc_address_.to_string(error); } return svc_address_.to_string(error); } static address from_string(const char * str) { error_code error; const address addr = from_string(str, error); boost::asio::detail::throw_error(error); return addr; } static address from_string(const char * str, error_code &error) { const address_pvc pvc_address = address_pvc::from_string(str, error); if (!error) { return address(pvc_address); } const address_svc svc_address = address_svc::from_string(str, error); if (!error) { return address(svc_address); } return address(); } static address from_string(const std::string &str) { return from_string(str.c_str()); } static address from_string(const std::string &str, error_code &error) { return from_string(str.c_str(), error); } /// Compare two addresses for equality. friend bool operator==(const address& a1, const address& a2) { if (a1.type_ != a2.type_) { return false; } if (a1.type_ == pvc) { return a1.pvc_address_ == a2.pvc_address_; } return a1.svc_address_ == a2.svc_address_; } /// Compare two addresses for inequality. friend bool operator!=(const address& a1, const address& a2) { return !(a1 == a2); } /// Compare addresses for ordering. friend bool operator<(const address& a1, const address& a2) { if (a1.type_ < a2.type_) { return true; } if (a1.type_ > a2.type_) { return false; } if (a1.type_ == pvc) { return a1.pvc_address_ < a2.pvc_address_; } return a1.svc_address_ < a2.svc_address_; } /// Compare addresses for ordering. friend bool operator>(const address& a1, const address& a2) { return a2 < a1; } /// Compare addresses for ordering. friend bool operator<=(const address& a1, const address& a2) { return !(a2 < a1); } /// Compare addresses for ordering. friend bool operator>=(const address& a1, const address& a2) { return !(a1 < a2); } private: enum { svc, pvc } type_; address_pvc pvc_address_; address_svc svc_address_; }; // class address #if !defined(BOOST_NO_IOSTREAM) /// Output an address as a string. /** * Used to output a human-readable string for a specified address. * * @param os The output stream to which the string will be written. * * @param addr The address to be written. * * @return The output stream. * * @relates boost::asio::atm::address_pvc */ template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address& addr); #endif // !defined(BOOST_NO_IOSTREAM) } // namespace atm } // namespace asio } // namespace boost #endif // BOOST_ASIO_ATM_ADDRESS_HEAD /// \file boost/asio/atm/address_pvc.hpp /// UNCLASSIFIED /// \brief Asynchronous Transfer Mode PVC address for Boost ASIO #ifndef BOOST_ASIO_ATM_ADDRESS_PVC_HEAD #define BOOST_ASIO_ATM_ADDRESS_PVC_HEAD #include <string> #include <vector> #include <sstream> #include <boost/asio.hpp> #include <boost/algorithm/string.hpp> #include "detail/socket_types.hpp" #include "detail/socket_ops.hpp" namespace boost { namespace asio { namespace atm { using boost::system::error_code; class address_pvc { public: address_pvc() : addr_() { detail::socket_ops::initialize(addr_); } address_pvc(const address_pvc &other) : addr_(other.addr_) { } address_pvc(const detail::atmpvc_addr_type &a) : addr_(a) { } address_pvc(const unsigned long vpi, const unsigned long vci) : addr_() { detail::socket_ops::initialize(addr_); set_vpi(vpi); set_vci(vci); } unsigned long itf() const { return detail::socket_ops::itf(addr_); } void set_itf(const unsigned long i) { return detail::socket_ops::set_itf(i, addr_); } unsigned long vpi() const { return detail::socket_ops::vpi(addr_); } void set_vpi(const unsigned long v) { return detail::socket_ops::set_vpi(v, addr_); } unsigned long vci() const { return detail::socket_ops::vci(addr_); } void set_vci(const unsigned long v) { return detail::socket_ops::set_vci(v, addr_); } const detail::atmpvc_addr_type* data() const { return &addr_; } std::string to_string() const { error_code error; const std::string str = to_string(error); boost::asio::detail::throw_error(error); return str; } std::string to_string(error_code &error) const { std::ostringstream strm; strm << itf() << "." << vpi() << "." << vci(); return strm.str(); } static address_pvc from_string(const char *str) { error_code error; const address_pvc addr = from_string(str, error); boost::asio::detail::throw_error(error); return addr; } static address_pvc from_string(const char *str, error_code &error) { return from_string(std::string(str), error); } static address_pvc from_string(const std::string &str) { return from_string(str.c_str()); } static address_pvc from_string(const std::string &str, error_code &error) { typedef std::vector<std::string> container; address_pvc addr; container tokens; boost::split(tokens, str, boost::is_any_of(".")); if (tokens.empty()) { tokens.push_back(str); } container::const_reverse_iterator i = tokens.rbegin(); // Read the VCI first std::istringstream vci_strm(*i); unsigned long vci; if (!(vci_strm >> vci)) { error = boost::asio::error::invalid_argument; return addr; } addr.set_vci(vci); advance(i, 1); if (i == tokens.rend()) { return addr; } // Read the VPI std::istringstream vpi_strm(*i); unsigned long vpi; if (!(vpi_strm >> vpi)) { error = boost::asio::error::invalid_argument; return addr; } addr.set_vpi(vpi); advance(i, 1); if (i == tokens.rend()) { return addr; } // Read the ITF std::istringstream itf_strm(*i); unsigned long itf; if (!(itf_strm >> itf)) { error = boost::asio::error::invalid_argument; return addr; } addr.set_itf(itf); advance(i, 1); if (i != tokens.rend()) { error = boost::asio::error::invalid_argument; } return addr; } /// Compare two addresses for equality. friend bool operator==(const address_pvc& a1, const address_pvc& a2) { return a1.itf() == a2.itf() && a1.vpi() == a2.vpi() && a2.vci() == a2.vci() ; } /// Compare two address_pvces for inequality. friend bool operator!=(const address_pvc& a1, const address_pvc& a2) { return !(a1 == a2); } /// Compare address_pvces for ordering. friend bool operator<(const address_pvc& a1, const address_pvc& a2) { if (a1.itf() < a2.itf()) { return true; } if (a1.itf() > a2.itf()) { return false; } if (a1.vpi() < a2.vpi()) { return true; } if (a1.vpi() > a2.vpi()) { return false; } return a1.vci() < a2.vci(); } /// Compare address_pvces for ordering. friend bool operator>(const address_pvc& a1, const address_pvc& a2) { return a2 < a1; } /// Compare address_pvces for ordering. friend bool operator<=(const address_pvc& a1, const address_pvc& a2) { return !(a2 < a1); } /// Compare address_pvces for ordering. friend bool operator>=(const address_pvc& a1, const address_pvc& a2) { return !(a1 < a2); } private: detail::atmpvc_addr_type addr_; }; // class address_pvc #if !defined(BOOST_NO_IOSTREAM) /// Output an address as a string. /** * Used to output a human-readable string for a specified address. * * @param os The output stream to which the string will be written. * * @param addr The address to be written. * * @return The output stream. * * @relates boost::asio::atm::address_pvc */ template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address_pvc& addr); #endif // !defined(BOOST_NO_IOSTREAM) } // namespace atm } // namespace asio } // namespace boost #endif // BOOST_ASIO_ATM_ADDRESS_PVC_HEAD /// \file boost/asio/atm/address_svc.hpp /// UNCLASSIFIED /// \brief Asynchronous Transfer Mode SVC address for Boost ASIO #ifndef BOOST_ASIO_ATM_ADDRESS_SVC_HEAD #define BOOST_ASIO_ATM_ADDRESS_SVC_HEAD #include <string> #include <boost/asio.hpp> #include "detail/socket_types.hpp" namespace boost { namespace asio { namespace atm { using boost::system::error_code; class address_svc { public: address_svc() : addr_() { } address_svc(const detail::atmsvc_addr_type& a) : addr_(a) { } address_svc(const address_svc &other) : addr_(other.addr_) { } const detail::atmsvc_addr_type* data() const { return &addr_; } std::string to_string() const { error_code error; const std::string str = to_string(error); boost::asio::detail::throw_error(error); return str; } std::string to_string(error_code &error) const { return ""; } static address_svc from_string(const char *str) { error_code error; const address_svc addr = from_string(str, error); boost::asio::detail::throw_error(error); return addr; } static address_svc from_string(const char *str, error_code &error) { address_svc addr; return addr; } static address_svc from_string(const std::string &str) { return from_string(str.c_str()); } static address_svc from_string(const std::string &str, error_code &error) { return from_string(str.c_str(), error); } /// Compare two addresses for equality. friend bool operator==(const address_svc& a1, const address_svc& a2) { return false; } /// Compare two address_svces for inequality. friend bool operator!=(const address_svc& a1, const address_svc& a2) { return !(a1 == a2); } /// Compare address_svces for ordering. friend bool operator<(const address_svc& a1, const address_svc& a2) { return false; } /// Compare address_svces for ordering. friend bool operator>(const address_svc& a1, const address_svc& a2) { return a2 < a1; } /// Compare address_svces for ordering. friend bool operator<=(const address_svc& a1, const address_svc& a2) { return !(a2 < a1); } /// Compare address_svces for ordering. friend bool operator>=(const address_svc& a1, const address_svc& a2) { return !(a1 < a2); } private: detail::atmsvc_addr_type addr_; }; // class address_svc #if !defined(BOOST_NO_IOSTREAM) /// Output an address as a string. /** * Used to output a human-readable string for a specified address. * * @param os The output stream to which the string will be written. * * @param addr The address to be written. * * @return The output stream. * * @relates boost::asio::atm::address_svc */ template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address_svc& addr); #endif // !defined(BOOST_NO_IOSTREAM) } // namespace atm } // namespace asio } // namespace boost #endif // BOOST_ASIO_ATM_ADDRESS_SVC_HEAD /// \file boost/asio/atm/basic_endpoint.hpp /// UNCLASSIFIED /// \brief Endpoint for ATM sockets #ifndef BOOST_ASIO_ATM_BASIC_ENDPOINT_HEAD #define BOOST_ASIO_ATM_BASIC_ENDPOINT_HEAD #include <boost/asio.hpp> #include "address.hpp" #include "qos.hpp" #include "detail/endpoint.hpp" namespace boost { namespace asio { namespace atm { template <typename AsynchronousTransferModeProtocol> class basic_endpoint { public: /// The protocol type associated with the endpoint. typedef AsynchronousTransferModeProtocol protocol_type; /// The type of the endpoint structure. This type is dependent on the /// underlying implementation of the socket layer. typedef boost::asio::atm::detail::endpoint endpoint_impl; typedef endpoint_impl::data_type data_type; /// Default constructor. basic_endpoint() : impl_() { } /// Construct an endpoint using an ATM address. This /// constructor may be used for accepting connections on a specific interface /// or for making a connection to a remote endpoint. basic_endpoint(const boost::asio::atm::address& addr) : impl_(addr) { } /// Construct an endpoint using an ATM address and Quality Of Service settings. This /// constructor may be used for accepting connections on a specific interface /// or for making a connection to a remote endpoint. basic_endpoint(const boost::asio::atm::address& addr, const qos::settings &qos) : impl_(addr, qos) { } /// Copy constructor. basic_endpoint(const basic_endpoint& other) : impl_(other.impl_) { } #if defined(BOOST_ASIO_HAS_MOVE) /// Move constructor. basic_endpoint(basic_endpoint&& other) : impl_(other.impl_) { } #endif // defined(BOOST_ASIO_HAS_MOVE) /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) { impl_ = other.impl_; return *this; } #if defined(BOOST_ASIO_HAS_MOVE) /// Move-assign from another endpoint. basic_endpoint& operator=(basic_endpoint&& other) { impl_ = other.impl_; return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) /// The protocol associated with the endpoint. protocol_type protocol() const { if (is_svc()) { return AsynchronousTransferModeProtocol::aal5_svc(); } return AsynchronousTransferModeProtocol::aal5_pvc(); } bool is_pvc() const { return impl_.is_pvc(); } bool is_svc() const { return impl_.is_svc(); } /// Get the underlying endpoint in the native type. data_type* data() { return impl_.data(); } /// Get the underlying endpoint in the native type. const data_type* data() const { return impl_.data(); } /// Get the underlying size of the endpoint in the native type. std::size_t size() const { return impl_.size(); } /// Set the underlying size of the endpoint in the native type. void resize(std::size_t new_size) { return impl_.resize(new_size); } /// Get the capacity of the endpoint in the native type. std::size_t capacity() const { return impl_.capacity(); } /// Get the IP address associated with the endpoint. const boost::asio::atm::address address() const { return impl_.address(); } /// Set the IP address associated with the endpoint. void address(const boost::asio::atm::address& addr) { impl_.address(addr); } /// Compare two endpoints for equality. friend bool operator==(const basic_endpoint<AsynchronousTransferModeProtocol>& e1, const basic_endpoint<AsynchronousTransferModeProtocol>& e2) { return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint<AsynchronousTransferModeProtocol>& e1, const basic_endpoint<AsynchronousTransferModeProtocol>& e2) { return !(e1 == e2); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint<AsynchronousTransferModeProtocol>& e1, const basic_endpoint<AsynchronousTransferModeProtocol>& e2) { return e1.impl_ < e2.impl_; } /// Compare endpoints for ordering. friend bool operator>(const basic_endpoint<AsynchronousTransferModeProtocol>& e1, const basic_endpoint<AsynchronousTransferModeProtocol>& e2) { return e2.impl_ < e1.impl_; } /// Compare endpoints for ordering. friend bool operator<=(const basic_endpoint<AsynchronousTransferModeProtocol>& e1, const basic_endpoint<AsynchronousTransferModeProtocol>& e2) { return !(e2 < e1); } /// Compare endpoints for ordering. friend bool operator>=(const basic_endpoint<AsynchronousTransferModeProtocol>& e1, const basic_endpoint<AsynchronousTransferModeProtocol>& e2) { return !(e1 < e2); } private: // The underlying ATM endpoint. endpoint_impl impl_; }; // class basic_endpoint #if !defined(BOOST_NO_IOSTREAM) /// Output an endpoint as a string. /** * Used to output a human-readable string for a specified endpoint. * * @param os The output stream to which the string will be written. * * @param endpoint The endpoint to be written. * * @return The output stream. * * @relates boost::asio::atm::basic_endpoint */ template <typename Elem, typename Traits, typename AsynchronousTransferModeProtocol> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const basic_endpoint<AsynchronousTransferModeProtocol>& endpoint); #endif // !defined(BOOST_NO_IOSTREAM) } // namespace atm } // namespace asio } // namespace boost #include "basic_endpoint.ipp" #endif // BOOST_ASIO_ATM_BASIC_ENDPOINT_HEAD /// \file boost/asio/atm/basic_endpoint.ipp /// UNCLASSIFIED #ifndef BOOST_ASIO_ATM_BASIC_ENDPOINT_IMPL #define BOOST_ASIO_ATM_BASIC_ENDPOINT_IMPL #include "address.hpp" namespace boost { namespace asio { namespace atm { template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& os, const address_pvc& addr) { if (os) { os << addr.to_string(); } return os; } template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& os, const address& addr) { if (os) { os << addr.to_string(); } return os; } #if !defined(BOOST_NO_IOSTREAM) template <typename Elem, typename Traits, typename AsynchronousTransferModeProtocol> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const basic_endpoint<AsynchronousTransferModeProtocol>& endpoint) { if (os) { os << endpoint.address(); } return os; } #endif // !defined(BOOST_NO_IOSTREAM) } // namespace atm } // namespace asio } // namespace boost #endif // BOOST_ASIO_ATM_BASIC_ENDPOINT_IMPL /// \file boost/asio/atm/qos.hpp /// UNCLASSIFIED /// \brief Asynchronous Transfer Mode QOS for Boost ASIO #ifndef BOOST_ASIO_ATM_QOS_HEAD #define BOOST_ASIO_ATM_QOS_HEAD #include <boost/variant.hpp> #include "detail/socket_types.hpp" namespace boost { namespace asio { namespace atm { namespace qos { struct do_not_use_qos { do_not_use_qos() { } }; struct ubr_settings { unsigned long peak_cell_rate; ubr_settings() : peak_cell_rate(0u) { } ubr_settings(const unsigned long r) : peak_cell_rate(r) { } }; struct cbr_settings { unsigned long peak_cell_rate; cbr_settings() : peak_cell_rate(0u) { } }; struct vbr_settings { unsigned long peak_cell_rate; unsigned long substainable_cell_rate; unsigned long max_burst_size; vbr_settings() : peak_cell_rate(0u), substainable_cell_rate(0u), max_burst_size(0u) { } }; struct abr_settings { unsigned long peak_cell_rate; unsigned long minimum_cell_rate; unsigned long allowed_cell_rate; unsigned long initial_cell_rate; unsigned long rate_increase_factor; unsigned long rate_decrease_factor; unsigned long cut_off_decrease_factor; abr_settings() : peak_cell_rate(0u) , minimum_cell_rate(0u) , allowed_cell_rate(0u) , initial_cell_rate(0u) , rate_increase_factor(0u) , rate_decrease_factor(0u) , cut_off_decrease_factor(0u) { } }; typedef boost::variant<do_not_use_qos, ubr_settings, cbr_settings, vbr_settings, abr_settings> settings; } // namespace qos } // namespace atm } // namespace asio } // namespace boost #include "detail/qos.hpp" #endif // BOOST_ASIO_ATM_QOS_HEAD /// \file boost/asio/atm/detail/endpoint.hpp /// UNCLASSIFIED /// \brief Endpoint for ATM sockets #ifndef BOOST_ASIO_ATM_DETAIL_ENDPOINT_HEAD #define BOOST_ASIO_ATM_DETAIL_ENDPOINT_HEAD #include <boost/asio.hpp> #include <boost/variant.hpp> #include "boost/asio/atm/address.hpp" #include "boost/asio/atm/detail/socket_types.hpp" #include "boost/asio/atm/qos.hpp" namespace boost { namespace asio { namespace atm { namespace detail { class endpoint_data_size_visitor : public boost::static_visitor<std::size_t> { public: std::size_t operator()(const atmpvc_endpoint_type& params) const { return sizeof(atmpvc_endpoint_type); } std::size_t operator()(const atmsvc_endpoint_type &ep) const { return sizeof(atmsvc_endpoint_type); } }; // class endpoint_data_size_visitor class endpoint_address_visitor : public boost::static_visitor<boost::asio::atm::address> { public: boost::asio::atm::address operator()(const atmpvc_endpoint_type& ep) const { return boost::asio::atm::address_pvc(ep.native_connection_id()); } boost::asio::atm::address operator()(const atmsvc_endpoint_type &ep) const { return boost::asio::atm::address_svc(ep.native_connection_id()); } }; // class endpoint_data_size_visitor class endpoint { public: typedef boost::asio::atm::detail::atm_endpoint_type data_type; endpoint() : data_() , qos_() { } /// \todo Add QOS parameters to this constructor endpoint(const boost::asio::atm::address& addr, const qos::settings &qos = qos::do_not_use_qos()) : data_() , qos_(qos) { address(addr); } bool is_pvc() const { return boost::get<atmpvc_endpoint_type*>(&data_) != NULL; } bool is_svc() const { return boost::get<atmsvc_endpoint_type*>(&data_) != NULL; } /// Get the underlying endpoint in the native type. data_type* data() { return &data_; } /// Get the underlying endpoint in the native type. const data_type* data() const { return &data_; } std::size_t size() const { return boost::apply_visitor(endpoint_data_size_visitor(), data_); } void resize(const std::size_t new_size) { if (new_size > sizeof(data_type)) { boost::system::error_code ec(boost::asio::error::invalid_argument); boost::asio::detail::throw_error(ec); } } std::size_t capacity() const { return sizeof(data_type); } boost::asio::atm::address address() const { return boost::apply_visitor(endpoint_address_visitor(), data_); } void address(const boost::asio::atm::address& addr) { if (addr.is_pvc()) { const address_pvc my_pvc_addr = addr.to_pvc(); atmpvc_endpoint_type my_data; boost::apply_visitor(boost::asio::atm::qos::detail::pvc_visitor(my_data), qos_); my_data.assign(*my_pvc_addr.data()); data_ = my_data; } } friend bool operator==(const endpoint& e1, const endpoint& e2) { return e1.address() == e2.address(); } /// Compare endpoints for ordering. friend bool operator<(const endpoint& e1, const endpoint& e2) { return e1.address() < e2.address(); } private: data_type data_; qos::settings qos_; }; // class endpoint } // namespace detail } // namespace atm } // namespace asio } // namespace boost #include "boost/asio/atm/detail/impl/endpoint.ipp" #endif // BOOST_ASIO_ATM_DETAIL_ENDPOINT_HEAD /// \file boost/asio/atm/detail/qos.hpp /// UNCLASSIFIED /// \brief Asynchronous Transfer Mode QOS details for Boost ASIO #ifndef BOOST_ASIO_ATM_DETAIL_QOS_HEAD #define BOOST_ASIO_ATM_DETAIL_QOS_HEAD namespace boost { namespace asio { namespace atm { namespace qos { namespace detail { class pvc_visitor : public boost::static_visitor<> { public: pvc_visitor(boost::asio::atm::detail::atmpvc_endpoint_type &p) : boost::static_visitor<>() , data(p) { } void operator()(const do_not_use_qos &) const; void operator()(const ubr_settings &ubr) const; void operator()(const cbr_settings &cbr) const; void operator()(const vbr_settings &vbr) const; void operator()(const abr_settings &abr) const; private: boost::asio::atm::detail::atmpvc_endpoint_type& data; }; } // namespace detail } // namespace qos } // namespace atm } // namespace asio } // namespace boost #endif // BOOST_ASIO_ATM_DETAIL_QOS_HEAD #include "boost/asio/atm/detail/impl/qos.ipp" /// \file boost/asio/atm/detail/socket_ops.hpp /// UNCLASSIFIED /// \brief Asynchronous Transfer Mode socket operations for Boost ASIO #ifndef BOOST_ASIO_ATM_DETAIL_SOCKET_OPS_HEAD #define BOOST_ASIO_ATM_DETAIL_SOCKET_OPS_HEAD #include <boost/variant.hpp> #include <boost/asio.hpp> #include <boost/exception/all.hpp> #include "boost/asio/atm/detail/socket_types.hpp" namespace boost { namespace asio { namespace atm { namespace detail { namespace socket_ops { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) inline void initialize(atmpvc_addr_type& addr) { memset(&addr, 0, sizeof(atmpvc_addr_type)); } inline void set_itf(const unsigned long itf, atmpvc_addr_type& addr) { addr.DeviceNumber = itf; } inline unsigned long itf(const atmpvc_addr_type& addr) { return addr.DeviceNumber; } inline void set_vci(const unsigned long vci, atmpvc_addr_type& addr) { addr.VCI = vci; } inline unsigned long vci(const atmpvc_addr_type& addr) { return addr.VCI; } inline void set_vpi(const unsigned long vpi, atmpvc_addr_type& addr) { addr.VPI = vpi; } inline unsigned long vpi(const atmpvc_addr_type& addr) { return addr.VPI; } #else // ! (BOOST_WINDOWS || __CYGWIN__) inline void initialize(atmpvc_addr_type& addr) { memset(&addr, 0, sizeof(atmpvc_addr_type)); addr.sap_family = AF_ATMPVC; } inline void set_itf(const unsigned long itf, atmpvc_addr_type& addr) { addr.sap_addr.itf = itf; } inline unsigned long itf(const atmpvc_addr_type& addr) { return addr.sap_addr.itf; } inline void set_vci(const unsigned long vci, atmpvc_addr_type& addr) { addr.sap_addr.vci = vci; } inline unsigned long vci(const atmpvc_addr_type& addr) { return addr.sap_addr.vci; } inline void set_vpi(const unsigned long vpi, atmpvc_addr_type& addr) { addr.sap_addr.vpi = vpi; } inline unsigned long vpi(const atmpvc_addr_type& addr) { return addr.sap_addr.vpi; } #endif // BOOST_WINDOWS || __CYGWIN__ } // namespace socket_ops class bind_endpoint_visitor : public boost::static_visitor<int> { public: bind_endpoint_visitor(const boost::asio::detail::socket_type s, boost::system::error_code &ec) : socket_(s) , ec_(ec) { } /// Set the VCI/VPI pair for a permament virtual circuit (PVC) int operator()(const atmpvc_endpoint_type& params) const; int operator()(const atmsvc_endpoint_type& params) const; private: boost::asio::detail::socket_type socket_; boost::system::error_code& ec_; }; // class bind_endpoint_visitor } // namespace detail } // namespace atm } // namespace asio } // namespace boost namespace boost { namespace asio { namespace detail { namespace socket_ops { BOOST_ASIO_DECL int bind(socket_type s, const boost::asio::atm::detail::atm_endpoint_type* addr, std::size_t addrlen, boost::system::error_code& ec) { return boost::apply_visitor(boost::asio::atm::detail::bind_endpoint_visitor(s, ec), *addr); } } // namespace socket_ops } // namespace detail } // namespace asio } // namespace boost #endif // BOOST_ASIO_ATM_DETAIL_SOCKET_OPS_HEAD /// \file boost/asio/atm/detail/socket_option.hpp /// UNCLASSIFIED /// \brief Asynchronous Transfer Mode socket options for Boost ASIO #ifndef BOOST_ASIO_ATM_DETAIL_SOCKET_OPTION_HEAD #define BOOST_ASIO_ATM_DETAIL_SOCKET_OPTION_HEAD #include <boost/asio.hpp> namespace boost { namespace asio { namespace atm { namespace detail { namespace socket_option { class qos { public: template <typename Protocol> int level(const Protocol& protocol) const { } template <typename Protocol> int name(const Protocol& protocol) const { } template <typename Protocol> void* data(const Protocol& protocol) { } template <typename Protocol> const void* data(const Protocol& protocol) const { } template <typename Protocol> std::size_t size(const Protocol& protocol) const { } template <typename Protocol> void resize(const Protocol& protocol, std::size_t s) { } private: }; // class qos } // namespace socket_option } // namespace detail } // namespace atm } // namespace asio } // namespace boost #endif // BOOST_ASIO_ATM_DETAIL_SOCKET_OPTION_HEAD /// \file boost/asio/atm/detail/socket_types.hpp /// UNCLASSIFIED /// \brief Asynchronous Transfer Mode socket types for Boost ASIO #ifndef BOOST_ASIO_ATM_DETAIL_SOCKET_TYPES_HEAD #define BOOST_ASIO_ATM_DETAIL_SOCKET_TYPES_HEAD #include <string> #include <boost/asio.hpp> #include <boost/variant.hpp> #if defined HAVE_ATM_H extern "C" { # include <atm.h> } #elif defined HAVE_SYS_NETATM_ATM_H # include <sys/netatm/atm.h> #elif defined _WIN32 # include <ws2atm.h> #else # error There is no ATM header to include #endif namespace boost { namespace asio { namespace atm { namespace detail { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef sockaddr_atm atmsvc_addr_type; typedef ATM_CONNECTION_ID atmpvc_addr_type; /// \note Wrap the ATM_PVC_PARAMS so that I have a place to default construct it. struct atmpvc_endpoint_type { ATM_PVC_PARAMS native_; atmpvc_endpoint_type() : native_() { // Initialize Qos Settings with default values : UBR without specified Qos native_.PvcQos.ReceivingFlowspec.TokenRate = QOS_NOT_SPECIFIED; native_.PvcQos.ReceivingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED; native_.PvcQos.ReceivingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED; native_.PvcQos.ReceivingFlowspec.Latency = QOS_NOT_SPECIFIED; native_.PvcQos.ReceivingFlowspec.DelayVariation = QOS_NOT_SPECIFIED; native_.PvcQos.ReceivingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT; native_.PvcQos.ReceivingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED; native_.PvcQos.ReceivingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED; native_.PvcQos.SendingFlowspec.TokenRate = QOS_NOT_SPECIFIED; native_.PvcQos.SendingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED; native_.PvcQos.SendingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED; native_.PvcQos.SendingFlowspec.Latency = QOS_NOT_SPECIFIED; native_.PvcQos.SendingFlowspec.DelayVariation = QOS_NOT_SPECIFIED; native_.PvcQos.SendingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT; native_.PvcQos.SendingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED; native_.PvcQos.SendingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED; } const ATM_PVC_PARAMS &native() const { return native_; } const ATM_CONNECTION_ID &native_connection_id() const { return native_.PvcConnectionId; } void assign(const ATM_CONNECTION_ID &i) { native_.PvcConnectionId = i; } }; struct atmsvc_endpoint_type { sockaddr_atm native_; atmsvc_endpoint_type() : native_() { } const sockaddr_atm &native() const { return native_; } const sockaddr_atm &native_connection_id() const { return native_; } void assign(const sockaddr_atm &i) { native_ = i; } }; #else typedef sockaddr_atmsvc atmsvc_addr_type; typedef sockaddr_atmpvc atmpvc_addr_type; typedef atm_qos atm_qos_type; struct atmpvc_endpoint_type { atmpvc_addr_type addr; atm_qos_type qos; atmpvc_endpoint_type() : addr() , qos() { qos.aal = ATM_AAL5; } const atmpvc_addr_type &native() const { return addr; } const atmpvc_addr_type &native_connection_id() const { return addr; } void assign(const atmpvc_addr_type &a) { addr = a; } }; struct atmsvc_endpoint_type { atmsvc_addr_type addr; atm_qos_type qos; const atmsvc_addr_type &native() const { return addr; } const atmsvc_addr_type &native_connection_id() const { return addr; } void assign(const atmsvc_addr_type &a) { addr = a; } }; #endif // BOOST_WINDOWS || __CYGWIN__ typedef boost::variant<atmpvc_endpoint_type, atmsvc_endpoint_type> atm_endpoint_type; } // namespace detail } // namespace atm } // namespace asio } // namespace boost #endif // BOOST_ASIO_ATM_DETAIL_SOCKET_TYPES_HEAD /// \file boost/asio/atm/detail/impl/endpoint.ipp /// UNCLASSIFIED /// \brief Endpoint for ATM sockets #ifndef BOOST_ASIO_ATM_DETAIL_ENDPOINT_IPP #define BOOST_ASIO_ATM_DETAIL_ENDPOINT_IPP namespace boost { namespace asio { namespace atm { namespace detail { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) int bind_endpoint_visitor::operator()(const atmpvc_endpoint_type& params) const { using boost::asio::detail::socket_ops::error_wrapper; DWORD out_bytes; /// \todo What gets placed in out_bytes? return error_wrapper(WSAIoctl(socket_, SIO_ASSOCIATE_PVC, (LPVOID) ¶ms.native(), sizeof(ATM_PVC_PARAMS), NULL, 0, &out_bytes, NULL, NULL), ec_); } int bind_endpoint_visitor::operator()(const atmsvc_endpoint_type& params) const { ec_ = boost::asio::error::invalid_argument; return -1; } #else // ! (BOOST_WINDOWS || __CYGWIN__) int bind_endpoint_visitor::operator()(const atmpvc_endpoint_type& params) const { // I am not convinced that this is the best place to set the ATM QOS // options, but it makes the implementation consistent with Windows. // Also, it makes the socket constructors that accept an endpoint work. // I probably need an equivalent for "connect" and "listen." boost::asio::detail::socket_ops::state_type my_state; if (const int result = boost::asio::detail::socket_ops::setsockopt(socket_, my_state, SOL_ATM, SO_ATMQOS, ¶ms.qos, sizeof(params.qos), ec_)) { return result; } return boost::asio::detail::socket_ops::bind(socket_, (struct sockaddr *) ¶ms.addr, sizeof(params.addr), ec_); } int bind_endpoint_visitor::operator()(const atmsvc_endpoint_type& params) const { ec_ = boost::asio::error::invalid_argument; return -1; } #endif // end defined(BOOST_WINDOWS) || defined(__CYGWIN__) } // namespace detail } // namespace atm } // namespace asio } // namespace boost #endif // BOOST_ASIO_ATM_DETAIL_ENDPOINT_IPP /// \file boost/asio/atm/detail/impl/qos.ipp /// UNCLASSIFIED /// \brief Asynchronous Transfer Mode QOS implementation #ifndef BOOST_ASIO_ATM_QOS_IPP #define BOOST_ASIO_ATM_QOS_IPP namespace boost { namespace asio { namespace atm { namespace qos { namespace detail { #if defined BOOST_WINDOWS || __CYGWIN__ void pvc_visitor::operator()(const do_not_use_qos &) const { } void pvc_visitor::operator()(const ubr_settings &ubr) const { data.native_.PvcQos.SendingFlowspec.PeakBandwidth = ubr.peak_cell_rate * 48u; } void pvc_visitor::operator()(const cbr_settings &cbr) const { data.native_.PvcQos.SendingFlowspec.ServiceType = SERVICETYPE_GUARANTEED; data.native_.PvcQos.ReceivingFlowspec.ServiceType = SERVICETYPE_GUARANTEED; data.native_.PvcQos.SendingFlowspec.PeakBandwidth = cbr.peak_cell_rate * 48u; } void pvc_visitor::operator()(const vbr_settings &vbr) const { data.native_.PvcQos.SendingFlowspec.ServiceType = SERVICETYPE_CONTROLLEDLOAD; data.native_.PvcQos.ReceivingFlowspec.ServiceType = SERVICETYPE_CONTROLLEDLOAD; data.native_.PvcQos.SendingFlowspec.PeakBandwidth = vbr.peak_cell_rate * 48u; data.native_.PvcQos.SendingFlowspec.TokenRate = vbr.substainable_cell_rate * 48u; data.native_.PvcQos.SendingFlowspec.TokenBucketSize = vbr.max_burst_size * 48u; } void pvc_visitor::operator()(const abr_settings &abr) const { } #else void pvc_visitor::operator()(const do_not_use_qos &) const { data.qos.txtp.traffic_class = ATM_NONE; data.qos.txtp.traffic_class = ATM_NONE; } void pvc_visitor::operator()(const ubr_settings &ubr) const { data.qos.txtp.traffic_class = ATM_UBR; data.qos.rxtp.traffic_class = ATM_UBR; data.qos.rxtp.max_sdu = ubr.peak_cell_rate; data.qos.txtp.max_pcr = ubr.peak_cell_rate; } void pvc_visitor::operator()(const cbr_settings &cbr) const { data.qos.txtp.traffic_class = ATM_CBR; data.qos.rxtp.traffic_class = ATM_CBR; //data.qos.txtp.ServiceType = SERVICETYPE_GUARANTEED; //data.native.qos.rxtp.ServiceType = SERVICETYPE_GUARANTEED; data.qos.txtp.max_pcr = cbr.peak_cell_rate; } void pvc_visitor::operator()(const vbr_settings &vbr) const { data.qos.txtp.traffic_class = ATM_VBR; data.qos.rxtp.traffic_class = ATM_VBR; //data.qos.txtp.ServiceType = SERVICETYPE_CONTROLLEDLOAD; //data.qos.rxtp.ServiceType = SERVICETYPE_CONTROLLEDLOAD; data.qos.txtp.max_pcr = vbr.peak_cell_rate; //data.qos.txtp.TokenRate = vbr.substainable_cell_rate; //data.qos.txtp.TokenBucketSize = vbr.max_burst_size; } void pvc_visitor::operator()(const abr_settings &abr) const { data.qos.txtp.traffic_class = ATM_ABR; data.qos.rxtp.traffic_class = ATM_ABR; } #endif } // namespace detail } // namespace qos } // namespace atm } // namespace asio } // namespace boost #endif // BOOST_ASIO_ATM_QOS_IPP
participants (1)
-
Casimiro, Daniel C CIV NUWC NWPT