/* * 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. */ #ifndef THRIFT_ASYNC_TASYNCTRANSPORT_H_ #define THRIFT_ASYNC_TASYNCTRANSPORT_H_ 1 #include "thrift/lib/cpp/thrift_config.h" #include #include #include namespace folly { class IOBuf; } namespace apache { namespace thrift { namespace transport { class TSocketAddress; class TTransportException; } namespace async { class TEventBase; /** * TAsyncTransport defines an asynchronous API for streaming I/O. * * This class provides an API to for asynchronously waiting for data * on a streaming transport, and for asynchronously sending data. * * The APIs for reading and writing are intentionally asymmetric. Waiting for * data to read is a persistent API: a callback is installed, and is notified * whenever new data is available. It continues to be notified of new events * until it is uninstalled. * * TAsyncTransport does not provide read timeout functionality, because it * typically cannot determine when the timeout should be active. Generally, a * timeout should only be enabled when processing is blocked waiting on data * from the remote endpoint. For server-side applications, the timeout should * not be active if the server is currently processing one or more outstanding * requests on this transport. For client-side applications, the timeout * should not be active if there are no requests pending on the transport. * Additionally, if a client has multiple pending requests, it will ususally * want a separate timeout for each request, rather than a single read timeout. * * The write API is fairly intuitive: a user can request to send a block of * data, and a callback will be informed once the entire block has been * transferred to the kernel, or on error. TAsyncTransport does provide a send * timeout, since most callers want to give up if the remote end stops * responding and no further progress can be made sending the data. */ class TAsyncTransport { public: class ReadCallback { public: virtual ~ReadCallback() {} /** * When data becomes available, getReadBuffer() will be invoked to get the * buffer into which data should be read. * * This method allows the ReadCallback to delay buffer allocation until * data becomes available. This allows applications to manage large * numbers of idle connections, without having to maintain a separate read * buffer for each idle connection. * * It is possible that in some cases, getReadBuffer() may be called * multiple times before readDataAvailable() is invoked. In this case, the * data will be written to the buffer returned from the most recent call to * readDataAvailable(). If the previous calls to readDataAvailable() * returned different buffers, the ReadCallback is responsible for ensuring * that they are not leaked. * * If getReadBuffer() throws an exception, returns a NULL buffer, or * returns a 0 length, the ReadCallback will be uninstalled and its * readError() method will be invoked. * * getReadBuffer() is not allowed to change the transport state before it * returns. (For example, it should never uninstall the read callback, or * set a different read callback.) * * @param bufReturn getReadBuffer() should update *bufReturn to contain the * address of the read buffer. This parameter will never * be NULL. * @param lenReturn getReadBuffer() should update *lenReturn to contain the * maximum number of bytes that may be written to the read * buffer. This parameter will never be NULL. */ virtual void getReadBuffer(void** bufReturn, size_t* lenReturn) = 0; /** * readDataAvailable() will be invoked when data has been successfully read * into the buffer returned by the last call to getReadBuffer(). * * The read callback remains installed after readDataAvailable() returns. * It must be explicitly uninstalled to stop receiving read events. * getReadBuffer() will be called at least once before each call to * readDataAvailable(). getReadBuffer() will also be called before any * call to readEOF(). * * @param len The number of bytes placed in the buffer. */ virtual void readDataAvailable(size_t len) THRIFT_NOEXCEPT = 0; /** * readEOF() will be invoked when the transport is closed. * * The read callback will be automatically uninstalled immediately before * readEOF() is invoked. */ virtual void readEOF() THRIFT_NOEXCEPT = 0; /** * readError() will be invoked if an error occurs reading from the * transport. * * The read callback will be automatically uninstalled immediately before * readError() is invoked. * * @param ex An exception describing the error that occurred. */ virtual void readError(const transport::TTransportException& ex) THRIFT_NOEXCEPT = 0; }; class WriteCallback { public: virtual ~WriteCallback() {} /** * writeSuccess() will be invoked when all of the data has been * successfully written. * * Note that this mainly signals that the buffer containing the data to * write is no longer needed and may be freed or re-used. It does not * guarantee that the data has been fully transmitted to the remote * endpoint. For example, on socket-based transports, writeSuccess() only * indicates that the data has been given to the kernel for eventual * transmission. */ virtual void writeSuccess() THRIFT_NOEXCEPT = 0; /** * writeError() will be invoked if an error occurs writing the data. * * @param bytesWritten The number of bytes that were successfull * @param ex An exception describing the error that occurred. */ virtual void writeError(size_t bytesWritten, const transport::TTransportException& ex) THRIFT_NOEXCEPT = 0; }; virtual ~TAsyncTransport() {} /** * Set the read callback. * * See the documentation for ReadCallback above for a description of how the * callback will be invoked. Note that the callback remains installed until * it is explicitly uninstalled, or until an error occurs. * * If a ReadCallback is already installed, it is replaced with the new * callback. * * Note that setReadCallback() may invoke the ReadCallback immediately, * before returning. * * @param callback The callback to invoke when data is available. * This parameter may be NULL to uninstall the current * read callback. */ virtual void setReadCallback(ReadCallback* callback) = 0; /** * Get the currently installed read callback. * * @return Returns a pointer to the installed ReadCallback, or NULL if no * ReadCallback is installed. */ virtual ReadCallback* getReadCallback() const = 0; /** * Write data to the transport. * * write() will always return immediately. The WriteCallback will later be * invoked from the main TEventBase loop when the write has completed. * * Additional write attempts may be started before the first write completes. * The subsequent write requests will be queued, and processed in the order * in which they were called. * * @param callback The callback to invoke when the data has been written. * The callback may not be NULL. * @param buf The buffer containing the data to write. The caller is * responsible for ensuring that this buffer remains valid * until the callback is invoked. This parameter may not * be NULL. * @param bytes The number of bytes to write. */ virtual void write(WriteCallback* callback, const void* buf, size_t bytes) = 0; /** * Write non-contiguous data to the transport. * * writev() will always return immediately. The WriteCallback will later be * invoked from the main TEventBase loop when the write has completed. * * Additional write attempts may be started before the first write completes. * The subsequent write requests will be queued, and processed in the order * in which they were called. * * @param callback The callback to invoke when the data has been written. * The callback may not be NULL. * @param vec A pointer to an array of iovec objects. The caller is * responsible for ensuring that the buffers remain valid * until the callback is invoked. This parameter may not * be NULL. * @param count The number of iovec objects in the vec array. */ virtual void writev(WriteCallback* callback, const iovec* vec, size_t count) = 0; /** * Write a chain of IOBufs to the transport. * * writeChain() will always return immediately. The WriteCallback will * later be invoked from the main TEventBase loop when the write has * completed. * * Additional write attempts may be started before the first write completes. * The subsequent write requests will be queued, and processed in the order * in which they were called. * * @param callback The callback to invoke when the data has been written. * The callback may not be NULL. * @param iob The head of an IOBuf chain. The TAsyncTransport * will take ownership of this chain and delete it * after writing. * @param cork Whether to delay the write until the next non-corked * write operation. (Note: may not be supported in all * subclasses or on all platforms.) */ virtual void writeChain(WriteCallback* callback, std::unique_ptr&& iob, bool cork = false) = 0; /** * Close the transport. * * This gracefully closes the transport, waiting for all pending write * requests to complete before actually closing the underlying transport. * * If a read callback is set, readEOF() will be called immediately. If there * are outstanding write requests, the close will be delayed until all * remaining writes have completed. No new writes may be started after * close() has been called. */ virtual void close() = 0; /** * Close the transport immediately. * * This closes the transport immediately, dropping any outstanding data * waiting to be written. * * If a read callback is set, readEOF() will be called immediately. * If there are outstanding write requests, these requests will be aborted * and writeError() will be invoked immediately on all outstanding write * callbacks. */ virtual void closeNow() = 0; /** * Reset the transport immediately. * * This closes the transport immediately, sending a reset to the remote peer * if possible to indicate abnormal shutdown. * * Note that not all subclasses implement this reset functionality: some * subclasses may treat reset() the same as closeNow(). Subclasses that use * TCP transports should terminate the connection with a TCP reset. */ virtual void closeWithReset() { closeNow(); } /** * Perform a half-shutdown of the write side of the transport. * * The caller should not make any more calls to write() or writev() after * shutdownWrite() is called. Any future write attempts will fail * immediately. * * Not all transport types support half-shutdown. If the underlying * transport does not support half-shutdown, it will fully shutdown both the * read and write sides of the transport. (Fully shutting down the socket is * better than doing nothing at all, since the caller may rely on the * shutdownWrite() call to notify the other end of the connection that no * more data can be read.) * * If there is pending data still waiting to be written on the transport, * the actual shutdown will be delayed until the pending data has been * written. * * Note: There is no corresponding shutdownRead() equivalent. Simply * uninstall the read callback if you wish to stop reading. (On TCP sockets * at least, shutting down the read side of the socket is a no-op anyway.) */ virtual void shutdownWrite() = 0; /** * Perform a half-shutdown of the write side of the transport. * * shutdownWriteNow() is identical to shutdownWrite(), except that it * immediately performs the shutdown, rather than waiting for pending writes * to complete. Any pending write requests will be immediately failed when * shutdownWriteNow() is called. */ virtual void shutdownWriteNow() = 0; /** * Determine if transport is open and ready to read or write. * * Note that this function returns false on EOF; you must also call error() * to distinguish between an EOF and an error. * * @return true iff the transport is open and ready, false otherwise. */ virtual bool good() const = 0; /** * Determine if the transport is readable or not. * * @return true iff the transport is readable, false otherwise. */ virtual bool readable() const = 0; /** * Determine if transport is connected to the endpoint * * @return false iff the transport is connected, otherwise true */ virtual bool connecting() const = 0; /** * Determine if an error has occurred with this transport. * * @return true iff an error has occurred (not EOF). */ virtual bool error() const = 0; /** * Attach the transport to a TEventBase. * * This may only be called if the transport is not currently attached to a * TEventBase (by an earlier call to detachEventBase()). * * This method must be invoked in the TEventBase's thread. */ virtual void attachEventBase(TEventBase* eventBase) = 0; /** * Detach the transport from its TEventBase. * * This may only be called when the transport is idle and has no reads or * writes pending. Once detached, the transport may not be used again until * it is re-attached to a TEventBase by calling attachEventBase(). * * This method must be called from the current TEventBase's thread. */ virtual void detachEventBase() = 0; /** * Get the TEventBase used by this transport. * * Returns NULL if this transport is not currently attached to a TEventBase. */ virtual TEventBase* getEventBase() const = 0; /** * Set the send timeout. * * If write requests do not make any progress for more than the specified * number of milliseconds, fail all pending writes and close the transport. * * If write requests are currently pending when setSendTimeout() is called, * the timeout interval is immediately restarted using the new value. * * @param milliseconds The timeout duration, in milliseconds. If 0, no * timeout will be used. */ virtual void setSendTimeout(uint32_t milliseconds) = 0; /** * Get the send timeout. * * @return Returns the current send timeout, in milliseconds. A return value * of 0 indicates that no timeout is set. */ virtual uint32_t getSendTimeout() const = 0; /** * Get the address of the local endpoint of this transport. * * This function may throw TTransportException on error. * * @param address The local address will be stored in the specified * TSocketAddress. */ virtual void getLocalAddress(transport::TSocketAddress* address) const = 0; /** * Get the address of the remote endpoint to which this transport is * connected. * * This function may throw TTransportException on error. * * @param address The remote endpoint's address will be stored in the * specified TSocketAddress. */ virtual void getPeerAddress(transport::TSocketAddress* address) const = 0; }; }}} // apache::thrift::async #endif // #ifndef THRIFT_ASYNC_TASYNCTRANSPORT_H_