Finished turning the socket classes into templates.

This commit is contained in:
chris 2003-09-18 03:37:24 +00:00
parent 672cc09bb1
commit 09641826f0
25 changed files with 1213 additions and 1206 deletions

View File

@ -17,11 +17,8 @@ ___lib_libasio_a_SOURCES = \
asio/service_provider.cpp \
asio/service_provider_factory.cpp \
asio/service_unavailable.cpp \
asio/socket_acceptor.cpp \
asio/socket_address.cpp \
asio/socket_connector.cpp \
asio/socket_error.cpp \
asio/stream_socket.cpp \
asio/detail/default_service_provider_factory.cpp \
asio/detail/demuxer_thread_pool.cpp \
asio/detail/dgram_socket_service.cpp \
@ -43,6 +40,9 @@ ___lib_libasio_a_SOURCES = \
nobase_include_HEADERS = \
asio.hpp \
asio/basic_dgram_socket.hpp \
asio/basic_socket_acceptor.hpp \
asio/basic_socket_connector.hpp \
asio/basic_stream_socket.hpp \
asio/basic_timer_queue.hpp \
asio/buffered_recv_stream.hpp \
asio/buffered_send_stream.hpp \

View File

@ -16,6 +16,9 @@
#define ASIO_HPP
#include "asio/basic_dgram_socket.hpp"
#include "asio/basic_socket_acceptor.hpp"
#include "asio/basic_socket_connector.hpp"
#include "asio/basic_stream_socket.hpp"
#include "asio/basic_timer_queue.hpp"
#include "asio/buffered_recv_stream.hpp"
#include "asio/buffered_send_stream.hpp"
@ -38,6 +41,7 @@
#include "asio/socket_address.hpp"
#include "asio/socket_connector.hpp"
#include "asio/socket_error.hpp"
#include "asio/stream_socket.hpp"
#include "asio/timer_queue.hpp"
#endif // ASIO_HPP

View File

@ -27,7 +27,6 @@
namespace asio {
class socket_address;
class socket_error;
/// The basic_dgram_socket class template provides asynchronous and blocking
/// datagram-oriented socket functionality. Most applications will simply use
@ -37,20 +36,24 @@ class basic_dgram_socket
: private boost::noncopyable
{
public:
/// The native implementation type of the dgram socket.
typedef typename Service::impl_type impl_type;
/// The type of the service that will be used to provide socket operations.
typedef Service service_type;
/// Construct a dgram_socket without opening it. The socket needs to be
/// The native implementation type of the dgram socket.
typedef typename service_type::impl_type impl_type;
/// Construct a basic_dgram_socket without opening it. The socket needs to be
/// opened before data can be sent or received on it.
explicit basic_dgram_socket(demuxer& d)
: service_(dynamic_cast<Service&>(d.get_service(Service::id)))
: service_(dynamic_cast<service_type&>(d.get_service(service_type::id))),
impl_(service_type::invalid_impl)
{
service_.nullify(impl_);
}
/// Construct a dgram_socket opened on the given address.
/// Construct a basic_dgram_socket opened on the given address.
basic_dgram_socket(demuxer& d, const socket_address& address)
: service_(dynamic_cast<Service&>(d.get_service(Service::id)))
: service_(dynamic_cast<service_type&>(d.get_service(service_type::id))),
impl_(service_type::invalid_impl)
{
service_.create(impl_, address);
}
@ -79,13 +82,6 @@ public:
return impl_;
}
/// Attach an existing implementation to the dgram socket. The dgram_socket
/// object takes ownership of the implementation.
void attach_impl(impl_type impl)
{
service_.attach(impl_, impl);
}
/// Send a datagram to the specified address. Returns the number of bytes
/// sent. Throws a socket_error exception on failure.
size_t sendto(const void* data, size_t length,
@ -96,7 +92,7 @@ public:
/// The handler when a sendto operation is completed. The first argument is
/// the error code, the second is the number of bytes sent.
typedef typename Service::sendto_handler sendto_handler;
typedef typename service_type::sendto_handler sendto_handler;
/// Start an asynchronous send. The data being sent must be valid for the
/// lifetime of the asynchronous operation.
@ -117,7 +113,7 @@ public:
/// The handler when a recvfrom operation is completed. The first argument is
/// the error code, the second is the number of bytes received.
typedef typename Service::recvfrom_handler recvfrom_handler;
typedef typename service_type::recvfrom_handler recvfrom_handler;
/// Start an asynchronous receive. The buffer for the data being received and
/// the sender_address obejct must both be valid for the lifetime of the
@ -132,7 +128,7 @@ public:
private:
/// The backend service implementation.
Service& service_;
service_type& service_;
/// The underlying native implementation.
impl_type impl_;

View File

@ -0,0 +1,169 @@
//
// basic_socket_acceptor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003 Christopher M. Kohlhoff (chris@kohlhoff.com)
//
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appears in all copies and that both the copyright
// notice and this permission notice appear in supporting documentation. This
// software is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
#ifndef ASIO_BASIC_SOCKET_ACCEPTOR_HPP
#define ASIO_BASIC_SOCKET_ACCEPTOR_HPP
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/noncopyable.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/completion_context.hpp"
#include "asio/demuxer.hpp"
namespace asio {
class socket_address;
/// The basic_socket_acceptor class template is used for accepting new socket
/// connections. Most applications would simply use the socket_acceptor
/// typedef.
template <typename Service>
class basic_socket_acceptor
: private boost::noncopyable
{
public:
/// The type of the service that will be used to provide accept operations.
typedef Service service_type;
/// The native implementation type of the socket acceptor.
typedef typename service_type::impl_type impl_type;
/// Constructor an acceptor without opening it. The acceptor needs to be
/// opened before it can accept new connections.
explicit basic_socket_acceptor(demuxer& d)
: service_(dynamic_cast<service_type&>(d.get_service(service_type::id))),
impl_(service_type::invalid_impl)
{
}
/// Construct an acceptor opened on the given address.
basic_socket_acceptor(demuxer& d, const socket_address& addr)
: service_(dynamic_cast<service_type&>(d.get_service(service_type::id))),
impl_(service_type::invalid_impl)
{
service_.create(impl_, addr);
}
/// Construct an acceptor opened on the given address and with the listen
/// queue set to the given number of connections.
basic_socket_acceptor(demuxer& d, const socket_address& addr,
int listen_queue)
: service_(dynamic_cast<service_type&>(d.get_service(service_type::id))),
impl_(service_type::invalid_impl)
{
service_.create(impl_, addr, listen_queue);
}
/// Destructor.
~basic_socket_acceptor()
{
service_.destroy(impl_);
}
/// Open the acceptor using the given address.
void open(const socket_address& addr)
{
service_.create(impl_, addr);
}
/// Open the acceptor using the given address and length of the listen queue.
void open(const socket_address& addr, int listen_queue)
{
service_.create(impl_, addr, listen_queue);
}
/// Close the acceptor.
void close()
{
service_.destroy(impl_);
}
/// Get the underlying implementation in the native type.
impl_type impl() const
{
return impl_;
}
/// Accept a new connection. Throws a socket_error exception on failure.
template <typename Stream>
void accept(Stream& peer_socket)
{
service_.accept(impl_, peer_socket.lowest_layer());
}
/// Accept a new connection. Throws a socket_error exception on failure.
template <typename Stream>
void accept(Stream& peer_socket, socket_address& peer_address)
{
service_.accept(impl_, peer_socket.lowest_layer(), peer_address);
}
/// The type of a handler called when the asynchronous accept completes. The
/// only argument is the error code.
typedef typename service_type::accept_handler accept_handler;
/// Start an asynchronous accept. The peer_socket object must be valid until
/// the accept's completion handler is invoked.
template <typename Stream>
void async_accept(Stream& peer_socket, const accept_handler& handler)
{
service_.async_accept(impl_, peer_socket.lowest_layer(), handler,
completion_context::null());
}
/// Start an asynchronous accept. The peer_socket object must be valid until
/// the accept's completion handler is invoked.
template <typename Stream>
void async_accept(Stream& peer_socket, const accept_handler& handler,
completion_context& context)
{
service_.async_accept(impl_, peer_socket.lowest_layer(), handler, context);
}
/// Start an asynchronous accept. The peer_socket and peer_address objects
/// must be valid until the accept's completion handler is invoked.
template <typename Stream>
void async_accept(Stream& peer_socket, socket_address& peer_address,
const accept_handler& handler)
{
service_.async_accept(impl_, peer_socket.lowest_layer(), peer_address,
handler, completion_context::null());
}
/// Start an asynchronous accept. The peer_socket and peer_address objects
/// must be valid until the accept's completion handler is invoked.
template <typename Stream>
void async_accept(Stream& peer_socket, socket_address& peer_address,
const accept_handler& handler, completion_context& context)
{
service_.async_accept(impl_, peer_socket.lowest_layer(), peer_address,
handler, context);
}
private:
/// The backend service implementation.
service_type& service_;
/// The underlying native implementation.
impl_type impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SOCKET_ACCEPTOR_HPP

View File

@ -0,0 +1,122 @@
//
// basic_socket_connector.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003 Christopher M. Kohlhoff (chris@kohlhoff.com)
//
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appears in all copies and that both the copyright
// notice and this permission notice appear in supporting documentation. This
// software is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
#ifndef ASIO_BASIC_SOCKET_CONNECTOR_HPP
#define ASIO_BASIC_SOCKET_CONNECTOR_HPP
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/noncopyable.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/completion_context.hpp"
#include "asio/demuxer.hpp"
namespace asio {
class socket_address;
/// The basic_socket_connector class template is used to connect a socket to a
/// remote endpoint. Most applications will simply use the socket_connector
/// typedef.
template <typename Service>
class basic_socket_connector
: private boost::noncopyable
{
public:
/// The type of the service that will be used to provide connect operations.
typedef Service service_type;
/// The native implementation type of the socket connector.
typedef typename service_type::impl_type impl_type;
/// Constructor a connector. The connector is automatically opened.
explicit basic_socket_connector(demuxer& d)
: service_(dynamic_cast<service_type&>(d.get_service(service_type::id))),
impl_(service_type::invalid_impl)
{
service_.create(impl_);
}
/// Destructor.
~basic_socket_connector()
{
service_.destroy(impl_);
}
/// Open the connector.
void open()
{
service_.create(impl_);
}
/// Close the connector.
void close()
{
service_.destroy(impl_);
}
/// Get the underlying implementation in the native type.
impl_type impl() const
{
return impl_;
}
/// Connect the given socket to the peer at the specified address. Throws a
/// socket_error exception on failure.
template <typename Stream>
void connect(Stream& peer_socket, const socket_address& peer_address)
{
service_.connect(impl_, peer_socket.lowest_layer(), peer_address);
}
/// The type of a handler called when the asynchronous connect completes. The
/// only argument is the error code.
typedef typename service_type::connect_handler connect_handler;
/// Start an asynchronous connect. The peer_socket object must be valid until
/// the connect's completion handler is invoked.
template <typename Stream>
void async_connect(Stream& peer_socket,
const socket_address& peer_address, const connect_handler& handler)
{
service_.async_connect(impl_, peer_socket.lowest_layer(), peer_address,
handler, completion_context::null());
}
/// Start an asynchronous connect. The peer_socket object must be valid until
/// the connect's completion handler is invoked.
template <typename Stream>
void async_connect(Stream& peer_socket,
const socket_address& peer_address, const connect_handler& handler,
completion_context& context)
{
service_.async_connect(impl_, peer_socket.lowest_layer(), peer_address,
handler, context);
}
private:
/// The backend service implementation.
service_type& service_;
/// The underlying native implementation.
impl_type impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SOCKET_CONNECTOR_HPP

View File

@ -0,0 +1,185 @@
//
// basic_stream_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003 Christopher M. Kohlhoff (chris@kohlhoff.com)
//
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appears in all copies and that both the copyright
// notice and this permission notice appear in supporting documentation. This
// software is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
#ifndef ASIO_BASIC_STREAM_SOCKET_HPP
#define ASIO_BASIC_STREAM_SOCKET_HPP
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/noncopyable.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/completion_context.hpp"
#include "asio/demuxer.hpp"
namespace asio {
/// The basic_stream_socket class template provides asynchronous and blocking
/// stream-oriented socket functionality. Most applications will simply use the
/// stream_socket typedef.
template <typename Service>
class basic_stream_socket
: private boost::noncopyable
{
public:
/// The type of the service that will be used to provide socket operations.
typedef Service service_type;
/// The native implementation type of the stream socket.
typedef typename service_type::impl_type impl_type;
/// A basic_stream_socket is always the lowest layer.
typedef basic_stream_socket<service_type> lowest_layer_type;
/// Construct a basic_stream_socket without opening it. The socket needs to
/// be connected or accepted before data can be sent or received on it.
explicit basic_stream_socket(demuxer& d)
: service_(dynamic_cast<service_type&>(d.get_service(service_type::id))),
impl_(service_type::invalid_impl)
{
}
/// Destructor.
~basic_stream_socket()
{
service_.destroy(impl_);
}
/// Close the socket.
void close()
{
service_.destroy(impl_);
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get the underlying implementation in the native type.
impl_type impl() const
{
return impl_;
}
/// Set the underlying implementation in the native type. The object must not
/// be open priot to this call being made.
void set_impl(impl_type new_impl)
{
service_.create(impl_, new_impl);
}
/// Send the given data to the peer. Returns the number of bytes sent or
/// 0 if the connection was closed cleanly. Throws a socket_error exception
/// on failure.
size_t send(const void* data, size_t length)
{
return service_.send(impl_, data, length);
}
/// The handler when a send operation is completed. The first argument is the
/// error code, the second is the number of bytes sent.
typedef typename service_type::send_handler send_handler;
/// Start an asynchronous send. The data being sent must be valid for the
/// lifetime of the asynchronous operation.
void async_send(const void* data, size_t length,
const send_handler& handler,
completion_context& context = completion_context::null())
{
service_.async_send(impl_, length, handler, context);
}
/// Send all of the given data to the peer before returning. Returns the
/// number of bytes sent on the last send or 0 if the connection was closed
/// cleanly. Throws a socket_error exception on failure.
size_t send_n(const void* data, size_t length, size_t* total_bytes_sent = 0)
{
return service_.send_n(impl_, data, length, total_bytes_sent);
}
/// The handler when a send_n operation is completed. The first argument is
/// the error code, the second is the total number of bytes sent, and the
/// third is the number of bytes sent in the last send operation.
typedef typename service_type::send_n_handler send_n_handler;
/// Start an asynchronous send that will not return until all of the data has
/// been sent or an error occurs. The data being sent must be valid for the
/// lifetime of the asynchronous operation.
void async_send_n(const void* data, size_t length,
const send_n_handler& handler,
completion_context& context = completion_context::null())
{
service_.async_send_n(impl_, data, length, handler, context);
}
/// Receive some data from the peer. Returns the number of bytes received or
/// 0 if the connection was closed cleanly. Throws a socket_error exception
/// on failure.
size_t recv(void* data, size_t max_length)
{
return service_.recv(impl_, data, max_length);
}
/// The handler when a recv operation is completed. The first argument is the
/// error code, the second is the number of bytes received.
typedef typename service_type::recv_handler recv_handler;
/// Start an asynchronous receive. The buffer for the data being received must
/// be valid for the lifetime of the asynchronous operation.
void async_recv(void* data, size_t max_length,
const recv_handler& handler,
completion_context& context = completion_context::null())
{
service_.async_recv(impl_, data, max_length, handler, context);
}
/// Receive the specified amount of data from the peer. Returns the number of
/// bytes received on the last recv call or 0 if the connection
/// was closed cleanly. Throws a socket_error exception on failure.
size_t recv_n(void* data, size_t length, size_t* total_bytes_recvd = 0)
{
return service_.recv_n(impl_, data, length, total_bytes_recvd);
}
/// The handler when a recv_n operation is completed. The first argument is
/// the error code, the second is the number of bytes received, the third is
/// the number of bytes received in the last recv operation.
typedef typename service_type::recv_n_handler recv_n_handler;
/// Start an asynchronous receive that will not return until the specified
/// number of bytes has been received or an error occurs. The buffer for the
/// data being received must be valid for the lifetime of the asynchronous
/// operation.
void async_recv_n(void* data, size_t length, const recv_n_handler& handler,
completion_context& context = completion_context::null())
{
service_.async_recv_n(impl_, data, length, handler, context);
}
private:
/// The backend service implementation.
service_type& service_;
/// The underlying native implementation.
impl_type impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_STREAM_SOCKET_HPP

View File

@ -35,14 +35,17 @@ class basic_timer_queue
: private boost::noncopyable
{
public:
/// The type of the service that will be used to provide timer operations.
typedef Service service_type;
/// Constructor.
explicit basic_timer_queue(demuxer& d)
: service_(dynamic_cast<Service&>(d.get_service(Service::id)))
: service_(dynamic_cast<service_type&>(d.get_service(service_type::id)))
{
}
/// The handler for when a timer expires.
typedef typename Service::timer_handler timer_handler;
typedef typename service_type::timer_handler timer_handler;
/// Schedule a timer to fire once at the given start_time. The id of the new
/// timer is returned so that it may be cancelled.
@ -72,7 +75,7 @@ public:
private:
/// The backend service implementation.
Service& service_;
service_type& service_;
};
} // namespace asio

View File

@ -27,14 +27,7 @@ namespace asio {
namespace detail {
const service_type_id dgram_socket_service::id;
void
dgram_socket_service::
nullify(
impl_type& impl)
{
impl = invalid_socket;
}
const dgram_socket_service::impl_type dgram_socket_service::invalid_impl;
void
dgram_socket_service::
@ -58,14 +51,6 @@ create(
impl = sock.release();
}
void
attach(
impl_type& impl,
impl_type new_impl)
{
impl = new_impl;
}
void
dgram_socket_service::
destroy(

View File

@ -21,11 +21,11 @@
#include <boost/function.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/completion_context.hpp"
#include "asio/service.hpp"
#include "asio/service_type_id.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio { class completion_context; }
namespace asio { class socket_address; }
namespace asio { class socket_error; }
@ -39,29 +39,26 @@ public:
// The service type id.
static const service_type_id id;
/// The native type of the dgram socket. This type is dependent on the
/// underlying implementation of the socket layer.
// The native type of the dgram socket. This type is dependent on the
// underlying implementation of the socket layer.
typedef socket_type impl_type;
// Initialise a dgram socket to a null implementation.
void nullify(impl_type& impl);
// The value to use for uninitialised implementations.
static const impl_type invalid_impl = invalid_socket;
// Create a new dgram socket implementation.
void create(impl_type& impl, const socket_address& address);
// Attach an existing dgram socket implementation to the service.
void attach(impl_type& impl, impl_type new_impl);
// Destroy a dgram socket implementation.
void destroy(impl_type& impl);
/// Send a datagram to the specified address. Returns the number of bytes
/// sent. Throws a socket_error exception on failure.
// Send a datagram to the specified address. Returns the number of bytes
// sent. Throws a socket_error exception on failure.
size_t sendto(impl_type& impl, const void* data, size_t length,
const socket_address& destination);
/// The handler when a sendto operation is completed. The first argument is
/// the error code, the second is the number of bytes sent.
// The handler when a sendto operation is completed. The first argument is
// the error code, the second is the number of bytes sent.
typedef boost::function2<void, const socket_error&, size_t> sendto_handler;
// Start an asynchronous send. The data being sent must be valid for the
@ -70,13 +67,13 @@ public:
const socket_address& destination, const sendto_handler& handler,
completion_context& context);
/// Receive a datagram with the address of the sender. Returns the number of
/// bytes received. Throws a socket_error exception on failure.
// Receive a datagram with the address of the sender. Returns the number of
// bytes received. Throws a socket_error exception on failure.
size_t recvfrom(impl_type& impl, void* data, size_t max_length,
socket_address& sender_address);
/// The handler when a recvfrom operation is completed. The first argument is
/// the error code, the second is the number of bytes received.
// The handler when a recvfrom operation is completed. The first argument is
// the error code, the second is the number of bytes received.
typedef boost::function2<void, const socket_error&, size_t> recvfrom_handler;
// Start an asynchronous receive. The buffer for the data being received and

View File

@ -60,11 +60,11 @@ select_provider::
do_dgram_socket_destroy(
dgram_socket_service::impl_type& impl)
{
if (impl != invalid_socket)
if (impl != dgram_socket_service::invalid_impl)
{
selector_.close_descriptor(impl);
socket_ops::close(impl);
impl = invalid_socket;
impl = dgram_socket_service::invalid_impl;
}
}
@ -199,19 +199,15 @@ do_dgram_socket_async_recvfrom(
void
select_provider::
register_socket_acceptor(
socket_acceptor&)
do_socket_acceptor_destroy(
socket_acceptor_service::impl_type& impl)
{
// Registration is not required with the select_provider since each operation
// is handled individually.
}
void
select_provider::
deregister_socket_acceptor(
socket_acceptor& socket)
{
selector_.close_descriptor(socket.native_handle());
if (impl != socket_acceptor_service::invalid_impl)
{
selector_.close_descriptor(impl);
socket_ops::close(impl);
impl = socket_acceptor_service::invalid_impl;
}
}
namespace
@ -219,9 +215,8 @@ namespace
struct accept_op : public select_op
{
demuxer* demuxer_;
socket_acceptor* acceptor_;
stream_socket* peer_socket_;
socket_acceptor::accept_handler handler_;
socket_acceptor_service::peer_type* peer_socket_;
socket_acceptor_service::accept_handler handler_;
completion_context* context_;
accept_op(int d) : select_op(d) {}
@ -231,8 +226,7 @@ namespace
socket_type new_socket = socket_ops::accept(descriptor(), 0, 0);
socket_error error(new_socket == invalid_socket
? socket_ops::get_error() : socket_error::success);
select_provider::do_associate_accepted_stream_socket(*acceptor_,
*peer_socket_, new_socket);
peer_socket_->set_impl(new_socket);
demuxer_->operation_completed(boost::bind(&accept_op::do_upcall,
handler_, error), *context_);
delete this;
@ -246,7 +240,8 @@ namespace
delete this;
}
static void do_upcall(const socket_acceptor::accept_handler& handler,
static void do_upcall(
const socket_acceptor_service::accept_handler& handler,
const socket_error& error)
{
handler(error);
@ -256,13 +251,13 @@ namespace
void
select_provider::
async_socket_accept(
socket_acceptor& acceptor,
stream_socket& peer_socket,
do_socket_acceptor_async_accept(
socket_acceptor_service::impl_type& impl,
socket_acceptor_service::peer_type& peer_socket,
const accept_handler& handler,
completion_context& context)
{
if (peer_socket.native_handle() != invalid_socket)
if (peer_socket.impl() != invalid_socket)
{
socket_error error(socket_error::already_connected);
demuxer_.operation_immediate(
@ -270,9 +265,8 @@ async_socket_accept(
return;
}
accept_op* op = new accept_op(acceptor.native_handle());
accept_op* op = new accept_op(impl);
op->demuxer_ = &demuxer_;
op->acceptor_ = &acceptor;
op->peer_socket_ = &peer_socket;
op->handler_ = handler;
op->context_ = &context;
@ -287,10 +281,9 @@ namespace
struct accept_with_addr_op : public select_op
{
demuxer* demuxer_;
socket_acceptor* acceptor_;
stream_socket* peer_socket_;
socket_acceptor_service::peer_type* peer_socket_;
socket_address* peer_address_;
socket_acceptor::accept_handler handler_;
socket_acceptor_service::accept_handler handler_;
completion_context* context_;
accept_with_addr_op(int d) : select_op(d) {}
@ -303,8 +296,7 @@ namespace
socket_error error(new_socket == invalid_socket
? socket_ops::get_error() : socket_error::success);
peer_address_->native_size(addr_len);
select_provider::do_associate_accepted_stream_socket(*acceptor_,
*peer_socket_, new_socket);
peer_socket_->set_impl(new_socket);
demuxer_->operation_completed(boost::bind(&accept_op::do_upcall,
handler_, error), *context_);
delete this;
@ -318,7 +310,8 @@ namespace
delete this;
}
static void do_upcall(const socket_acceptor::accept_handler& handler,
static void do_upcall(
const socket_acceptor_service::accept_handler& handler,
const socket_error& error)
{
handler(error);
@ -328,14 +321,14 @@ namespace
void
select_provider::
async_socket_accept(
socket_acceptor& acceptor,
stream_socket& peer_socket,
do_socket_acceptor_async_accept(
socket_acceptor_service::impl_type& impl,
socket_acceptor_service::peer_type& peer_socket,
socket_address& peer_address,
const accept_handler& handler,
completion_context& context)
{
if (peer_socket.native_handle() != invalid_socket)
if (peer_socket.impl() != invalid_socket)
{
socket_error error(socket_error::already_connected);
demuxer_.operation_immediate(
@ -343,9 +336,8 @@ async_socket_accept(
return;
}
accept_with_addr_op* op = new accept_with_addr_op(acceptor.native_handle());
accept_with_addr_op* op = new accept_with_addr_op(impl);
op->demuxer_ = &demuxer_;
op->acceptor_ = &acceptor;
op->peer_socket_ = &peer_socket;
op->peer_address_ = &peer_address;
op->handler_ = handler;
@ -358,33 +350,20 @@ async_socket_accept(
void
select_provider::
do_associate_accepted_stream_socket(
socket_acceptor& acceptor,
stream_socket& peer_socket,
stream_socket::native_type handle)
do_socket_connector_destroy(
socket_connector_service::impl_type& impl)
{
associate_accepted_stream_socket(acceptor, peer_socket, handle);
}
if (impl != socket_connector_service::invalid_impl)
{
socket_connector_impl::socket_set sockets;
impl->get_sockets(sockets);
socket_connector_impl::socket_set::iterator i = sockets.begin();
while (i != sockets.end())
selector_.close_descriptor(*i++);
void
select_provider::
register_socket_connector(
socket_connector&)
{
// Registration is not required with the select_provider since each operation
// is handled individually.
}
void
select_provider::
deregister_socket_connector(
socket_connector& connector)
{
socket_connector_impl::socket_set sockets;
connector.native_handle()->get_sockets(sockets);
socket_connector_impl::socket_set::iterator i = sockets.begin();
while (i != sockets.end())
selector_.close_descriptor(*i++);
delete impl;
impl = socket_connector_service::invalid_impl;
}
}
namespace
@ -392,10 +371,10 @@ namespace
struct connect_op : public select_op
{
demuxer* demuxer_;
socket_connector* connector_;
stream_socket* peer_socket_;
socket_connector_service::impl_type connector_impl_;
socket_connector_service::peer_type* peer_socket_;
generic_address peer_address_;
socket_connector::connect_handler handler_;
socket_connector_service::connect_handler handler_;
completion_context* context_;
connect_op(int d) : select_op(d) {}
@ -403,7 +382,7 @@ namespace
virtual void do_operation()
{
socket_holder new_socket(descriptor());
connector_->native_handle()->remove_socket(new_socket.get());
connector_impl_->remove_socket(new_socket.get());
// Get the error code from the connect operation.
int connect_error = 0;
@ -412,8 +391,6 @@ namespace
&connect_error, &connect_error_len) == socket_error_retval)
{
socket_error error(socket_ops::get_error());
select_provider::do_associate_connected_stream_socket(*connector_,
*peer_socket_, invalid_socket);
demuxer_->operation_completed(boost::bind(&connect_op::do_upcall,
handler_, error), *context_);
delete this;
@ -424,8 +401,6 @@ namespace
if (connect_error)
{
socket_error error(connect_error);
select_provider::do_associate_connected_stream_socket(*connector_,
*peer_socket_, invalid_socket);
demuxer_->operation_completed(boost::bind(&connect_op::do_upcall,
handler_, error), *context_);
delete this;
@ -437,8 +412,6 @@ namespace
if (socket_ops::ioctl(new_socket.get(), FIONBIO, &non_blocking))
{
socket_error error(socket_ops::get_error());
select_provider::do_associate_connected_stream_socket(*connector_,
*peer_socket_, invalid_socket);
demuxer_->operation_completed(boost::bind(&connect_op::do_upcall,
handler_, error), *context_);
delete this;
@ -446,8 +419,7 @@ namespace
}
// Post the result of the successful connection operation.
select_provider::do_associate_connected_stream_socket(*connector_,
*peer_socket_, new_socket.release());
peer_socket_->set_impl(new_socket.release());
socket_error error(socket_error::success);
demuxer_->operation_completed(boost::bind(&connect_op::do_upcall,
handler_, error), *context_);
@ -456,14 +428,15 @@ namespace
virtual void do_cancel()
{
connector_->native_handle()->remove_socket(descriptor());
connector_impl_->remove_socket(descriptor());
socket_error error(socket_error::operation_aborted);
demuxer_->operation_completed(boost::bind(&connect_op::do_upcall,
handler_, error), *context_);
delete this;
}
static void do_upcall(const socket_connector::connect_handler& handler,
static void do_upcall(
const socket_connector_service::connect_handler& handler,
const socket_error& error)
{
handler(error);
@ -473,14 +446,13 @@ namespace
void
select_provider::
async_socket_connect(
socket_connector& connector,
stream_socket& peer_socket,
const socket_address& peer_address,
const connect_handler& handler,
do_socket_connector_async_connect(
socket_connector_service::impl_type& impl,
socket_connector_service::peer_type& peer_socket,
const socket_address& peer_address, const connect_handler& handler,
completion_context& context)
{
if (peer_socket.native_handle() != invalid_socket)
if (peer_socket.impl() != invalid_socket)
{
socket_error error(socket_error::already_connected);
demuxer_.operation_immediate(
@ -495,7 +467,6 @@ async_socket_connect(
if (new_socket.get() == invalid_socket)
{
socket_error error(socket_ops::get_error());
associate_connected_stream_socket(connector, peer_socket, invalid_socket);
demuxer_.operation_immediate(boost::bind(&connect_op::do_upcall, handler,
error), context);
return;
@ -507,7 +478,6 @@ async_socket_connect(
if (socket_ops::ioctl(new_socket.get(), FIONBIO, &non_blocking))
{
socket_error error(socket_ops::get_error());
associate_connected_stream_socket(connector, peer_socket, invalid_socket);
demuxer_.operation_immediate(boost::bind(&connect_op::do_upcall, handler,
error), context);
return;
@ -519,8 +489,7 @@ async_socket_connect(
{
// The connect operation has finished successfully so we need to post the
// completion immediately.
associate_connected_stream_socket(connector, peer_socket,
new_socket.release());
peer_socket.set_impl(new_socket.release());
socket_error error(socket_error::success);
demuxer_.operation_immediate(boost::bind(&connect_op::do_upcall, handler,
error), context);
@ -533,13 +502,13 @@ async_socket_connect(
connect_op* op = new connect_op(new_socket.get());
op->demuxer_ = &demuxer_;
op->connector_ = &connector;
op->connector_impl_ = impl;
op->peer_socket_ = &peer_socket;
op->peer_address_ = peer_address;
op->handler_ = handler;
op->context_ = &context;
connector.native_handle()->add_socket(new_socket.get());
impl->add_socket(new_socket.get());
new_socket.release();
demuxer_.operation_started();
@ -550,7 +519,6 @@ async_socket_connect(
{
// The connect operation has failed, so post completion immediately.
socket_error error(socket_ops::get_error());
associate_connected_stream_socket(connector, peer_socket, invalid_socket);
demuxer_.operation_immediate(boost::bind(&connect_op::do_upcall, handler,
error), context);
}
@ -558,29 +526,24 @@ async_socket_connect(
void
select_provider::
do_associate_connected_stream_socket(
socket_connector& connector,
stream_socket& peer_socket,
stream_socket::native_type handle)
do_stream_socket_create(
stream_socket_service::impl_type& impl,
stream_socket_service::impl_type new_impl)
{
associate_connected_stream_socket(connector, peer_socket, handle);
impl = new_impl;
}
void
select_provider::
register_stream_socket(
stream_socket&)
do_stream_socket_destroy(
stream_socket_service::impl_type& impl)
{
// Registration is not required with the select_provider since each operation
// is handled individually.
}
void
select_provider::
deregister_stream_socket(
stream_socket& socket)
{
selector_.close_descriptor(socket.native_handle());
if (impl != stream_socket_service::invalid_impl)
{
selector_.close_descriptor(impl);
socket_ops::close(impl);
impl = stream_socket_service::invalid_impl;
}
}
namespace
@ -590,7 +553,7 @@ namespace
demuxer* demuxer_;
const void* data_;
size_t length_;
stream_socket::send_handler handler_;
stream_socket_service::send_handler handler_;
completion_context* context_;
send_op(int d) : select_op(d) {}
@ -613,7 +576,7 @@ namespace
delete this;
}
static void do_upcall(const stream_socket::send_handler& handler,
static void do_upcall(const stream_socket_service::send_handler& handler,
const socket_error& error, size_t bytes_transferred)
{
handler(error, bytes_transferred);
@ -623,14 +586,14 @@ namespace
void
select_provider::
async_stream_socket_send(
stream_socket& socket,
do_stream_socket_async_send(
stream_socket_service::impl_type& impl,
const void* data,
size_t length,
const send_handler& handler,
completion_context& context)
{
send_op* op = new send_op(socket.native_handle());
send_op* op = new send_op(impl);
op->demuxer_ = &demuxer_;
op->data_ = data;
op->length_ = length;
@ -651,7 +614,7 @@ namespace
const void* data_;
size_t length_;
size_t already_sent_;
stream_socket::send_n_handler handler_;
stream_socket_service::send_n_handler handler_;
completion_context* context_;
send_n_op(int d) : select_op(d) {}
@ -686,7 +649,7 @@ namespace
delete this;
}
static void do_upcall(const stream_socket::send_n_handler& handler,
static void do_upcall(const stream_socket_service::send_n_handler& handler,
const socket_error& error, size_t total_bytes_transferred,
size_t last_bytes_transferred)
{
@ -697,14 +660,14 @@ namespace
void
select_provider::
async_stream_socket_send_n(
stream_socket& socket,
do_stream_socket_async_send_n(
stream_socket_service::impl_type& impl,
const void* data,
size_t length,
const send_n_handler& handler,
completion_context& context)
{
send_n_op* op = new send_n_op(socket.native_handle());
send_n_op* op = new send_n_op(impl);
op->demuxer_ = &demuxer_;
op->selector_ = &selector_;
op->data_ = data;
@ -725,7 +688,7 @@ namespace
demuxer* demuxer_;
void* data_;
size_t max_length_;
stream_socket::recv_handler handler_;
stream_socket_service::recv_handler handler_;
completion_context* context_;
recv_op(int d) : select_op(d) {}
@ -748,7 +711,7 @@ namespace
delete this;
}
static void do_upcall(const stream_socket::recv_handler& handler,
static void do_upcall(const stream_socket_service::recv_handler& handler,
const socket_error& error, size_t bytes_transferred)
{
handler(error, bytes_transferred);
@ -758,14 +721,14 @@ namespace
void
select_provider::
async_stream_socket_recv(
stream_socket& socket,
do_stream_socket_async_recv(
stream_socket_service::impl_type& impl,
void* data,
size_t max_length,
const recv_handler& handler,
completion_context& context)
{
recv_op* op = new recv_op(socket.native_handle());
recv_op* op = new recv_op(impl);
op->demuxer_ = &demuxer_;
op->data_ = data;
op->max_length_ = max_length;
@ -786,7 +749,7 @@ namespace
void* data_;
size_t length_;
size_t already_recvd_;
stream_socket::recv_n_handler handler_;
stream_socket_service::recv_n_handler handler_;
completion_context* context_;
recv_n_op(int d) : select_op(d) {}
@ -821,7 +784,7 @@ namespace
delete this;
}
static void do_upcall(const stream_socket::recv_n_handler& handler,
static void do_upcall(const stream_socket_service::recv_n_handler& handler,
const socket_error& error, size_t total_bytes_transferred,
size_t last_bytes_transferred)
{
@ -832,14 +795,14 @@ namespace
void
select_provider::
async_stream_socket_recv_n(
stream_socket& socket,
do_stream_socket_async_recv_n(
stream_socket_service::impl_type& impl,
void* data,
size_t length,
const recv_n_handler& handler,
completion_context& context)
{
recv_n_op* op = new recv_n_op(socket.native_handle());
recv_n_op* op = new recv_n_op(impl);
op->demuxer_ = &demuxer_;
op->selector_ = &selector_;
op->data_ = data;

View File

@ -59,82 +59,66 @@ public:
socket_address& sender_address, const recvfrom_handler& handler,
completion_context& context);
// Register a new socket_acceptor with the service. This should be called
// only after the socket acceptor has been opened.
virtual void register_socket_acceptor(socket_acceptor& acceptor);
// Remove a socket acceptor registration from the service. This should be
// called immediately before the socket acceptor is closed.
virtual void deregister_socket_acceptor(socket_acceptor& acceptor);
// Destroy a socket connector implementation.
virtual void do_socket_acceptor_destroy(
socket_acceptor_service::impl_type& impl);
// Start an asynchronous accept on the given socket. The peer_socket object
// must be valid until the accept's completion handler is invoked.
virtual void async_socket_accept(socket_acceptor& acceptor,
stream_socket& peer_socket, const accept_handler& handler,
completion_context& context);
virtual void do_socket_acceptor_async_accept(
socket_acceptor_service::impl_type& impl,
socket_acceptor_service::peer_type& peer_socket,
const accept_handler& handler, completion_context& context);
// Start an asynchronous accept on the given socket. The peer_socket and
// peer_address objects must be valid until the accept's completion handler
// is invoked.
virtual void async_socket_accept(socket_acceptor& acceptor,
stream_socket& peer_socket, socket_address& peer_address,
const accept_handler& handler, completion_context& context);
// Register a new socket_connector with the service. This should be called
// only after the socket connector has been opened.
virtual void register_socket_connector(socket_connector& connector);
// Remove a socket connector registration from the service. This should be
// called immediately before the socket connector is closed.
virtual void deregister_socket_connector(socket_connector& connector);
// Start an asynchronous connect on the given socket. The peer_socket object
// be valid until the connect's completion handler is invoked.
virtual void async_socket_connect(socket_connector& connector,
stream_socket& peer_socket, const socket_address& peer_address,
const connect_handler& handler, completion_context& context);
// Register a new stream socket with the service. This should be called only
// after the socket has been opened, i.e. after an accept or just before a
// connect.
virtual void register_stream_socket(stream_socket& socket);
// Remove a stream socket registration from the service. This should be
// called immediately before the socket is closed.
virtual void deregister_stream_socket(stream_socket& socket);
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
virtual void async_stream_socket_send(stream_socket& socket,
const void* data, size_t length, const send_handler& handler,
virtual void do_socket_acceptor_async_accept(
socket_acceptor_service::impl_type& impl,
socket_acceptor_service::peer_type& peer_socket,
socket_address& peer_address, const accept_handler& handler,
completion_context& context);
// Destroy a socket connector implementation.
virtual void do_socket_connector_destroy(
socket_connector_service::impl_type& impl);
// Start an asynchronous connect.
virtual void do_socket_connector_async_connect(
socket_connector_service::impl_type& impl,
socket_connector_service::peer_type& peer_socket,
const socket_address& peer_address, const connect_handler& handler,
completion_context& context);
// Create a new socket connector implementation.
virtual void do_stream_socket_create(stream_socket_service::impl_type& impl,
stream_socket_service::impl_type new_impl);
// Destroy a socket connector implementation.
virtual void do_stream_socket_destroy(
stream_socket_service::impl_type& impl);
// Start an asynchronous send.
virtual void do_stream_socket_async_send(
stream_socket_service::impl_type& impl, const void* data, size_t length,
const send_handler& handler, completion_context& context);
// Start an asynchronous send that will not return until all of the data has
// been sent or an error occurs. The data being sent must be valid for the
// lifetime of the asynchronous operation.
virtual void async_stream_socket_send_n(stream_socket& socket,
const void* data, size_t length, const send_n_handler& handler,
completion_context& context);
// been sent or an error occurs.
virtual void do_stream_socket_async_send_n(
stream_socket_service::impl_type& impl, const void* data, size_t length,
const send_n_handler& handler, completion_context& context);
// Start an asynchronous receive. The buffer for the data being received must
// be valid for the lifetime of the asynchronous operation.
virtual void async_stream_socket_recv(stream_socket& socket, void* data,
size_t max_length, const recv_handler& handler,
completion_context& context);
// Start an asynchronous receive.
virtual void do_stream_socket_async_recv(
stream_socket_service::impl_type& impl, void* data, size_t max_length,
const recv_handler& handler, completion_context& context);
// Start an asynchronous receive that will not return until the specified
// number of bytes has been received or an error occurs. The buffer for the
// data being received must be valid for the lifetime of the asynchronous
// operation.
virtual void async_stream_socket_recv_n(stream_socket& socket, void* data,
size_t length, const recv_n_handler& handler,
completion_context& context);
// Provide access to these functions for the operation implementations.
static void do_associate_accepted_stream_socket(socket_acceptor& acceptor,
stream_socket& peer_socket, stream_socket::native_type handle);
static void do_associate_connected_stream_socket(socket_connector& connector,
stream_socket& peer_socket, stream_socket::native_type handle);
// number of bytes has been received or an error occurs.
virtual void do_stream_socket_async_recv_n(
stream_socket_service::impl_type& impl, void* data, size_t length,
const recv_n_handler& handler, completion_context& context);
private:
// The demuxer used for delivering completion notifications.

View File

@ -14,19 +14,125 @@
#include "asio/detail/socket_acceptor_service.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/socket_address.hpp"
#include "asio/socket_error.hpp"
#include "asio/detail/socket_holder.hpp"
#include "asio/detail/socket_ops.hpp"
namespace asio {
namespace detail {
const service_type_id socket_acceptor_service::id;
const socket_acceptor_service::impl_type socket_acceptor_service::invalid_impl;
void
socket_acceptor_service::
associate_accepted_stream_socket(
socket_acceptor& acceptor,
stream_socket& peer_socket,
stream_socket::native_type handle)
create(
impl_type& impl,
const socket_address& address)
{
acceptor.associate(peer_socket, handle);
create(impl, address, SOMAXCONN);
}
void
socket_acceptor_service::
create(
impl_type& impl,
const socket_address& address,
int listen_queue)
{
socket_holder sock(socket_ops::socket(address.family(), SOCK_STREAM,
IPPROTO_TCP));
if (sock.get() == invalid_socket)
boost::throw_exception(socket_error(socket_ops::get_error()));
int reuse = 1;
socket_ops::setsockopt(sock.get(), SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
if (socket_ops::bind(sock.get(), address.native_address(),
address.native_size()) == socket_error_retval)
boost::throw_exception(socket_error(socket_ops::get_error()));
if (socket_ops::listen(sock.get(), listen_queue) == socket_error_retval)
boost::throw_exception(socket_error(socket_ops::get_error()));
impl = sock.release();
}
void
socket_acceptor_service::
destroy(
impl_type& impl)
{
do_socket_acceptor_destroy(impl);
}
void
socket_acceptor_service::
accept(
impl_type& impl,
peer_type& peer_socket)
{
// We cannot accept a socket that is already open.
if (peer_socket.impl() != invalid_socket)
boost::throw_exception(socket_error(socket_error::already_connected));
socket_type new_socket = socket_ops::accept(impl, 0, 0);
if (int error = socket_ops::get_error())
boost::throw_exception(socket_error(error));
peer_socket.set_impl(new_socket);
}
void
socket_acceptor_service::
accept(
impl_type& impl,
peer_type& peer_socket,
socket_address& peer_address)
{
// We cannot accept a socket that is already open.
if (peer_socket.impl() != invalid_socket)
boost::throw_exception(socket_error(socket_error::already_connected));
socket_addr_len_type addr_len = peer_address.native_size();
socket_type new_socket = socket_ops::accept(impl,
peer_address.native_address(), &addr_len);
if (int error = socket_ops::get_error())
boost::throw_exception(socket_error(error));
peer_address.native_size(addr_len);
peer_socket.set_impl(new_socket);
}
void
socket_acceptor_service::
async_accept(
impl_type& impl,
peer_type& peer_socket,
const accept_handler& handler,
completion_context& context)
{
do_socket_acceptor_async_accept(impl, peer_socket, handler, context);
}
void
socket_acceptor_service::
async_accept(
impl_type& impl,
peer_type& peer_socket,
socket_address& peer_address,
const accept_handler& handler,
completion_context& context)
{
do_socket_acceptor_async_accept(impl, peer_socket, peer_address, handler,
context);
}
} // namespace detail

View File

@ -17,10 +17,19 @@
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/function.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_stream_socket.hpp"
#include "asio/service.hpp"
#include "asio/service_type_id.hpp"
#include "asio/socket_acceptor.hpp"
#include "asio/stream_socket.hpp"
#include "asio/detail/stream_socket_service.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio { class completion_context; }
namespace asio { class socket_address; }
namespace asio { class socket_error; }
namespace asio {
namespace detail {
@ -29,37 +38,67 @@ class socket_acceptor_service
: public virtual service
{
public:
typedef socket_acceptor::accept_handler accept_handler;
// The service type id.
static const service_type_id id;
// Register a new socket_acceptor with the service. This should be called
// only after the socket acceptor has been opened.
virtual void register_socket_acceptor(socket_acceptor& acceptor) = 0;
// The native type of the socket acceptor. This type is dependent on the
// underlying implementation of the socket layer.
typedef socket_type impl_type;
// Remove a socket acceptor registration from the service. This should be
// called immediately before the socket acceptor is closed.
virtual void deregister_socket_acceptor(socket_acceptor& acceptor) = 0;
// The value to use for uninitialised implementations.
static const impl_type invalid_impl = invalid_socket;
// The type of the stream sockets that will be connected.
typedef basic_stream_socket<stream_socket_service> peer_type;
// Create a new socket connector implementation.
void create(impl_type& impl, const socket_address& address);
// Create a new socket connector implementation.
void create(impl_type& impl, const socket_address& address,
int listen_queue);
// Destroy a socket connector implementation.
void destroy(impl_type& impl);
// Accept a new connection. Throws a socket_error exception on failure.
void accept(impl_type& impl, peer_type& peer_socket);
// Accept a new connection. Throws a socket_error exception on failure.
void accept(impl_type& impl, peer_type& peer_socket,
socket_address& peer_address);
// The type of a handler called when the asynchronous accept completes. The
// only argument is the error code.
typedef boost::function1<void, const socket_error&> accept_handler;
// Start an asynchronous accept. The peer_socket object must be valid until
// the accept's completion handler is invoked.
void async_accept(impl_type& impl, peer_type& peer_socket,
const accept_handler& handler, completion_context& context);
// Start an asynchronous accept. The peer_socket and peer_address objects
// must be valid until the accept's completion handler is invoked.
void async_accept(impl_type& impl, peer_type& peer_socket,
socket_address& peer_address, const accept_handler& handler,
completion_context& context);
private:
// Destroy a socket connector implementation.
virtual void do_socket_acceptor_destroy(impl_type& impl) = 0;
// Start an asynchronous accept on the given socket. The peer_socket object
// must be valid until the accept's completion handler is invoked.
virtual void async_socket_accept(socket_acceptor& acceptor,
stream_socket& peer_socket, const accept_handler& handler,
virtual void do_socket_acceptor_async_accept(impl_type& impl,
peer_type& peer_socket, const accept_handler& handler,
completion_context& context) = 0;
// Start an asynchronous accept on the given socket. The peer_socket and
// peer_address objects must be valid until the accept's completion handler
// is invoked.
virtual void async_socket_accept(socket_acceptor& acceptor,
stream_socket& peer_socket, socket_address& peer_address,
virtual void do_socket_acceptor_async_accept(impl_type& impl,
peer_type& peer_socket, socket_address& peer_address,
const accept_handler& handler, completion_context& context) = 0;
protected:
// Associate the given stream_socket with the underlying native handle that
// was obtained by the acceptor.
static void associate_accepted_stream_socket(socket_acceptor& acceptor,
stream_socket& peer_socket, stream_socket::native_type handle);
};
} // namespace detail

View File

@ -14,19 +14,81 @@
#include "asio/detail/socket_connector_service.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/socket_address.hpp"
#include "asio/socket_error.hpp"
#include "asio/detail/socket_connector_impl.hpp"
#include "asio/detail/socket_holder.hpp"
#include "asio/detail/socket_ops.hpp"
namespace asio {
namespace detail {
const service_type_id socket_connector_service::id;
const socket_connector_service::impl_type
socket_connector_service::invalid_impl;
void
socket_connector_service::
associate_connected_stream_socket(
socket_connector& connector,
stream_socket& peer_socket,
stream_socket::native_type handle)
create(
impl_type& impl)
{
connector.associate(peer_socket, handle);
impl = new socket_connector_impl;
}
void
socket_connector_service::
destroy(impl_type& impl)
{
do_socket_connector_destroy(impl);
}
void
socket_connector_service::
connect(
impl_type& impl,
peer_type& peer_socket,
const socket_address& peer_address)
{
// We cannot connect a socket that is already open.
if (peer_socket.impl() != invalid_socket)
boost::throw_exception(socket_error(socket_error::already_connected));
// Create a new socket for the connection. This will not be put into the
// stream_socket object until the connection has beenestablished.
socket_holder sock(socket_ops::socket(peer_address.family(), SOCK_STREAM,
IPPROTO_TCP));
if (sock.get() == invalid_socket)
boost::throw_exception(socket_error(socket_ops::get_error()));
// Perform the connect operation itself.
impl->add_socket(sock.get());
int result = socket_ops::connect(sock.get(), peer_address.native_address(),
peer_address.native_size());
impl->remove_socket(sock.get());
if (result == socket_error_retval)
boost::throw_exception(socket_error(socket_ops::get_error()));
// Connection was successful. The stream_socket object will now take
// ownership of the newly connected native socket handle.
peer_socket.set_impl(sock.release());
}
void
socket_connector_service::
async_connect(
impl_type& impl,
peer_type& peer_socket,
const socket_address& peer_address,
const connect_handler& handler,
completion_context& context)
{
do_socket_connector_async_connect(impl, peer_socket, peer_address, handler,
context);
}
} // namespace detail

View File

@ -17,8 +17,18 @@
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/function.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_stream_socket.hpp"
#include "asio/service.hpp"
#include "asio/service_type_id.hpp"
#include "asio/detail/stream_socket_service.hpp"
namespace asio { class completion_context; }
namespace asio { class socket_address; }
namespace asio { class socket_error; }
namespace asio {
namespace detail {
@ -29,17 +39,18 @@ class socket_connector_service
: public virtual service
{
public:
typedef socket_connector::connect_handler connect_handler;
// The service type id.
static const service_type_id id;
/// The native type of the socket connector. This type is dependent on the
/// underlying implementation of the socket layer.
// The native type of the socket connector. This type is dependent on the
// underlying implementation of the socket layer.
typedef socket_connector_impl* impl_type;
// Initialise a socket connector to a null implementation.
void nullify(impl_type& impl);
// The type of the stream sockets that will be connected.
typedef basic_stream_socket<stream_socket_service> peer_type;
// The value to use for uninitialised implementations.
static const impl_type invalid_impl = 0;
// Create a new socket connector implementation.
void create(impl_type& impl);
@ -48,36 +59,28 @@ public:
void destroy(impl_type& impl);
// Connect the given socket to the peer at the specified address. Throws a
// socket_error exception on failure.
void connect(socket_type& peer_socket, const socket_address& peer_address);
// socket_error exception on error.
void connect(impl_type& impl, peer_type& peer_socket,
const socket_address& peer_address);
// The type of a handler called when the asynchronous connect completes. The
// only argument is the error code.
typedef boost::function1<void, const socket_error&> connect_handler;
// Start an asynchronous connect. The peer_socket object must be valid until
// the connect's completion handler is invoked.
void async_connect(peer_socket& peer_socket,
void async_connect(impl_type& impl, peer_type& peer_socket,
const socket_address& peer_address, const connect_handler& handler,
completion_context& context = completion_context::null());
// Register a new socket_connector with the service. This should be called
// only after the socket connector has been opened.
virtual void register_socket_connector(socket_connector& connector) = 0;
// Remove a socket connector registration from the service. This should be
// called immediately before the socket connector is closed.
virtual void deregister_socket_connector(socket_connector& connector) = 0;
// Start an asynchronous connect on the given socket. The peer_socket object
// be valid until the connect's completion handler is invoked.
virtual void async_socket_connect(socket_connector& connector,
stream_socket& peer_socket, const socket_address& peer_address,
const connect_handler& handler, completion_context& context) = 0;
protected:
// Associate the given stream_socket with the underlying native handle that
// was obtained by the connector.
static void associate_connected_stream_socket(socket_connector& connector,
stream_socket& peer_socket, stream_socket::native_type handle);
completion_context& context);
private:
// Destroy a socket connector implementation.
virtual void do_socket_connector_destroy(impl_type& impl) = 0;
// Start an asynchronous connect.
virtual void do_socket_connector_async_connect(impl_type& impl,
peer_type& peer_socket, const socket_address& peer_address,
const connect_handler& handler, completion_context& context) = 0;
};
} // namespace detail

View File

@ -14,10 +14,176 @@
#include "asio/detail/stream_socket_service.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/socket_error.hpp"
#include "asio/detail/socket_ops.hpp"
namespace asio {
namespace detail {
const service_type_id stream_socket_service::id;
const stream_socket_service::impl_type stream_socket_service::invalid_impl;
void
stream_socket_service::
create(
impl_type& impl,
impl_type new_impl)
{
do_stream_socket_create(impl, new_impl);
}
void
stream_socket_service::
destroy(
impl_type& impl)
{
do_stream_socket_destroy(impl);
}
size_t
stream_socket_service::
send(
impl_type& impl,
const void* data,
size_t length)
{
int bytes_sent = socket_ops::send(impl, data, length, 0);
if (bytes_sent < 0)
boost::throw_exception(socket_error(socket_ops::get_error()));
return bytes_sent;
}
void
stream_socket_service::
async_send(
impl_type& impl,
const void* data,
size_t length,
const send_handler& handler,
completion_context& context)
{
do_stream_socket_async_send(impl, data, length, handler, context);
}
size_t
stream_socket_service::
send_n(
impl_type& impl,
const void* data,
size_t length,
size_t* total_bytes_sent)
{
// TODO handle non-blocking sockets using select to wait until ready.
int bytes_sent = 0;
size_t total_sent = 0;
while (total_sent < length)
{
bytes_sent = socket_ops::send(impl,
static_cast<const char*>(data) + total_sent, length - total_sent, 0);
if (bytes_sent < 0)
{
boost::throw_exception(socket_error(socket_ops::get_error()));
}
else if (bytes_sent == 0)
{
if (total_bytes_sent)
*total_bytes_sent = total_sent;
return bytes_sent;
}
total_sent += bytes_sent;
}
if (total_bytes_sent)
*total_bytes_sent = total_sent;
return bytes_sent;
}
void
stream_socket_service::
async_send_n(
impl_type& impl,
const void* data,
size_t length,
const send_n_handler& handler,
completion_context& context)
{
do_stream_socket_async_send_n(impl, data, length, handler, context);
}
size_t
stream_socket_service::
recv(
impl_type& impl,
void* data,
size_t max_length)
{
int bytes_recvd = socket_ops::recv(impl, data, max_length, 0);
if (bytes_recvd < 0)
boost::throw_exception(socket_error(socket_ops::get_error()));
return bytes_recvd;
}
void
stream_socket_service::
async_recv(
impl_type& impl,
void* data,
size_t max_length,
const recv_handler& handler,
completion_context& context)
{
do_stream_socket_async_recv(impl, data, max_length, handler, context);
}
size_t
stream_socket_service::
recv_n(
impl_type& impl,
void* data,
size_t length,
size_t* total_bytes_recvd)
{
// TODO handle non-blocking sockets using select to wait until ready.
int bytes_recvd = 0;
size_t total_recvd = 0;
while (total_recvd < length)
{
bytes_recvd = socket_ops::recv(impl,
static_cast<char*>(data) + total_recvd, length - total_recvd, 0);
if (bytes_recvd < 0)
{
boost::throw_exception(socket_error(socket_ops::get_error()));
}
else if (bytes_recvd == 0)
{
if (total_bytes_recvd)
*total_bytes_recvd = total_recvd;
return bytes_recvd;
}
total_recvd += bytes_recvd;
}
if (total_bytes_recvd)
*total_bytes_recvd = total_recvd;
return bytes_recvd;
}
void
stream_socket_service::
async_recv_n(
impl_type& impl,
void* data,
size_t length,
const recv_n_handler& handler,
completion_context& context)
{
do_stream_socket_async_recv_n(impl, data, length, handler, context);
}
} // namespace detail
} // namespace asio

View File

@ -17,9 +17,16 @@
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/function.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/service.hpp"
#include "asio/service_type_id.hpp"
#include "asio/stream_socket.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio { class completion_context; }
namespace asio { class socket_error; }
namespace asio {
namespace detail {
@ -28,47 +35,114 @@ class stream_socket_service
: public virtual service
{
public:
typedef stream_socket::send_handler send_handler;
typedef stream_socket::send_n_handler send_n_handler;
typedef stream_socket::recv_handler recv_handler;
typedef stream_socket::recv_n_handler recv_n_handler;
// The service type id.
static const service_type_id id;
// Register a new stream socket with the service. This should be called only
// after the socket has been opened, i.e. after an accept or just before a
// connect.
virtual void register_stream_socket(stream_socket& socket) = 0;
// The native type of the stream socket. This type is dependent on the
// underlying implementation of the socket layer.
typedef socket_type impl_type;
// Remove a stream socket registration from the service. This should be
// called immediately before the socket is closed.
virtual void deregister_stream_socket(stream_socket& socket) = 0;
// The value to use for uninitialised implementations.
static const impl_type invalid_impl = invalid_socket;
// Create a new socket connector implementation.
void create(impl_type& impl, impl_type new_impl);
// Destroy a socket connector implementation.
void destroy(impl_type& impl);
// Send the given data to the peer. Returns the number of bytes sent or
// 0 if the connection was closed cleanly. Throws a socket_error exception
// on failure.
size_t send(impl_type& impl, const void* data, size_t length);
// The handler when a send operation is completed. The first argument is the
// error code, the second is the number of bytes sent.
typedef boost::function2<void, const socket_error&, size_t> send_handler;
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
virtual void async_stream_socket_send(stream_socket& socket,
const void* data, size_t length, const send_handler& handler,
completion_context& context) = 0;
void async_send(impl_type& impl, const void* data, size_t length,
const send_handler& handler, completion_context& context);
// Send all of the given data to the peer before returning. Returns the
// number of bytes sent on the last send or 0 if the connection was closed
// cleanly. Throws a socket_error exception on failure.
size_t send_n(impl_type& impl, const void* data, size_t length,
size_t* total_bytes_sent);
// The handler when a send_n operation is completed. The first argument is
// the error code, the second is the total number of bytes sent, and the
// third is the number of bytes sent in the last send operation.
typedef boost::function3<void, const socket_error&, size_t, size_t>
send_n_handler;
// Start an asynchronous send that will not return until all of the data has
// been sent or an error occurs. The data being sent must be valid for the
// lifetime of the asynchronous operation.
virtual void async_stream_socket_send_n(stream_socket& socket,
const void* data, size_t length, const send_n_handler& handler,
completion_context& context) = 0;
void async_send_n(impl_type& impl, const void* data, size_t length,
const send_n_handler& handler, completion_context& context);
// Receive some data from the peer. Returns the number of bytes received or
// 0 if the connection was closed cleanly. Throws a socket_error exception
// on failure.
size_t recv(impl_type& impl, void* data, size_t max_length);
// The handler when a recv operation is completed. The first argument is the
// error code, the second is the number of bytes received.
typedef boost::function2<void, const socket_error&, size_t> recv_handler;
// Start an asynchronous receive. The buffer for the data being received
// must be valid for the lifetime of the asynchronous operation.
virtual void async_stream_socket_recv(stream_socket& socket, void* data,
size_t max_length, const recv_handler& handler,
completion_context& context) = 0;
void async_recv(impl_type& impl, void* data, size_t max_length,
const recv_handler& handler, completion_context& context);
// Receive the specified amount of data from the peer. Returns the number of
// bytes received on the last recv call or 0 if the connection
// was closed cleanly. Throws a socket_error exception on failure.
size_t recv_n(impl_type& impl, void* data, size_t length,
size_t* total_bytes_recvd);
// The handler when a recv_n operation is completed. The first argument is
// the error code, the second is the number of bytes received, the third is
// the number of bytes received in the last recv operation.
typedef boost::function3<void, const socket_error&, size_t, size_t>
recv_n_handler;
// Start an asynchronous receive that will not return until the specified
// number of bytes has been received or an error occurs. The buffer for the
// data being received must be valid for the lifetime of the asynchronous
// operation.
virtual void async_stream_socket_recv_n(stream_socket& socket, void* data,
void async_recv_n(impl_type& impl, void* data, size_t length,
const recv_n_handler& handler, completion_context& context);
private:
// Create a new socket connector implementation.
virtual void do_stream_socket_create(impl_type& impl,
impl_type new_impl) = 0;
// Destroy a socket connector implementation.
virtual void do_stream_socket_destroy(impl_type& impl) = 0;
// Start an asynchronous send.
virtual void do_stream_socket_async_send(impl_type& impl, const void* data,
size_t length, const send_handler& handler,
completion_context& context) = 0;
// Start an asynchronous send that will not return until all of the data has
// been sent or an error occurs.
virtual void do_stream_socket_async_send_n(impl_type& impl, const void* data,
size_t length, const send_n_handler& handler,
completion_context& context) = 0;
// Start an asynchronous receive.
virtual void do_stream_socket_async_recv(impl_type& impl, void* data,
size_t max_length, const recv_handler& handler,
completion_context& context) = 0;
// Start an asynchronous receive that will not return until the specified
// number of bytes has been received or an error occurs.
virtual void do_stream_socket_async_recv_n(impl_type& impl, void* data,
size_t length, const recv_n_handler& handler,
completion_context& context) = 0;
};

View File

@ -22,10 +22,11 @@
#include <boost/thread/xtime.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/completion_context.hpp"
#include "asio/service.hpp"
#include "asio/service_type_id.hpp"
namespace asio { class completion_context; }
namespace asio {
namespace detail {
@ -36,23 +37,22 @@ public:
// The service type id.
static const service_type_id id;
/// The handler for when a timer expires.
// The handler for when a timer expires.
typedef boost::function0<void> timer_handler;
/// Schedule a timer to fire once at the given start_time. The id of the new
/// timer is returned so that it may be cancelled.
// Schedule a timer to fire once at the given start_time. The id of the new
// timer is returned so that it may be cancelled.
int schedule_timer(void* owner, const boost::xtime& start_time,
const timer_handler& handler,
completion_context& context = completion_context::null());
const timer_handler& handler, completion_context& context);
/// Schedule a timer to fire first after at the start time, and then every
/// interval until the timer is cancelled. The id of the new timer is
/// returned so that it may be cancelled.
// Schedule a timer to fire first after at the start time, and then every
// interval until the timer is cancelled. The id of the new timer is
// returned so that it may be cancelled.
int schedule_timer(void* owner, const boost::xtime& start_time,
const boost::xtime& interval, const timer_handler& handler,
completion_context& context = completion_context::null());
completion_context& context);
/// Cancel the timer with the given id.
// Cancel the timer with the given id.
void cancel_timer(void* owner, int timer_id);
private:

View File

@ -17,7 +17,7 @@
#include "asio/detail/push_options.hpp"
#include "asio/dgram_socket.hpp"
#include "asio/basic_dgram_socket.hpp"
#include "asio/detail/dgram_socket_service.hpp"
namespace asio {

View File

@ -1,172 +0,0 @@
//
// socket_acceptor.cpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003 Christopher M. Kohlhoff (chris@kohlhoff.com)
//
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appears in all copies and that both the copyright
// notice and this permission notice appear in supporting documentation. This
// software is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
#include "asio/socket_acceptor.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <cassert>
#include "asio/detail/pop_options.hpp"
#include "asio/demuxer.hpp"
#include "asio/socket_address.hpp"
#include "asio/socket_error.hpp"
#include "asio/detail/socket_acceptor_service.hpp"
#include "asio/detail/socket_holder.hpp"
#include "asio/detail/socket_ops.hpp"
namespace asio {
socket_acceptor::
socket_acceptor(
demuxer& d)
: service_(dynamic_cast<detail::socket_acceptor_service&>(
d.get_service(detail::socket_acceptor_service::id))),
handle_(detail::invalid_socket)
{
}
socket_acceptor::
socket_acceptor(
demuxer& d,
const socket_address& addr,
int listen_queue)
: service_(dynamic_cast<detail::socket_acceptor_service&>(
d.get_service(detail::socket_acceptor_service::id))),
handle_(detail::invalid_socket)
{
open(addr, listen_queue);
}
socket_acceptor::
~socket_acceptor()
{
close();
}
void
socket_acceptor::
open(
const socket_address& addr,
int listen_queue)
{
assert(handle_ == detail::invalid_socket);
detail::socket_holder sock(detail::socket_ops::socket(addr.family(),
SOCK_STREAM, IPPROTO_TCP));
if (sock.get() == detail::invalid_socket)
boost::throw_exception(socket_error(detail::socket_ops::get_error()));
int reuse = 1;
detail::socket_ops::setsockopt(sock.get(), SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
if (detail::socket_ops::bind(sock.get(), addr.native_address(),
addr.native_size()) == detail::socket_error_retval)
boost::throw_exception(socket_error(detail::socket_ops::get_error()));
if (detail::socket_ops::listen(sock.get(), listen_queue)
== detail::socket_error_retval)
boost::throw_exception(socket_error(detail::socket_ops::get_error()));
handle_ = sock.release();
service_.register_socket_acceptor(*this);
}
void
socket_acceptor::
close()
{
if (handle_ != detail::invalid_socket)
{
service_.deregister_socket_acceptor(*this);
detail::socket_ops::close(handle_);
handle_ = detail::invalid_socket;
}
}
socket_acceptor::native_type
socket_acceptor::
native_handle() const
{
return handle_;
}
void
socket_acceptor::
accept_i(
stream_socket& peer_socket)
{
// We cannot accept a socket that is already open.
if (peer_socket.native_handle() != detail::invalid_socket)
boost::throw_exception(socket_error(socket_error::already_connected));
detail::socket_type new_socket = detail::socket_ops::accept(handle_, 0, 0);
if (int error = detail::socket_ops::get_error())
boost::throw_exception(socket_error(error));
peer_socket.associate(new_socket);
}
void
socket_acceptor::
accept_i(
stream_socket& peer_socket,
socket_address& peer_address)
{
// We cannot accept a socket that is already open.
if (peer_socket.native_handle() != detail::invalid_socket)
boost::throw_exception(socket_error(socket_error::already_connected));
detail::socket_addr_len_type addr_len = peer_address.native_size();
detail::socket_type new_socket = detail::socket_ops::accept(handle_,
peer_address.native_address(), &addr_len);
if (int error = detail::socket_ops::get_error())
boost::throw_exception(socket_error(error));
peer_address.native_size(addr_len);
peer_socket.associate(new_socket);
}
void
socket_acceptor::
async_accept_i(
stream_socket& peer_socket,
const accept_handler& handler,
completion_context& context)
{
service_.async_socket_accept(*this, peer_socket, handler, context);
}
void
socket_acceptor::
async_accept_i(
stream_socket& peer_socket,
socket_address& peer_address,
const accept_handler& handler,
completion_context& context)
{
service_.async_socket_accept(*this, peer_socket, peer_address, handler,
context);
}
void
socket_acceptor::
associate(
stream_socket& peer_socket,
stream_socket::native_type handle)
{
peer_socket.associate(handle);
}
} // namespace asio

View File

@ -17,138 +17,14 @@
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/completion_context.hpp"
#include "asio/stream_socket.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/basic_socket_acceptor.hpp"
#include "asio/detail/socket_acceptor_service.hpp"
namespace asio {
class demuxer;
class socket_address;
class socket_error;
namespace detail { class socket_acceptor_service; }
/// The socket_acceptor class is used for accepting new socket connections.
class socket_acceptor
: private boost::noncopyable
{
public:
/// The native type of the socket acceptor. This type is dependent on the
/// underlying implementation of the socket layer.
typedef detail::socket_type native_type;
/// Constructor an acceptor without opening it. The acceptor needs to be
/// opened before it can accept new connections.
explicit socket_acceptor(demuxer& d);
/// Construct an acceptor opened on the given address and with the listen
/// queue set to the given number of connections.
socket_acceptor(demuxer& d, const socket_address& addr,
int listen_queue = SOMAXCONN);
/// Destructor.
~socket_acceptor();
/// Open the acceptor using the given address and length of the listen queue.
void open(const socket_address& addr, int listen_queue = SOMAXCONN);
/// Close the acceptor.
void close();
/// Get the underlying handle in the native type.
native_type native_handle() const;
/// Accept a new connection. Throws a socket_error exception on failure.
template <typename Stream>
void accept(Stream& peer_socket)
{
accept_i(peer_socket.lowest_layer());
}
/// Accept a new connection. Throws a socket_error exception on failure.
template <typename Stream>
void accept(Stream& peer_socket, socket_address& peer_address)
{
accept_i(peer_socket.lowest_layer(), peer_address);
}
/// The type of a handler called when the asynchronous accept completes. The
/// only argument is the error code.
typedef boost::function1<void, const socket_error&> accept_handler;
/// Start an asynchronous accept. The peer_socket object must be valid until
/// the accept's completion handler is invoked.
template <typename Stream>
void async_accept(Stream& peer_socket, const accept_handler& handler)
{
async_accept_i(peer_socket.lowest_layer(), handler);
}
/// Start an asynchronous accept. The peer_socket object must be valid until
/// the accept's completion handler is invoked.
template <typename Stream>
void async_accept(Stream& peer_socket, const accept_handler& handler,
completion_context& context)
{
async_accept_i(peer_socket.lowest_layer(), handler, context);
}
/// Start an asynchronous accept. The peer_socket and peer_address objects
/// must be valid until the accept's completion handler is invoked.
template <typename Stream>
void async_accept(Stream& peer_socket, socket_address& peer_address,
const accept_handler& handler)
{
async_accept_i(peer_socket.lowest_layer(), peer_address, handler);
}
/// Start an asynchronous accept. The peer_socket and peer_address objects
/// must be valid until the accept's completion handler is invoked.
template <typename Stream>
void async_accept(Stream& peer_socket, socket_address& peer_address,
const accept_handler& handler, completion_context& context)
{
async_accept_i(peer_socket.lowest_layer(), peer_address, handler, context);
}
private:
/// The socket_acceptor_service class is permitted to call the associate()
/// function.
friend class detail::socket_acceptor_service;
// Accept a new connection. Throws a socket_error exception on failure.
void accept_i(stream_socket& peer_socket);
// Accept a new connection. Throws a socket_error exception on failure.
void accept_i(stream_socket& peer_socket, socket_address& peer_address);
// Start an asynchronous accept. The peer_socket object must be valid until
// the accept's completion handler is invoked.
void async_accept_i(stream_socket& peer_socket,
const accept_handler& handler,
completion_context& context = completion_context::null());
// Start an asynchronous accept. The peer_socket and peer_address objects
// must be valid until the accept's completion handler is invoked.
void async_accept_i(stream_socket& peer_socket, socket_address& peer_address,
const accept_handler& handler,
completion_context& context = completion_context::null());
/// Associate the given stream socket with the native socket handle.
void associate(stream_socket& peer_socket,
stream_socket::native_type handle);
/// The backend service implementation.
detail::socket_acceptor_service& service_;
/// The underlying native handle.
native_type handle_;
};
/// Typedef for the typical usage of socket_acceptor.
typedef basic_socket_acceptor<detail::socket_acceptor_service>
socket_acceptor;
} // namespace asio

View File

@ -1,127 +0,0 @@
//
// socket_connector.cpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003 Christopher M. Kohlhoff (chris@kohlhoff.com)
//
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appears in all copies and that both the copyright
// notice and this permission notice appear in supporting documentation. This
// software is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
#include "asio/socket_connector.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <cassert>
#include "asio/detail/pop_options.hpp"
#include "asio/demuxer.hpp"
#include "asio/socket_address.hpp"
#include "asio/socket_error.hpp"
#include "asio/detail/socket_connector_impl.hpp"
#include "asio/detail/socket_connector_service.hpp"
#include "asio/detail/socket_holder.hpp"
#include "asio/detail/socket_ops.hpp"
namespace asio {
socket_connector::
socket_connector(
demuxer& d)
: service_(dynamic_cast<detail::socket_connector_service&>(
d.get_service(detail::socket_connector_service::id))),
impl_(new detail::socket_connector_impl)
{
service_.register_socket_connector(*this);
}
socket_connector::
~socket_connector()
{
delete impl_;
}
void
socket_connector::
open()
{
assert(impl_ == 0);
impl_ = new detail::socket_connector_impl;
service_.register_socket_connector(*this);
}
void
socket_connector::
close()
{
if (impl_)
{
service_.deregister_socket_connector(*this);
delete impl_;
impl_ = 0;
}
}
socket_connector::native_type
socket_connector::
native_handle() const
{
return impl_;
}
void
socket_connector::
connect_i(
stream_socket& peer_socket,
const socket_address& peer_address)
{
// We cannot connect a socket that is already open.
if (peer_socket.native_handle() != detail::invalid_socket)
boost::throw_exception(socket_error(socket_error::already_connected));
// Create a new socket for the connection. This will not be put into the
// stream_socket object until the connection has beenestablished.
detail::socket_holder sock(detail::socket_ops::socket(peer_address.family(),
SOCK_STREAM, IPPROTO_TCP));
if (sock.get() == detail::invalid_socket)
boost::throw_exception(socket_error(detail::socket_ops::get_error()));
// Perform the connect operation itself.
impl_->add_socket(sock.get());
int result = detail::socket_ops::connect(sock.get(),
peer_address.native_address(), peer_address.native_size());
impl_->remove_socket(sock.get());
if (result == detail::socket_error_retval)
boost::throw_exception(socket_error(detail::socket_ops::get_error()));
// Connection was successful. The stream_socket object will now take
// ownership of the newly connected native socket handle.
peer_socket.associate(sock.release());
}
void
socket_connector::
async_connect_i(
stream_socket& peer_socket,
const socket_address& peer_address,
const connect_handler& handler,
completion_context& context)
{
service_.async_socket_connect(*this, peer_socket, peer_address, handler,
context);
}
void
socket_connector::
associate(
stream_socket& peer_socket,
stream_socket::native_type handle)
{
peer_socket.associate(handle);
}
} // namespace asio

View File

@ -17,106 +17,14 @@
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/completion_context.hpp"
#include "asio/stream_socket.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/basic_socket_connector.hpp"
#include "asio/detail/socket_connector_service.hpp"
namespace asio {
class demuxer;
class socket_address;
class socket_error;
namespace detail { class socket_connector_service; }
namespace detail { class socket_connector_impl; }
/// The socket_connector class is used to connect a socket to a remote
/// endpoint.
class socket_connector
: private boost::noncopyable
{
public:
/// The native type of the socket connector. This type is dependent on the
/// underlying implementation of the socket layer.
typedef detail::socket_connector_impl* native_type;
/// Constructor a connector. The connector is automatically opened.
explicit socket_connector(demuxer& d);
/// Destructor.
~socket_connector();
/// Open the connector.
void open();
/// Close the connector.
void close();
/// Get the underlying handle in the native type.
native_type native_handle() const;
/// Connect the given socket to the peer at the specified address. Throws a
/// socket_error exception on failure.
template <typename Stream>
void connect(Stream& peer_socket, const socket_address& peer_address)
{
connect_i(peer_socket.lowest_layer(), peer_address);
}
/// The type of a handler called when the asynchronous connect completes. The
/// only argument is the error code.
typedef boost::function1<void, const socket_error&> connect_handler;
/// Start an asynchronous connect. The peer_socket object must be valid until
/// the connect's completion handler is invoked.
template <typename Stream>
void async_connect(Stream& peer_socket,
const socket_address& peer_address, const connect_handler& handler)
{
async_connect_i(peer_socket.lowest_layer(), peer_address, handler);
}
/// Start an asynchronous connect. The peer_socket object must be valid until
/// the connect's completion handler is invoked.
template <typename Stream>
void async_connect(Stream& peer_socket,
const socket_address& peer_address, const connect_handler& handler,
completion_context& context)
{
async_connect_i(peer_socket.lowest_layer(), peer_address, handler,
context);
}
private:
/// The socket_connector_service is permitted to call the associate()
/// function.
friend class detail::socket_connector_service;
// Connect the given socket to the peer at the specified address. Throws a
// socket_error exception on failure.
void connect_i(stream_socket& peer_socket,
const socket_address& peer_address);
// Start an asynchronous connect. The peer_socket object must be valid until
// the connect's completion handler is invoked.
void async_connect_i(stream_socket& peer_socket,
const socket_address& peer_address, const connect_handler& handler,
completion_context& context = completion_context::null());
/// Associate the given stream socket with the native socket handle.
void associate(stream_socket& peer_socket,
stream_socket::native_type handle);
/// The backend service implementation.
detail::socket_connector_service& service_;
/// The underlying implementation.
detail::socket_connector_impl* impl_;
};
/// Typedef for the typical usage of socket_connector.
typedef basic_socket_connector<detail::socket_connector_service>
socket_connector;
} // namespace asio

View File

@ -1,213 +0,0 @@
//
// stream_socket.cpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003 Christopher M. Kohlhoff (chris@kohlhoff.com)
//
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appears in all copies and that both the copyright
// notice and this permission notice appear in supporting documentation. This
// software is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
#include "asio/stream_socket.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <cassert>
#include "asio/detail/pop_options.hpp"
#include "asio/demuxer.hpp"
#include "asio/socket_error.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/stream_socket_service.hpp"
namespace asio {
stream_socket::
stream_socket(
demuxer& d)
: service_(dynamic_cast<detail::stream_socket_service&>(
d.get_service(detail::stream_socket_service::id))),
handle_(detail::invalid_socket)
{
}
stream_socket::
~stream_socket()
{
close();
}
void
stream_socket::
close()
{
if (handle_ != detail::invalid_socket)
{
service_.deregister_stream_socket(*this);
detail::socket_ops::close(handle_);
handle_ = detail::invalid_socket;
}
}
stream_socket::lowest_layer_type&
stream_socket::
lowest_layer()
{
return *this;
}
stream_socket::native_type
stream_socket::
native_handle() const
{
return handle_;
}
size_t
stream_socket::
send(
const void* data,
size_t length)
{
int bytes_sent = detail::socket_ops::send(handle_, data, length, 0);
if (bytes_sent < 0)
boost::throw_exception(socket_error(detail::socket_ops::get_error()));
return bytes_sent;
}
void
stream_socket::
async_send(
const void* data,
size_t length,
const send_handler& handler,
completion_context& context)
{
service_.async_stream_socket_send(*this, data, length, handler, context);
}
size_t
stream_socket::
send_n(
const void* data,
size_t length,
size_t* total_bytes_sent)
{
// TODO handle non-blocking sockets using select to wait until ready.
int bytes_sent = 0;
size_t total_sent = 0;
while (total_sent < length)
{
bytes_sent = detail::socket_ops::send(handle_,
static_cast<const char*>(data) + total_sent, length - total_sent, 0);
if (bytes_sent < 0)
{
boost::throw_exception(socket_error(detail::socket_ops::get_error()));
}
else if (bytes_sent == 0)
{
if (total_bytes_sent)
*total_bytes_sent = total_sent;
return bytes_sent;
}
total_sent += bytes_sent;
}
if (total_bytes_sent)
*total_bytes_sent = total_sent;
return bytes_sent;
}
void
stream_socket::
async_send_n(
const void* data,
size_t length,
const send_n_handler& handler,
completion_context& context)
{
service_.async_stream_socket_send_n(*this, data, length, handler, context);
}
size_t
stream_socket::
recv(
void* data,
size_t max_length)
{
int bytes_recvd = detail::socket_ops::recv(handle_, data, max_length, 0);
if (bytes_recvd < 0)
boost::throw_exception(socket_error(detail::socket_ops::get_error()));
return bytes_recvd;
}
void
stream_socket::
async_recv(
void* data,
size_t max_length,
const recv_handler& handler,
completion_context& context)
{
service_.async_stream_socket_recv(*this, data, max_length, handler, context);
}
size_t
stream_socket::
recv_n(
void* data,
size_t length,
size_t* total_bytes_recvd)
{
// TODO handle non-blocking sockets using select to wait until ready.
int bytes_recvd = 0;
size_t total_recvd = 0;
while (total_recvd < length)
{
bytes_recvd = detail::socket_ops::recv(handle_,
static_cast<char*>(data) + total_recvd, length - total_recvd, 0);
if (bytes_recvd < 0)
{
boost::throw_exception(socket_error(detail::socket_ops::get_error()));
}
else if (bytes_recvd == 0)
{
if (total_bytes_recvd)
*total_bytes_recvd = total_recvd;
return bytes_recvd;
}
total_recvd += bytes_recvd;
}
if (total_bytes_recvd)
*total_bytes_recvd = total_recvd;
return bytes_recvd;
}
void
stream_socket::
async_recv_n(
void* data,
size_t length,
const recv_n_handler& handler,
completion_context& context)
{
service_.async_stream_socket_recv_n(*this, data, length, handler, context);
}
void
stream_socket::
associate(
native_type handle)
{
assert(handle_ == detail::invalid_socket);
handle_ = handle;
if (handle_ != detail::invalid_socket)
service_.register_stream_socket(*this);
}
} // namespace asio

View File

@ -17,136 +17,13 @@
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/completion_context.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/basic_stream_socket.hpp"
#include "asio/detail/stream_socket_service.hpp"
namespace asio {
class demuxer;
class socket_acceptor;
class socket_connector;
class socket_error;
namespace detail { class stream_socket_service; }
/// The stream_socket class provides asynchronous and blocking stream-oriented
/// socket functionality.
class stream_socket
: private boost::noncopyable
{
public:
/// The native type of the socket acceptor. This type is dependent on the
/// underlying implementation of the socket layer.
typedef detail::socket_type native_type;
/// A stream_socket is always the lowest layer.
typedef stream_socket lowest_layer_type;
/// Construct a stream_socket without opening it. The socket needs to be
/// connected or accepted before data can be sent or received on it.
explicit stream_socket(demuxer& d);
/// Destructor.
~stream_socket();
/// Close the socket.
void close();
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer();
/// Get the underlying handle in the native type.
native_type native_handle() const;
/// Attach a new socket implementation.
void set_impl(native_type impl);
/// Send the given data to the peer. Returns the number of bytes sent or
/// 0 if the connection was closed cleanly. Throws a socket_error exception
/// on failure.
size_t send(const void* data, size_t length);
/// The handler when a send operation is completed. The first argument is the
/// error code, the second is the number of bytes sent.
typedef boost::function2<void, const socket_error&, size_t> send_handler;
/// Start an asynchronous send. The data being sent must be valid for the
/// lifetime of the asynchronous operation.
void async_send(const void* data, size_t length,
const send_handler& handler,
completion_context& context = completion_context::null());
/// Send all of the given data to the peer before returning. Returns the
/// number of bytes sent on the last send or 0 if the connection was closed
/// cleanly. Throws a socket_error exception on failure.
size_t send_n(const void* data, size_t length, size_t* total_bytes_sent = 0);
/// The handler when a send_n operation is completed. The first argument is
/// the error code, the second is the total number of bytes sent, and the
/// third is the number of bytes sent in the last send operation.
typedef boost::function3<void, const socket_error&, size_t, size_t>
send_n_handler;
/// Start an asynchronous send that will not return until all of the data has
/// been sent or an error occurs. The data being sent must be valid for the
/// lifetime of the asynchronous operation.
void async_send_n(const void* data, size_t length,
const send_n_handler& handler,
completion_context& context = completion_context::null());
/// Receive some data from the peer. Returns the number of bytes received or
/// 0 if the connection was closed cleanly. Throws a socket_error exception
/// on failure.
size_t recv(void* data, size_t max_length);
/// The handler when a recv operation is completed. The first argument is the
/// error code, the second is the number of bytes received.
typedef boost::function2<void, const socket_error&, size_t> recv_handler;
/// Start an asynchronous receive. The buffer for the data being received must
/// be valid for the lifetime of the asynchronous operation.
void async_recv(void* data, size_t max_length,
const recv_handler& handler,
completion_context& context = completion_context::null());
/// Receive the specified amount of data from the peer. Returns the number of
/// bytes received on the last recv call or 0 if the connection
/// was closed cleanly. Throws a socket_error exception on failure.
size_t recv_n(void* data, size_t length, size_t* total_bytes_recvd = 0);
/// The handler when a recv_n operation is completed. The first argument is
/// the error code, the second is the number of bytes received, the third is
/// the number of bytes received in the last recv operation.
typedef boost::function3<void, const socket_error&, size_t, size_t>
recv_n_handler;
/// Start an asynchronous receive that will not return until the specified
/// number of bytes has been received or an error occurs. The buffer for the
/// data being received must be valid for the lifetime of the asynchronous
/// operation.
void async_recv_n(void* data, size_t length, const recv_n_handler& handler,
completion_context& context = completion_context::null());
private:
/// The socket_acceptor class is permitted to call the associate() function.
friend class socket_acceptor;
/// The socket_connector class is permitted to call the associate() function.
friend class socket_connector;
/// Associate the stream socket with the given native socket handle.
void associate(native_type handle);
/// The backend service implementation.
detail::stream_socket_service& service_;
/// The underlying native handle.
native_type handle_;
};
/// Typedef for the typical usage of stream_socket.
typedef basic_stream_socket<asio::detail::stream_socket_service> stream_socket;
} // namespace asio