PageRenderTime 28ms CodeModel.GetById 15ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/lliosocket.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 380 lines | 111 code | 35 blank | 234 comment | 0 complexity | 56b56b8e9187540d3f8031034e116d64 MD5 | raw file
  1/** 
  2 * @file lliosocket.h
  3 * @author Phoenix
  4 * @date 2005-07-31
  5 * @brief Declaration of files used for handling sockets and associated pipes
  6 *
  7 * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28
 29#ifndef LL_LLIOSOCKET_H
 30#define LL_LLIOSOCKET_H
 31
 32/** 
 33 * The socket interface provided here is a simple wraper around apr
 34 * sockets, with a pipe source and sink to read and write off of the
 35 * socket. Every socket only performs non-blocking operations except
 36 * the server socket which only performs blocking operations when an
 37 * OS poll indicates it will not block.
 38 */
 39
 40#include "lliopipe.h"
 41#include "apr_pools.h"
 42#include "apr_network_io.h"
 43#include "llchainio.h"
 44
 45class LLHost;
 46
 47/** 
 48 * @class LLSocket
 49 * @brief Implementation of a wrapper around a socket.
 50 *
 51 * An instance of this class represents a single socket over it's
 52 * entire life - from uninitialized, to connected, to a listening
 53 * socket depending on it's purpose. This class simplifies our access
 54 * into the socket interface by only providing stream/tcp and
 55 * datagram/udp sockets - the only types we are interested in, since
 56 * those are the only properly supported by all of our platforms.
 57 */
 58class LLSocket
 59{
 60public:
 61	/** 
 62	 * @brief Reference counted shared pointers to sockets.
 63	 */
 64	typedef boost::shared_ptr<LLSocket> ptr_t;
 65
 66	/** 
 67	 * @brief Type of socket to create.
 68	 */
 69	enum EType
 70	{
 71		STREAM_TCP,
 72		DATAGRAM_UDP,
 73	};
 74
 75	/** 
 76	 * @brief Anonymous enumeration to help identify ports
 77	 */
 78	enum
 79	{
 80		PORT_INVALID = (U16)-1,
 81		PORT_EPHEMERAL = 0,
 82	};
 83
 84	/** 
 85	 * @brief Create a socket.
 86	 *
 87	 * This is the call you would use if you intend to create a listen
 88	 * socket. If you intend the socket to be known to external
 89	 * clients without prior port notification, do not use
 90	 * PORT_EPHEMERAL.
 91	 * @param pool The apr pool to use. A child pool will be created
 92	 * and associated with the socket.
 93	 * @param type The type of socket to create
 94	 * @param port The port for the socket
 95	 * @return A valid socket shared pointer if the call worked.
 96	 */
 97	static ptr_t create(
 98		apr_pool_t* pool,
 99		EType type,
100		U16 port = PORT_EPHEMERAL);
101
102	/** 
103	 * @brief Create a LLSocket when you already have an apr socket.
104	 *
105	 * This method assumes an ephemeral port. This is typically used
106	 * by calls which spawn a socket such as a call to
107	 * <code>accept()</code> as in the server socket. This call should
108	 * not fail if you have a valid apr socket.
109	 * Because of the nature of how accept() works, you are expected
110	 * to create a new pool for the socket, use that pool for the
111	 * accept, and pass it in here where it will be bound with the
112	 * socket and destroyed at the same time.
113	 * @param socket The apr socket to use 
114	 * @param pool The pool used to create the socket. *NOTE: The pool
115	 * passed in will be DESTROYED.
116	 * @return A valid socket shared pointer if the call worked.
117	 */
118	static ptr_t create(apr_socket_t* socket, apr_pool_t* pool);
119
120	/** 
121	 * @brief Perform a blocking connect to a host. Do not use in production.
122	 *
123	 * @param host The host to connect this socket to.
124	 * @return Returns true if the connect was successful.
125	 */
126	bool blockingConnect(const LLHost& host);
127
128	/** 
129	 * @brief Get the type of socket
130	 */
131	//EType getType() const { return mType; }
132
133	/** 
134	 * @brief Get the port.
135	 *
136	 * This will return PORT_EPHEMERAL if bind was never called.
137	 * @return Returns the port associated with this socket.
138	 */
139	U16 getPort() const { return mPort; }
140
141	/** 
142	 * @brief Get the apr socket implementation.
143	 *
144	 * @return Returns the raw apr socket.
145	 */
146	apr_socket_t* getSocket() const { return mSocket; }
147
148	/** 
149	 * @brief Set default socket options, with SO_NONBLOCK = 0 and a timeout in us.
150	 * @param timeout Number of microseconds to wait on this socket. Any
151	 * negative number means block-forever. TIMEOUT OF 0 IS NON-PORTABLE.
152	 */
153	void setBlocking(S32 timeout);
154
155	/**
156	 * @brief Set default socket options, with SO_NONBLOCK = 1 and timeout = 0.
157	 */
158	void setNonBlocking();
159
160protected:
161	/**
162	 * @brief Protected constructor since should only make sockets
163	 * with one of the two <code>create()</code> calls.
164	 */
165	LLSocket(apr_socket_t* socket, apr_pool_t* pool);
166
167public:
168	/** 
169	 * @brief Do not call this directly.
170	 */
171	~LLSocket();
172
173protected:
174	// The apr socket.
175	apr_socket_t* mSocket;
176
177	// our memory pool
178	apr_pool_t* mPool;
179
180	// The port if we know it.
181	U16 mPort;
182
183	//EType mType;
184};
185
186/** 
187 * @class LLIOSocketReader
188 * @brief An LLIOPipe implementation which reads from a socket.
189 * @see LLIOPipe
190 *
191 * An instance of a socket reader wraps around an LLSocket and
192 * performs non-blocking reads and passes it to the next pipe in the
193 * chain.
194 */
195class LLIOSocketReader : public LLIOPipe
196{
197public:
198	LLIOSocketReader(LLSocket::ptr_t socket);
199	~LLIOSocketReader();
200
201protected:
202	/* @name LLIOPipe virtual implementations
203	 */
204	//@{
205	/** 
206	 * @brief Process the data coming in the socket.
207	 *
208	 * Since the socket and next pipe must exist for process to make
209	 * any sense, this method will return STATUS_PRECONDITION_NOT_MET
210	 * unless if they are not known.
211	 * If a STATUS_STOP returned by the next link in the chain, this
212	 * reader will turn of the socket polling.
213	 * @param buffer Pointer to a buffer which needs processing. Probably NULL.
214	 * @param bytes Number of bytes to in buffer to process. Probably 0.
215	 * @param eos True if this function is the last. Almost always false.
216	 * @param read Number of bytes actually processed.
217	 * @param pump The pump which is calling process. May be NULL.
218	 * @param context A data structure to pass structured data
219	 * @return STATUS_OK unless the preconditions are not met.
220	 */
221	virtual EStatus process_impl(
222		const LLChannelDescriptors& channels,
223		buffer_ptr_t& buffer,
224		bool& eos,
225		LLSD& context,
226		LLPumpIO* pump);
227	//@}
228
229protected:
230	LLSocket::ptr_t mSource;
231	std::vector<U8> mBuffer;
232	bool mInitialized;
233};
234
235/** 
236 * @class LLIOSocketWriter
237 * @brief An LLIOPipe implementation which writes to a socket
238 * @see LLIOPipe
239 *
240 * An instance of a socket writer wraps around an LLSocket and
241 * performs non-blocking writes of the data passed in.
242 */
243class LLIOSocketWriter : public LLIOPipe
244{
245public:
246	LLIOSocketWriter(LLSocket::ptr_t socket);
247	~LLIOSocketWriter();
248
249protected:
250	/* @name LLIOPipe virtual implementations
251	 */
252	//@{
253	/** 
254	 * @brief Write the data in buffer to the socket.
255	 *
256	 * Since the socket pipe must exist for process to make any sense,
257	 * this method will return STATUS_PRECONDITION_NOT_MET if it is
258	 * not known.
259	 * @param buffer Pointer to a buffer which needs processing.
260	 * @param bytes Number of bytes to in buffer to process.
261	 * @param eos True if this function is the last.
262	 * @param read Number of bytes actually processed.
263	 * @param pump The pump which is calling process. May be NULL.
264	 * @param context A data structure to pass structured data
265	 * @return A return code for the write.
266	 */
267	virtual EStatus process_impl(
268		const LLChannelDescriptors& channels,
269		buffer_ptr_t& buffer,
270		bool& eos,
271		LLSD& context,
272		LLPumpIO* pump);
273	//@}
274
275protected:
276	LLSocket::ptr_t mDestination;
277	U8* mLastWritten;
278	bool mInitialized;
279};
280
281/** 
282 * @class LLIOServerSocket
283 * @brief An IOPipe implementation which listens and spawns connected
284 * sockets.
285 * @see LLIOPipe, LLChainIOFactory
286 *
287 * Each server socket instance coordinates with a pump to ensure it
288 * only processes waiting connections. It uses the provided socket,
289 * and assumes it is correctly initialized. When the connection is
290 * established, the server will call the chain factory to build a
291 * chain, and attach a socket reader and the front and a socket writer
292 * at the end. It is up to the chain factory to create something which
293 * correctly handles the established connection using the reader as a
294 * source, and the writer as the final sink.
295 * The newly added chain timeout is in DEFAULT_CHAIN_EXPIRY_SECS unless
296 * adjusted with a call to setResponseTimeout().
297 */
298class LLIOServerSocket : public LLIOPipe
299{
300public:
301	typedef LLSocket::ptr_t socket_t;
302	typedef boost::shared_ptr<LLChainIOFactory> factory_t;
303	LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor);
304	virtual ~LLIOServerSocket();
305
306	/** 
307	 * @brief Set the timeout for the generated chains.
308	 *
309	 * This value is passed directly to the LLPumpIO::addChain()
310	 * method. The default on construction is set to
311	 * DEFAULT_CHAIN_EXPIRY_SECS which is a reasonable value for most
312	 * applications based on this library. Avoid passing in
313	 * NEVER_CHAIN_EXPIRY_SECS unless you have another method of
314	 * harvesting chains.
315	 * @param timeout_secs The seconds before timeout for the response chain. 
316	 */
317	void setResponseTimeout(F32 timeout_secs);
318
319	/* @name LLIOPipe virtual implementations
320	 */
321	//@{
322protected:
323	/** 
324	 * @brief Process the data in buffer
325	 */
326	virtual EStatus process_impl(
327		const LLChannelDescriptors& channels,
328		buffer_ptr_t& buffer,
329		bool& eos,
330		LLSD& context,
331		LLPumpIO* pump);
332	//@}
333
334protected:
335	apr_pool_t* mPool;
336	socket_t mListenSocket;
337	factory_t mReactor;
338	bool mInitialized;
339	F32 mResponseTimeout;
340};
341
342#if 0
343/** 
344 * @class LLIODataSocket
345 * @brief BRIEF_DESC
346 *
347 * THOROUGH_DESCRIPTION
348 */
349class LLIODataSocket : public LLIOSocket
350{
351public:
352	/**
353	 * @brief Construct a datagram socket.
354	 *
355	 * If you pass in LLIOSocket::PORT_EPHEMERAL as the suggested
356	 * port, The socket will not be in a 'listen' mode, but can still
357	 * read data sent back to it's port. When suggested_port is not
358	 * ephemeral or invalid and bind fails, the port discovery
359	 * algorithm will search through a limited set of ports to
360	 * try to find an open port. If that process fails, getPort() will
361	 * return LLIOSocket::PORT_INVALID
362	 * @param suggested_port The port you would like to bind. Use
363	 * LLIOSocket::PORT_EPHEMERAL for an unspecified port.
364	 * @param start_discovery_port The start range for
365	 * @param pool The pool to use for allocation.
366	 */
367	LLIODataSocket(
368		U16 suggested_port,
369		U16 start_discovery_port,
370		apr_pool_t* pool);
371	virtual ~LLIODataSocket();
372
373protected:
374
375private:
376	apr_socket_t* mSocket;
377};
378#endif
379
380#endif // LL_LLIOSOCKET_H