diff --git a/asio/src/Makefile.am b/asio/src/Makefile.am index 2fbbd9ba..b8e1b7a8 100644 --- a/asio/src/Makefile.am +++ b/asio/src/Makefile.am @@ -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 \ diff --git a/asio/src/asio.hpp b/asio/src/asio.hpp index ed409913..c88dd9ca 100644 --- a/asio/src/asio.hpp +++ b/asio/src/asio.hpp @@ -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 diff --git a/asio/src/asio/basic_dgram_socket.hpp b/asio/src/asio/basic_dgram_socket.hpp index 26d68644..7e1c8cab 100644 --- a/asio/src/asio/basic_dgram_socket.hpp +++ b/asio/src/asio/basic_dgram_socket.hpp @@ -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(d.get_service(Service::id))) + : service_(dynamic_cast(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(d.get_service(Service::id))) + : service_(dynamic_cast(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_; diff --git a/asio/src/asio/basic_socket_acceptor.hpp b/asio/src/asio/basic_socket_acceptor.hpp new file mode 100644 index 00000000..abe065a2 --- /dev/null +++ b/asio/src/asio/basic_socket_acceptor.hpp @@ -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 +#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 +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(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(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(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 + void accept(Stream& peer_socket) + { + service_.accept(impl_, peer_socket.lowest_layer()); + } + + /// Accept a new connection. Throws a socket_error exception on failure. + template + 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 + 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 + 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 + 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 + 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 diff --git a/asio/src/asio/basic_socket_connector.hpp b/asio/src/asio/basic_socket_connector.hpp new file mode 100644 index 00000000..66867010 --- /dev/null +++ b/asio/src/asio/basic_socket_connector.hpp @@ -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 +#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 +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(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 + 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 + 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 + 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 diff --git a/asio/src/asio/basic_stream_socket.hpp b/asio/src/asio/basic_stream_socket.hpp new file mode 100644 index 00000000..9bb6253c --- /dev/null +++ b/asio/src/asio/basic_stream_socket.hpp @@ -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 +#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 +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 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(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 diff --git a/asio/src/asio/basic_timer_queue.hpp b/asio/src/asio/basic_timer_queue.hpp index 5a9ad10c..bb63e66d 100644 --- a/asio/src/asio/basic_timer_queue.hpp +++ b/asio/src/asio/basic_timer_queue.hpp @@ -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(d.get_service(Service::id))) + : service_(dynamic_cast(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 diff --git a/asio/src/asio/detail/dgram_socket_service.cpp b/asio/src/asio/detail/dgram_socket_service.cpp index bf75a32b..b7a5261d 100644 --- a/asio/src/asio/detail/dgram_socket_service.cpp +++ b/asio/src/asio/detail/dgram_socket_service.cpp @@ -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( diff --git a/asio/src/asio/detail/dgram_socket_service.hpp b/asio/src/asio/detail/dgram_socket_service.hpp index 1b8bc069..73f35dc9 100644 --- a/asio/src/asio/detail/dgram_socket_service.hpp +++ b/asio/src/asio/detail/dgram_socket_service.hpp @@ -21,11 +21,11 @@ #include #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 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 recvfrom_handler; // Start an asynchronous receive. The buffer for the data being received and diff --git a/asio/src/asio/detail/select_provider.cpp b/asio/src/asio/detail/select_provider.cpp index 944725e7..12349320 100644 --- a/asio/src/asio/detail/select_provider.cpp +++ b/asio/src/asio/detail/select_provider.cpp @@ -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; diff --git a/asio/src/asio/detail/select_provider.hpp b/asio/src/asio/detail/select_provider.hpp index 7aa6424e..6a4a7cc6 100644 --- a/asio/src/asio/detail/select_provider.hpp +++ b/asio/src/asio/detail/select_provider.hpp @@ -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. diff --git a/asio/src/asio/detail/socket_acceptor_service.cpp b/asio/src/asio/detail/socket_acceptor_service.cpp index 6acfed43..a2872e2e 100644 --- a/asio/src/asio/detail/socket_acceptor_service.cpp +++ b/asio/src/asio/detail/socket_acceptor_service.cpp @@ -14,19 +14,125 @@ #include "asio/detail/socket_acceptor_service.hpp" +#include "asio/detail/push_options.hpp" +#include +#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 diff --git a/asio/src/asio/detail/socket_acceptor_service.hpp b/asio/src/asio/detail/socket_acceptor_service.hpp index c36e9de2..3feafb75 100644 --- a/asio/src/asio/detail/socket_acceptor_service.hpp +++ b/asio/src/asio/detail/socket_acceptor_service.hpp @@ -17,10 +17,19 @@ #include "asio/detail/push_options.hpp" +#include "asio/detail/push_options.hpp" +#include +#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 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 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 diff --git a/asio/src/asio/detail/socket_connector_service.cpp b/asio/src/asio/detail/socket_connector_service.cpp index a4f0472e..6b0b512d 100644 --- a/asio/src/asio/detail/socket_connector_service.cpp +++ b/asio/src/asio/detail/socket_connector_service.cpp @@ -14,19 +14,81 @@ #include "asio/detail/socket_connector_service.hpp" +#include "asio/detail/push_options.hpp" +#include +#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 diff --git a/asio/src/asio/detail/socket_connector_service.hpp b/asio/src/asio/detail/socket_connector_service.hpp index 3e92a8ac..7f526583 100644 --- a/asio/src/asio/detail/socket_connector_service.hpp +++ b/asio/src/asio/detail/socket_connector_service.hpp @@ -17,8 +17,18 @@ #include "asio/detail/push_options.hpp" +#include "asio/detail/push_options.hpp" +#include +#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 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 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 diff --git a/asio/src/asio/detail/stream_socket_service.cpp b/asio/src/asio/detail/stream_socket_service.cpp index fcee13e8..4305b27c 100644 --- a/asio/src/asio/detail/stream_socket_service.cpp +++ b/asio/src/asio/detail/stream_socket_service.cpp @@ -14,10 +14,176 @@ #include "asio/detail/stream_socket_service.hpp" +#include "asio/detail/push_options.hpp" +#include +#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(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(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 diff --git a/asio/src/asio/detail/stream_socket_service.hpp b/asio/src/asio/detail/stream_socket_service.hpp index 47e63ed0..b82a64ea 100644 --- a/asio/src/asio/detail/stream_socket_service.hpp +++ b/asio/src/asio/detail/stream_socket_service.hpp @@ -17,9 +17,16 @@ #include "asio/detail/push_options.hpp" +#include "asio/detail/push_options.hpp" +#include +#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 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 + 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 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 + 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; }; diff --git a/asio/src/asio/detail/timer_queue_service.hpp b/asio/src/asio/detail/timer_queue_service.hpp index 7f7d7fab..f41ab552 100644 --- a/asio/src/asio/detail/timer_queue_service.hpp +++ b/asio/src/asio/detail/timer_queue_service.hpp @@ -22,10 +22,11 @@ #include #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 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: diff --git a/asio/src/asio/dgram_socket.hpp b/asio/src/asio/dgram_socket.hpp index 6b6dba05..1e7c643e 100644 --- a/asio/src/asio/dgram_socket.hpp +++ b/asio/src/asio/dgram_socket.hpp @@ -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 { diff --git a/asio/src/asio/socket_acceptor.cpp b/asio/src/asio/socket_acceptor.cpp deleted file mode 100644 index 0083734d..00000000 --- a/asio/src/asio/socket_acceptor.cpp +++ /dev/null @@ -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 -#include -#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( - 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( - 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 diff --git a/asio/src/asio/socket_acceptor.hpp b/asio/src/asio/socket_acceptor.hpp index 9a0b6639..b5202d14 100644 --- a/asio/src/asio/socket_acceptor.hpp +++ b/asio/src/asio/socket_acceptor.hpp @@ -17,138 +17,14 @@ #include "asio/detail/push_options.hpp" -#include "asio/detail/push_options.hpp" -#include -#include -#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 - void accept(Stream& peer_socket) - { - accept_i(peer_socket.lowest_layer()); - } - - /// Accept a new connection. Throws a socket_error exception on failure. - template - 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 accept_handler; - - /// Start an asynchronous accept. The peer_socket object must be valid until - /// the accept's completion handler is invoked. - template - 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 - 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 - 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 - 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 + socket_acceptor; } // namespace asio diff --git a/asio/src/asio/socket_connector.cpp b/asio/src/asio/socket_connector.cpp deleted file mode 100644 index 76817038..00000000 --- a/asio/src/asio/socket_connector.cpp +++ /dev/null @@ -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 -#include -#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( - 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 diff --git a/asio/src/asio/socket_connector.hpp b/asio/src/asio/socket_connector.hpp index 0e17e14d..ed5dfeb4 100644 --- a/asio/src/asio/socket_connector.hpp +++ b/asio/src/asio/socket_connector.hpp @@ -17,106 +17,14 @@ #include "asio/detail/push_options.hpp" -#include "asio/detail/push_options.hpp" -#include -#include -#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 - 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 connect_handler; - - /// Start an asynchronous connect. The peer_socket object must be valid until - /// the connect's completion handler is invoked. - template - 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 - 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 + socket_connector; } // namespace asio diff --git a/asio/src/asio/stream_socket.cpp b/asio/src/asio/stream_socket.cpp deleted file mode 100644 index 61c98246..00000000 --- a/asio/src/asio/stream_socket.cpp +++ /dev/null @@ -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 -#include -#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( - 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(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(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 diff --git a/asio/src/asio/stream_socket.hpp b/asio/src/asio/stream_socket.hpp index ecff0584..0ec8511e 100644 --- a/asio/src/asio/stream_socket.hpp +++ b/asio/src/asio/stream_socket.hpp @@ -17,136 +17,13 @@ #include "asio/detail/push_options.hpp" -#include "asio/detail/push_options.hpp" -#include -#include -#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 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 - 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 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 - 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 stream_socket; } // namespace asio