blob: 4565f339568b3457220e2bd7bda19720317c31d1 [file] [log] [blame]
#ifndef CONNECTION_ENGINE_HPP
#define 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 "proton/connection.hpp"
#include "proton/connection_options.hpp"
#include "proton/export.hpp"
#include "proton/id_generator.hpp"
#include "proton/pn_unique_ptr.hpp"
#include "proton/types.hpp"
#include <cstddef>
#include <utility>
#include <string>
namespace proton {
class connection_engine_context;
class handler;
class connection;
// TODO aconway 2016-01-23: doc contrast with container.
/// An interface for connection-oriented IO integration. A
/// connection_engine manages a single AMQP connection. It is useful
/// for integrating AMQP into an existing IO framework.
///
/// The engine provides a simple "bytes-in/bytes-out" interface. Incoming AMQP
/// bytes from any kind of data connection are fed into the engine and processed
/// to dispatch events to a proton::handler. The resulting AMQP output data is
/// available from the engine and can sent back over the connection.
///
/// The engine does no IO of its own. It assumes a two-way flow of bytes over
/// some externally-managed "connection". The "connection" could be a socket
/// managed by select, poll, epoll or some other mechanism, or it could be
/// something else such as an RDMA connection, a shared-memory buffer or a Unix
/// pipe.
///
/// The application is coded the same way for engine or container: you implement
/// proton::handler. Handlers attached to an engine will receive transport,
/// connection, session, link and message events. They will not receive reactor,
/// selectable or timer events, the engine assumes those are managed externally.
///
/// THREAD SAFETY: A single engine instance cannot be called concurrently, but
/// different engine instances can be processed concurrently in separate threads.
class connection_engine {
public:
// FIXME aconway 2016-01-23: DOC
class container {
public:
/// Create a container with id. Default to random UUID if id
/// == "".
PN_CPP_EXTERN container(const std::string &id = "");
/// Return the container-id
PN_CPP_EXTERN std::string id() const;
/// Make options to configure a new engine, using the default options.
///
/// Call this once for each new engine as the options include a generated unique link_prefix.
/// You can modify the configuration before creating the engine but you should not
/// modify the container_id or link_prefix.
PN_CPP_EXTERN connection_options make_options();
/// Set the default options to be used for connection engines.
/// The container will set the container_id and link_prefix when make_options is called.
PN_CPP_EXTERN void options(const connection_options&);
private:
const std::string id_;
id_generator id_gen_;
connection_options options_;
};
/// Create a connection engine that dispatches to handler.
PN_CPP_EXTERN connection_engine(handler&, const connection_options& = no_opts);
PN_CPP_EXTERN virtual ~connection_engine();
/// Return the number of bytes that the engine is currently ready to read.
PN_CPP_EXTERN size_t can_read() const;
/// Return the number of bytes that the engine is currently ready to write.
PN_CPP_EXTERN size_t can_write() const;
/// Combine these flags with | to indicate read, write, both or neither
enum io_flag {
READ = 1,
WRITE = 2
};
/// Read, write and dispatch events.
///
/// io_flags indicates whether to read, write, both or neither.
/// dispatches all events generated by reading or writing.
///
/// @throw proton::closed_error if closed() is true before calling process()
/// @throw proton::io_error if the engine is closed by an error.
/// @return true if process should be called again, i.e. !closed()
PN_CPP_EXTERN bool process(int io_flags=READ|WRITE);
/// Non-throwing version of process. Use closed() and error_str()
/// to check the status of the engine.
PN_CPP_EXTERN bool process_nothrow(int io_flags=READ|WRITE);
/// True if the engine is closed, meaning there are no further
/// events to process and close_io has been called. Call
/// error_str() to get an error description.
PN_CPP_EXTERN bool closed() const;
/// If the engine was closed by an error, return a pointer.
PN_CPP_EXTERN std::string error_str() const;
/// Get the AMQP connection associated with this connection_engine.
PN_CPP_EXTERN class connection connection() const;
/// Get the transport associated with this connection_engine.
PN_CPP_EXTERN class transport transport() const;
/// Disconnect the engine.
///
/// @internal
///
/// XXX calls io::close?
///
/// Calls io::close and dispatches final events to the
/// handler. Neither the handler nor the io will be used after
/// this call.
PN_CPP_EXTERN void disconnect();
protected:
/** Does a non-blocking read of up to max bytes into buf.
* Return the number read, 0 if no data could be read without blocking.
*
*@throw proton::closed_error if the input reaches EOF.
*@throw proton::io_error if there is a read error.
*/
virtual size_t io_read(char* buf, size_t max) = 0;
/** Does a non-blocking write of up to max bytes from buf.
* Return the number written, 0 if no data could be written without blocking.
*
*@throw proton::io_error if there is a write error.
*/
virtual size_t io_write(const char*, size_t) = 0;
/**
* Close the io, no more _io methods will be called after this is called.
*/
virtual void io_close() = 0;
PN_CPP_EXTERN static const connection_options no_opts;
private:
connection_engine(const connection_engine&);
connection_engine& operator=(const connection_engine&);
void dispatch();
void try_read();
void try_write();
class connection connection_;
connection_engine_context* ctx_;
};
}
#endif // CONNECTION_ENGINE_HPP