blob: 32db158c668638c387dbf72a348a515da5661c53 [file] [log] [blame]
#ifndef PROTON_IO_CONNECTION_ENGINE_HPP
#define PROTON_IO_CONNECTION_ENGINE_HPP
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#include "../internal/config.hpp"
#include "../connection.hpp"
#include "../connection_options.hpp"
#include "../error.hpp"
#include "../error_condition.hpp"
#include "../internal/export.hpp"
#include "../internal/pn_unique_ptr.hpp"
#include "../transport.hpp"
#include "../types.hpp"
#include <cstddef>
#include <utility>
#include <string>
struct pn_collector_t;
namespace proton {
class event_loop;
class proton_handler;
namespace io {
class link_namer;
/// **Experimental** - Pointer to a mutable memory region with a size.
struct mutable_buffer {
char* data; ///< Beginning of the buffered data.
size_t size; ///< Number of bytes in the buffer.
/// Construct a buffer starting at data_ with size_ bytes.
mutable_buffer(char* data_=0, size_t size_=0) : data(data_), size(size_) {}
};
/// **Experimental** - Pointer to a const memory region with a size.
struct const_buffer {
const char* data; ///< Beginning of the buffered data.
size_t size; ///< Number of bytes in the buffer.
/// Construct a buffer starting at data_ with size_ bytes.
const_buffer(const char* data_=0, size_t size_=0) : data(data_), size(size_) {}
};
/// **Experimental** - An AMQP protocol engine for a single
/// connection.
///
/// A connection_engine is a protocol engine that integrates AMQP into
/// any IO or concurrency framework.
///
/// io::connection_engine manages a single proton::connection and dispatches
/// events to a proton::messaging_handler. It does no IO of its own, but allows you to
/// integrate AMQP protocol handling into any IO or concurrency framework.
///
/// The application is coded the same way as for the
/// proton::container. The application implements a
/// proton::messaging_handler to respond to transport, connection,
/// session, link, and message events. With a little care, the same
/// handler classes can be used for both container and
/// connection_engine. the @ref broker.cpp example illustrates this.
///
/// You need to write the IO code to read AMQP data to the
/// read_buffer(). The engine parses the AMQP frames. dispatch() calls
/// the appropriate functions on the applications proton::messaging_handler. You
/// write output data from the engine's write_buffer() to your IO.
///
/// The engine is not safe for concurrent use, but you can process
/// different engines concurrently. A common pattern for
/// high-performance servers is to serialize read/write activity
/// per connection and dispatch in a fixed-size thread pool.
///
/// The engine is designed to work with a classic reactor (e.g.,
/// select, poll, epoll) or an async-request driven proactor (e.g.,
/// windows completion ports, boost.asio, libuv).
///
/// The engine never throws exceptions.
class
PN_CPP_CLASS_EXTERN connection_engine {
public:
/// Create a connection engine. opts must contain a messaging_handler.
/// Takes ownership of loop, will be deleted only when the proton::connection is.
PN_CPP_EXTERN connection_engine(proton::container&, link_namer&, event_loop* loop = 0);
PN_CPP_EXTERN ~connection_engine();
/// Configure a connection by applying exactly the options in opts (including proton::messaging_handler)
/// Does not apply any default options, to apply container defaults use connect() or accept()
/// instead.
void configure(const connection_options& opts=connection_options());
/// Call configure() with client options and call connection::open()
/// Options applied: container::id(), container::client_connection_options(), opts.
PN_CPP_EXTERN void connect(const connection_options& opts);
/// Call configure() with server options.
/// Options applied: container::id(), container::server_connection_options(), opts.
///
/// Note this does not call connection::open(). If there is a messaging_handler in the
/// composed options it will receive messaging_handler::on_connection_open() and can
/// respond with connection::open() or connection::close()
PN_CPP_EXTERN void accept(const connection_options& opts);
/// The engine's read buffer. Read data into this buffer then call read_done() when complete.
/// Returns mutable_buffer(0, 0) if the engine cannot currently read data.
/// Calling dispatch() may open up more buffer space.
PN_CPP_EXTERN mutable_buffer read_buffer();
/// Indicate that the first n bytes of read_buffer() have valid data.
/// This changes the buffer, call read_buffer() to get the updated buffer.
PN_CPP_EXTERN void read_done(size_t n);
/// Indicate that the read side of the transport is closed and no more data will be read.
/// Note that there may still be events to dispatch() or data to write.
PN_CPP_EXTERN void read_close();
/// The engine's write buffer. Write data from this buffer then call write_done()
/// Returns const_buffer(0, 0) if the engine has nothing to write.
/// Calling dispatch() may generate more data in the write buffer.
PN_CPP_EXTERN const_buffer write_buffer() const;
/// Indicate that the first n bytes of write_buffer() have been written successfully.
/// This changes the buffer, call write_buffer() to get the updated buffer.
PN_CPP_EXTERN void write_done(size_t n);
/// Indicate that the write side of the transport has closed and no more data can be written.
/// Note that there may still be events to dispatch() or data to read.
PN_CPP_EXTERN void write_close();
/// Inform the engine that the transport been disconnected unexpectedly,
/// without completing the AMQP connection close sequence.
///
/// This calls read_close(), write_close(), sets the transport().error() and
/// queues an `on_transport_error` event. You must call dispatch() one more
/// time to dispatch the messaging_handler::on_transport_error() call and other final
/// events.
///
/// Note this does not close the connection() so that a proton::messaging_handler can
/// distinguish between a connection close error sent by the remote peer and
/// a transport failure.
///
PN_CPP_EXTERN void disconnected(const error_condition& = error_condition());
/// Dispatch all available events and call the corresponding \ref messaging_handler methods.
///
/// Returns true if the engine is still active, false if it is finished and
/// can be destroyed. The engine is finished when all events are dispatched
/// and one of the following is true:
///
/// - both read_close() and write_close() have been called, no more IO is possible.
/// - The AMQP connection() is closed AND the write_buffer() is empty.
///
/// May modify the read_buffer() and/or the write_buffer().
///
PN_CPP_EXTERN bool dispatch();
/// Get the AMQP connection associated with this connection_engine.
PN_CPP_EXTERN proton::connection connection() const;
/// Get the transport associated with this connection_engine.
PN_CPP_EXTERN proton::transport transport() const;
/// Get the container associated with this connection_engine.
PN_CPP_EXTERN proton::container& container() const;
private:
connection_engine(const connection_engine&);
connection_engine& operator=(const connection_engine&);
// TODO aconway 2016-05-06: reduce binary compat footprint, move stuff to connection context.
proton::proton_handler* handler_;
proton::connection connection_;
proton::transport transport_;
proton::internal::pn_ptr<pn_collector_t> collector_;
proton::container& container_;
};
} // io
} // proton
#endif // PROTON_IO_CONNECTION_ENGINE_HPP