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