#ifndef PROTON_CONNECTION_DRIVER_H #define PROTON_CONNECTION_DRIVER_H 1 /* * 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. */ /** * @file * * @copybrief connection_driver * * @addtogroup connection_driver * @{ * * Associate a @ref connection and @ref transport with AMQP byte * streams from any source. * * - process AMQP-encoded bytes from some input byte stream * - generate ::pn_event_t events for your application to handle * - encode resulting AMQP output bytes for some output byte stream * * The `pn_connection_driver_*` functions provide a simplified API and * extra logic to use ::pn_connection_t and ::pn_transport_t as a * unit. You can also access them directly for features that do not * have `pn_connection_driver_*` functions. * * The driver buffers events and data. You should run it until * pn_connection_driver_finished() is true, to ensure all reading, * writing, and event handling (including `ERROR` and `FINAL` events) * is finished. * * ## Error handling * * The `pn_connection_driver_*` functions do not return an error * code. IO errors are set on the transport condition and are returned * as a `PN_TRANSPORT_ERROR`. The integration code can set errors * using pn_connection_driver_errorf(). * * ## IO patterns * * This API supports asynchronous, proactive, non-blocking and * reactive IO. An integration does not have to follow the * dispatch-read-write sequence above, but note that you should handle * all available events before calling * pn_connection_driver_read_buffer() and check that `size` is * non-zero before starting a blocking or asynchronous read call. A * `read` started while there are unprocessed `CLOSE` events in the * buffer may never complete. * * AMQP is a full-duplex, asynchronous protocol. The "read" and * "write" sides of an AMQP connection can close separately. * * ## Thread safety * * The @ref connection_driver types are not thread safe, but each * connection and its associated types form an independent * unit. Different connections can be processed concurrently by * different threads. */ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * The elements needed to drive AMQP IO and events. */ typedef struct pn_connection_driver_t { pn_connection_t *connection; pn_transport_t *transport; pn_collector_t *collector; } pn_connection_driver_t; /** * Set connection and transport to the provided values, or create a new * @ref pn_connection_t or @ref pn_transport_t if either is NULL. * The provided values belong to the connection driver and will be freed by * pn_connection_driver_destroy(). * * The transport is bound automatically after the PN_CONNECTION_INIT has been is * handled by the application. It can be bound earlier with * pn_connection_driver_bind(). * * The following functions must be called before the transport is * bound to have effect: pn_connection_set_username(), pn_connection_set_password(), * pn_transport_set_server(). * * @return PN_OUT_OF_MEMORY if any allocation fails. */ PN_EXTERN int pn_connection_driver_init(pn_connection_driver_t*, pn_connection_t*, pn_transport_t*); /** * Force binding of the transport. This happens automatically after * the PN_CONNECTION_INIT is processed. * * @return PN_STATE_ERR if the transport is already bound. */ PN_EXTERN int pn_connection_driver_bind(pn_connection_driver_t *d); /** * Unbind, release and free the connection and transport. Set all pointers to * NULL. Does not free the @ref pn_connection_driver_t struct itself. */ PN_EXTERN void pn_connection_driver_destroy(pn_connection_driver_t *); /** * Disassociate the driver's connection from its transport and collector and * sets d->connection = NULL. Returns the previous value, which must be freed * by the caller. * * The transport and collector are still owned by the driver and will be freed by * pn_connection_driver_destroy(). * * @note This has nothing to do with pn_connection_release() */ PN_EXTERN pn_connection_t *pn_connection_driver_release_connection(pn_connection_driver_t *d); /** * Get the read buffer. * * Copy data from your input byte source to buf.start, up to buf.size. * Call pn_connection_driver_read_done() when reading is complete. * * buf.size==0 means reading is not possible: no buffer space or the read side is closed. */ PN_EXTERN pn_rwbytes_t pn_connection_driver_read_buffer(pn_connection_driver_t *); /** * Process the first n bytes of data in pn_connection_driver_read_buffer() and * reclaim the buffer space. */ PN_EXTERN void pn_connection_driver_read_done(pn_connection_driver_t *, size_t n); /** * Close the read side. Call when the IO can no longer be read. */ PN_EXTERN void pn_connection_driver_read_close(pn_connection_driver_t *); /** * True if read side is closed. */ PN_EXTERN bool pn_connection_driver_read_closed(pn_connection_driver_t *); /** * Get the write buffer. * * Write data from buf.start to your IO destination, up to a max of buf.size. * Call pn_connection_driver_write_done() when writing is complete. * * buf.size==0 means there is nothing to write. */ PN_EXTERN pn_bytes_t pn_connection_driver_write_buffer(pn_connection_driver_t *); /** * Call when the first n bytes of pn_connection_driver_write_buffer() have been * written to IO. Reclaims the buffer space and reset the write buffer. */ PN_EXTERN void pn_connection_driver_write_done(pn_connection_driver_t *, size_t n); /** * Close the write side. Call when IO can no longer be written to. */ PN_EXTERN void pn_connection_driver_write_close(pn_connection_driver_t *); /** * True if write side is closed. */ PN_EXTERN bool pn_connection_driver_write_closed(pn_connection_driver_t *); /** * Close both sides. */ PN_EXTERN void pn_connection_driver_close(pn_connection_driver_t * c); /** * Get the next event to handle. * * @return pointer is valid till the next call of * pn_connection_driver_next(). NULL if there are no more events available now, * reading/writing may produce more. */ PN_EXTERN pn_event_t* pn_connection_driver_next_event(pn_connection_driver_t *); /** * True if pn_connection_driver_next_event() will return a non-NULL event. */ PN_EXTERN bool pn_connection_driver_has_event(pn_connection_driver_t *); /** * Return true if the the driver is closed for reading and writing and there are * no more events. * * Call pn_connection_driver_destroy() to free all related memory. */ PN_EXTERN bool pn_connection_driver_finished(pn_connection_driver_t *); /** * Set transport error. * * The name and formatted description are set on the transport condition, and * returned as a PN_TRANSPORT_ERROR event from pn_connection_driver_next_event(). * * You must call this *before* pn_connection_driver_read_close() or * pn_connection_driver_write_close() to ensure the error is processed. */ PN_EXTERN void pn_connection_driver_errorf(pn_connection_driver_t *d, const char *name, const char *fmt, ...); /** * Set transport error via a va_list, see pn_connection_driver_errorf() */ PN_EXTERN void pn_connection_driver_verrorf(pn_connection_driver_t *d, const char *name, const char *fmt, va_list); /** * The write side of the transport is closed, it will no longer produce bytes to write to * external IO. Synonym for PN_TRANSPORT_HEAD_CLOSED */ #define PN_TRANSPORT_WRITE_CLOSED PN_TRANSPORT_HEAD_CLOSED /** * The read side of the transport is closed, it will no longer read bytes from external * IO. Alias for PN_TRANSPORT_TAIL_CLOSED */ #define PN_TRANSPORT_READ_CLOSED PN_TRANSPORT_TAIL_CLOSED /** * **Deprecated** - Use pn_transport_log(). */ PN_EXTERN void pn_connection_driver_log(pn_connection_driver_t *d, const char *msg); /** * **Deprecated** - Use pn_transport_logf(). */ PN_EXTERN void pn_connection_driver_logf(pn_connection_driver_t *d, const char *fmt, ...); /** * **Deprecated** - Use pn_transport_vlogf(). */ PN_EXTERN void pn_connection_driver_vlogf(pn_connection_driver_t *d, const char *fmt, va_list ap); /** * Associate a pn_connection_t with its pn_connection_driver_t. * * **NOTE**: this is only for use by IO integration writers. If you are using the standard * pn_proactor_t you *must not* use this function. * * @return pointer to the pn_connection_driver_t* field in a pn_connection_t. * * Return type is pointer to a pointer so that the caller can (if desired) use * atomic operations when loading and storing the value. */ PN_EXTERN pn_connection_driver_t **pn_connection_driver_ptr(pn_connection_t *connection); /** * @} */ #ifdef __cplusplus } #endif #endif /* connection_driver.h */