
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