diff options
author | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
---|---|---|
committer | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
commit | 420b91db29485df39fd6e724e782c449158811cb (patch) | |
tree | b471a94563af914d3ed3edd3e856d21cb1b69945 /indra/llmessage/lliosocket.h |
Print done when done.
Diffstat (limited to 'indra/llmessage/lliosocket.h')
-rw-r--r-- | indra/llmessage/lliosocket.h | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h new file mode 100644 index 0000000000..fd15949b69 --- /dev/null +++ b/indra/llmessage/lliosocket.h @@ -0,0 +1,355 @@ +/** + * @file lliosocket.h + * @author Phoenix + * @date 2005-07-31 + * @brief Declaration of files used for handling sockets and associated pipes + * + * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LL_LLIOSOCKET_H +#define LL_LLIOSOCKET_H + +/** + * The socket interface provided here is a simple wraper around apr + * sockets, with a pipe source and sink to read and write off of the + * socket. Every socket only performs non-blocking operations except + * the server socket which only performs blocking operations when an + * OS poll indicates it will not block. + */ + +#include "lliopipe.h" +#include "apr-1/apr_pools.h" +#include "apr-1/apr_network_io.h" +#include "llchainio.h" + +class LLHost; + +/** + * @class LLSocket + * @brief Implementation of a wrapper around a socket. + * + * An instance of this class represents a single socket over it's + * entire life - from uninitialized, to connected, to a listening + * socket depending on it's purpose. This class simplifies our access + * into the socket interface by only providing stream/tcp and + * datagram/udp sockets - the only types we are interested in, since + * those are the only properly supported by all of our platforms. + */ +class LLSocket +{ +public: + /** + * @brief Reference counted shared pointers to sockets. + */ + typedef boost::shared_ptr<LLSocket> ptr_t; + + /** + * @brief Type of socket to create. + */ + enum EType + { + STREAM_TCP, + DATAGRAM_UDP, + }; + + /** + * @brief Anonymous enumeration to help identify ports + */ + enum + { + PORT_INVALID = (U16)-1, + PORT_EPHEMERAL = 0, + }; + + /** + * @brief Create a socket. + * + * This is the call you would use if you intend to create a listen + * socket. If you intend the socket to be known to external + * clients without prior port notification, do not use + * PORT_EPHEMERAL. + * @param pool The apr pool to use. A child pool will be created + * and associated with the socket. + * @param type The type of socket to create + * @param port The port for the socket + * @return A valid socket shared pointer if the call worked. + */ + static ptr_t create( + apr_pool_t* pool, + EType type, + U16 port = PORT_EPHEMERAL); + + /** + * @brief Create a LLSocket when you already have an apr socket. + * + * This method assumes an ephemeral port. This is typically used + * by calls which spawn a socket such as a call to + * <code>accept()</code> as in the server socket. This call should + * not fail if you have a valid apr socket. + * Because of the nature of how accept() works, you are expected + * to create a new pool for the socket, use that pool for the + * accept, and pass it in here where it will be bound with the + * socket and destroyed at the same time. + * @param socket The apr socket to use + * @param pool The pool used to create the socket. *NOTE: The pool + * passed in will be DESTROYED. + * @return A valid socket shared pointer if the call worked. + */ + static ptr_t create(apr_socket_t* socket, apr_pool_t* pool); + + /** + * @brief Perform a blocking connect to a host. Do not use in production. + * + * @param host The host to connect this socket to. + * @return Returns true if the connect was successful. + */ + bool blockingConnect(const LLHost& host); + + /** + * @brief Get the type of socket + */ + //EType getType() const { return mType; } + + /** + * @brief Get the port. + * + * This will return PORT_EPHEMERAL if bind was never called. + * @return Returns the port associated with this socket. + */ + U16 getPort() const { return mPort; } + + /** + * @brief Get the apr socket implementation. + * + * @return Returns the raw apr socket. + */ + apr_socket_t* getSocket() const { return mSocket; } + +protected: + /** + * @brief Protected constructor since should only make sockets + * with one of the two <code>create()</code> calls. + */ + LLSocket(apr_socket_t* socket, apr_pool_t* pool); + + /** + * @brief Set default socket options. + */ + void setOptions(); + +public: + /** + * @brief Do not call this directly. + */ + ~LLSocket(); + +protected: + // The apr socket. + apr_socket_t* mSocket; + + // our memory pool + apr_pool_t* mPool; + + // The port if we know it. + U16 mPort; + + //EType mType; +}; + +/** + * @class LLIOSocketReader + * @brief An LLIOPipe implementation which reads from a socket. + * @see LLIOPipe + * + * An instance of a socket reader wraps around an LLSocket and + * performs non-blocking reads and passes it to the next pipe in the + * chain. + */ +class LLIOSocketReader : public LLIOPipe +{ +public: + LLIOSocketReader(LLSocket::ptr_t socket); + ~LLIOSocketReader(); + +protected: + /* @name LLIOPipe virtual implementations + */ + //@{ + /** + * @brief Process the data coming in the socket. + * + * Since the socket and next pipe must exist for process to make + * any sense, this method will return STATUS_PRECONDITION_NOT_MET + * unless if they are not known. + * If a STATUS_STOP returned by the next link in the chain, this + * reader will turn of the socket polling. + * @param buffer Pointer to a buffer which needs processing. Probably NULL. + * @param bytes Number of bytes to in buffer to process. Probably 0. + * @param eos True if this function is the last. Almost always false. + * @param read Number of bytes actually processed. + * @param pump The pump which is calling process. May be NULL. + * @param context A data structure to pass structured data + * @return STATUS_OK unless the preconditions are not met. + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} + +protected: + LLSocket::ptr_t mSource; + std::vector<U8> mBuffer; + bool mInitialized; +}; + +/** + * @class LLIOSocketWriter + * @brief An LLIOPipe implementation which writes to a socket + * @see LLIOPipe + * + * An instance of a socket writer wraps around an LLSocket and + * performs non-blocking writes of the data passed in. + */ +class LLIOSocketWriter : public LLIOPipe +{ +public: + LLIOSocketWriter(LLSocket::ptr_t socket); + ~LLIOSocketWriter(); + +protected: + /* @name LLIOPipe virtual implementations + */ + //@{ + /** + * @brief Write the data in buffer to the socket. + * + * Since the socket pipe must exist for process to make any sense, + * this method will return STATUS_PRECONDITION_NOT_MET if it is + * not known. + * @param buffer Pointer to a buffer which needs processing. + * @param bytes Number of bytes to in buffer to process. + * @param eos True if this function is the last. + * @param read Number of bytes actually processed. + * @param pump The pump which is calling process. May be NULL. + * @param context A data structure to pass structured data + * @return A return code for the write. + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} + +protected: + LLSocket::ptr_t mDestination; + U8* mLastWritten; + bool mInitialized; +}; + +/** + * @class LLIOServerSocket + * @brief An IOPipe implementation which listens and spawns connected + * sockets. + * @see LLIOPipe, LLChainIOFactory + * + * Each server socket instance coordinates with a pump to ensure it + * only processes waiting connections. It uses the provided socket, + * and assumes it is correctly initialized. When the connection is + * established, the server will call the chain factory to build a + * chain, and attach a socket reader and the front and a socket writer + * at the end. It is up to the chain factory to create something which + * correctly handles the established connection using the reader as a + * source, and the writer as the final sink. + * The newly added chain timeout is in DEFAULT_CHAIN_EXPIRY_SECS unless + * adjusted with a call to setResponseTimeout(). + */ +class LLIOServerSocket : public LLIOPipe +{ +public: + typedef LLSocket::ptr_t socket_t; + typedef boost::shared_ptr<LLChainIOFactory> factory_t; + LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor); + virtual ~LLIOServerSocket(); + + /** + * @brief Set the timeout for the generated chains. + * + * This value is passed directly to the LLPumpIO::addChain() + * method. The default on construction is set to + * DEFAULT_CHAIN_EXPIRY_SECS which is a reasonable value for most + * applications based on this library. Avoid passing in + * NEVER_CHAIN_EXPIRY_SECS unless you have another method of + * harvesting chains. + * @param timeout_secs The seconds before timeout for the response chain. + */ + void setResponseTimeout(F32 timeout_secs); + + /* @name LLIOPipe virtual implementations + */ + //@{ +protected: + /** + * @brief Process the data in buffer + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} + +protected: + apr_pool_t* mPool; + socket_t mListenSocket; + factory_t mReactor; + bool mInitialized; + F32 mResponseTimeout; +}; + +#if 0 +/** + * @class LLIODataSocket + * @brief BRIEF_DESC + * + * THOROUGH_DESCRIPTION + */ +class LLIODataSocket : public LLIOSocket +{ +public: + /** + * @brief Construct a datagram socket. + * + * If you pass in LLIOSocket::PORT_EPHEMERAL as the suggested + * port, The socket will not be in a 'listen' mode, but can still + * read data sent back to it's port. When suggested_port is not + * ephemeral or invalid and bind fails, the port discovery + * algorithm will search through a limited set of ports to + * try to find an open port. If that process fails, getPort() will + * return LLIOSocket::PORT_INVALID + * @param suggested_port The port you would like to bind. Use + * LLIOSocket::PORT_EPHEMERAL for an unspecified port. + * @param start_discovery_port The start range for + * @param pool The pool to use for allocation. + */ + LLIODataSocket( + U16 suggested_port, + U16 start_discovery_port, + apr_pool_t* pool); + virtual ~LLIODataSocket(); + +protected: + +private: + apr_socket_t* mSocket; +}; +#endif + +#endif // LL_LLIOSOCKET_H |