1 /**
2  * @file Csocket.h
3  * @author Jim Hull <csocket@jimloco.com>
4  *
5  *    Copyright (c) 1999-2012 Jim Hull <csocket@jimloco.com>
6  *    All rights reserved
7  *
8  * Redistribution and use in source and binary forms, with or without modification,
9  * are permitted provided that the following conditions are met:
10  * Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  * Redistributions in binary form must reproduce the above copyright notice, this list
13  * of conditions and the following disclaimer in the documentation and/or other materials
14  * provided with the distribution.
15  * Redistributions in any form must be accompanied by information on how to obtain
16  * complete source code for this software and any accompanying software that uses this software.
17  * The source code must either be included in the distribution or be available for no more than
18  * the cost of distribution plus a nominal fee, and must be freely redistributable
19  * under reasonable conditions. For an executable file, complete source code means the source
20  * code for all modules it contains. It does not include source code for modules or files
21  * that typically accompany the major components of the operating system on which the executable file runs.
22  *
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
25  * OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OF THIS SOFTWARE BE LIABLE FOR ANY DIRECT,
26  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
29  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * NOTES ...
35  * - You should always compile with -Woverloaded-virtual to detect callbacks that may have been redefined since your last update
36  * - If you want to use gethostbyname instead of getaddrinfo, the use -DUSE_GETHOSTBYNAME when compiling
37  * - To compile with win32 need to link to winsock2, using gcc its -lws2_32
38  * - Code is formated with 'astyle --style=ansi -t4 --unpad-paren --pad-paren-in --keep-one-line-blocks'
39  */
40 #ifndef _HAS_CSOCKET_
41 #define _HAS_CSOCKET_
42 
43 #include "defines.h" // require this as a general rule, most projects have a defines.h or the like
44 
45 #include <stdio.h>
46 #include <fcntl.h>
47 
48 #ifndef _WIN32
49 
50 #include <unistd.h>
51 #include <sys/time.h>
52 #include <sys/file.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
55 #include <sys/socket.h>
56 #include <sys/ioctl.h>
57 #include <netdb.h>
58 #include <sys/select.h>
59 
60 #else
61 
62 #include <io.h>
63 #include <winsock2.h>
64 #include <ws2tcpip.h>
65 #include <time.h>
66 #include <sys/timeb.h>
67 
68 #ifdef _MSC_VER
69 #define strcasecmp _stricmp
70 #define suseconds_t long
71 #endif
72 
73 #ifndef ECONNREFUSED
74 // these aliases might or might not be defined in errno.h
75 // already, depending on the WinSDK version.
76 #define ECONNREFUSED WSAECONNREFUSED
77 #define EINPROGRESS WSAEINPROGRESS
78 #define ETIMEDOUT WSAETIMEDOUT
79 #define EADDRNOTAVAIL WSAEADDRNOTAVAIL
80 #define ECONNABORTED WSAECONNABORTED
81 #define ENETUNREACH WSAENETUNREACH
82 #endif /* ECONNREFUSED */
83 
84 #endif /* _WIN32 */
85 
86 #ifdef HAVE_C_ARES
87 #include <ares.h>
88 #endif /* HAVE_C_ARES */
89 
90 #ifdef HAVE_ICU
91 # include <unicode/ucnv.h>
92 #endif
93 
94 #include <stdlib.h>
95 #include <errno.h>
96 #include <string.h>
97 #include <ctype.h>
98 #include <assert.h>
99 
100 #ifdef HAVE_LIBSSL
101 #include <openssl/ssl.h>
102 #include <openssl/err.h>
103 #include <openssl/rand.h>
104 #endif /* HAVE_LIBSSL */
105 
106 #ifdef __sun
107 #include <strings.h>
108 #include <fcntl.h>
109 #endif /* __sun */
110 
111 #include <vector>
112 #include <list>
113 #include <iostream>
114 #include <sstream>
115 #include <string>
116 #include <set>
117 #include <map>
118 
119 #ifndef CS_STRING
120 #	ifdef _HAS_CSTRING_
121 #		define CS_STRING Cstring
122 #	else
123 #		define CS_STRING std::string
124 #	endif	/* _HAS_CSTRING_ */
125 #endif /* CS_STRING */
126 
127 #ifndef CS_DEBUG
128 #ifdef __DEBUG__
129 #	define CS_DEBUG( f ) std::cerr << __FILE__ << ":" << __LINE__ << " " << f << std::endl
130 #else
131 #	define CS_DEBUG(f)	(void)0
132 #endif /* __DEBUG__ */
133 #endif /* CS_DEBUG */
134 
135 #ifndef CS_EXPORT
136 #define CS_EXPORT
137 #endif /* CS_EXPORT */
138 
139 #ifndef PERROR
140 #ifdef __DEBUG__
141 #	define PERROR( f ) __Perror( f, __FILE__, __LINE__ )
142 #else
143 #	define PERROR( f )	(void)0
144 #endif /* __DEBUG__ */
145 #endif /* PERROR */
146 
147 #ifdef _WIN32
148 typedef SOCKET cs_sock_t;
149 #ifdef _WIN64
150 typedef signed __int64 cs_ssize_t;
151 #else
152 typedef signed int cs_ssize_t;
153 #endif  /* _WIN64 */
154 #define CS_INVALID_SOCK	INVALID_SOCKET
155 #else
156 typedef int cs_sock_t;
157 typedef ssize_t cs_ssize_t;
158 #define CS_INVALID_SOCK	-1
159 #endif /* _WIN32 */
160 
161 /* Assume that everything but windows has Unix sockets */
162 #ifndef _WIN32
163 #define HAVE_UNIX_SOCKET
164 #endif
165 
166 #ifdef CSOCK_USE_POLL
167 #include <poll.h>
168 #endif /* CSOCK_USE_POLL */
169 
170 #ifdef HAVE_UNIX_SOCKET
171 #include <sys/un.h>
172 #endif
173 
174 #ifndef _NO_CSOCKET_NS // some people may not want to use a namespace
175 namespace Csocket
176 {
177 #endif /* _NO_CSOCKET_NS */
178 
179 
180 /**
181  * @class CSCharBuffer
182  * @brief Ease of use self deleting char * class.
183  */
184 class CS_EXPORT CSCharBuffer
185 {
186 public:
CSCharBuffer(size_t iSize)187 	CSCharBuffer( size_t iSize )
188 	{
189 		m_pBuffer = ( char * )malloc( iSize );
190 	}
~CSCharBuffer()191 	~CSCharBuffer()
192 	{
193 		free( m_pBuffer );
194 	}
operator()195 	char * operator()() { return( m_pBuffer ); }
196 
197 private:
198 	char *	m_pBuffer;
199 };
200 
201 
202 /**
203  * @class CSSockAddr
204  * @brief sockaddr wrapper.
205  */
206 class CS_EXPORT CSSockAddr
207 {
208 public:
CSSockAddr()209 	CSSockAddr()
210 	{
211 		m_bIsIPv6 = false;
212 		memset( ( struct sockaddr_in * ) &m_saddr, '\0', sizeof( m_saddr ) );
213 #ifdef HAVE_IPV6
214 		memset( ( struct sockaddr_in6 * ) &m_saddr6, '\0', sizeof( m_saddr6 ) );
215 #endif /* HAVE_IPV6 */
216 		m_iAFRequire = RAF_ANY;
217 	}
~CSSockAddr()218 	virtual ~CSSockAddr() {}
219 
220 
221 	enum EAFRequire
222 	{
223 	    RAF_ANY		= PF_UNSPEC,
224 #ifdef HAVE_IPV6
225 	    RAF_INET6	= AF_INET6,
226 #endif /* HAVE_IPV6 */
227 	    RAF_INET	= AF_INET
228 	};
229 
230 	void SinFamily();
231 	void SinPort( uint16_t iPort );
232 	void SetIPv6( bool b );
GetIPv6()233 	bool GetIPv6() const { return( m_bIsIPv6 ); }
234 
GetSockAddrLen()235 	socklen_t GetSockAddrLen() { return( sizeof( m_saddr ) ); }
GetSockAddr()236 	sockaddr_in * GetSockAddr() { return( &m_saddr ); }
GetAddr()237 	in_addr * GetAddr() { return( &( m_saddr.sin_addr ) ); }
238 #ifdef HAVE_IPV6
GetSockAddrLen6()239 	socklen_t GetSockAddrLen6() { return( sizeof( m_saddr6 ) ); }
GetSockAddr6()240 	sockaddr_in6 * GetSockAddr6() { return( &m_saddr6 ); }
GetAddr6()241 	in6_addr * GetAddr6() { return( &( m_saddr6.sin6_addr ) ); }
242 #endif /* HAVE_IPV6 */
243 
SetAFRequire(EAFRequire iWhich)244 	void SetAFRequire( EAFRequire iWhich ) { m_iAFRequire = iWhich; }
GetAFRequire()245 	EAFRequire GetAFRequire() const { return( m_iAFRequire ); }
246 
247 private:
248 	bool			m_bIsIPv6;
249 	sockaddr_in		m_saddr;
250 #ifdef HAVE_IPV6
251 	sockaddr_in6	m_saddr6;
252 #endif /* HAVE_IPV6 */
253 	EAFRequire		m_iAFRequire;
254 };
255 
256 
257 class Csock;
258 
259 
260 /**
261  * @class CGetAddrInfo
262  * @brief this function is a wrapper around getaddrinfo (for ipv6)
263  *
264  * in the event this code is using ipv6, it calls getaddrinfo, and it tries to start the connection on each iteration
265  * in the linked list returned by getaddrinfo. if pSock is not NULL the following behavior happens.
266  * - if pSock is a listener, or if the connect state is in a bind vhost state (to be used with bind) AI_PASSIVE is sent to getaddrinfo
267  * - if pSock is an outbound connection, AI_ADDRCONFIG and the connection is started from within this function.
268  * getaddrinfo might return multiple (possibly invalid depending on system configuration) ip addresses, so connect needs to try them all.
269  * A classic example of this is a hostname that resolves to both ipv4 and ipv6 ip's. You still need to call Connect (and ConnectSSL) to finish
270  * up the connection state
271  *
272  * Process can be called in a thread, but Init and Finish must only be called from the parent once the thread is complete
273  */
274 class CS_EXPORT CGetAddrInfo
275 {
276 public:
277 	/**
278 	 * @brief ctor
279 	 * @param sHostname the host to resolve
280 	 * @param pSock the sock being setup, this option can be NULL, if it is null csSockAddr is only setup
281 	 * @param csSockAddr the struct that sockaddr data is being copied to
282 	 */
283 	CGetAddrInfo( const CS_STRING & sHostname, Csock * pSock, CSSockAddr & csSockAddr );
284 	~CGetAddrInfo();
285 
286 	//! simply sets up m_cHints for use in process
287 	void Init();
288 	//! the simplest part of the function, only calls getaddrinfo and uses only m_sHostname, m_pAddrRes, and m_cHints.
289 	int Process();
290 	//! finalizes and sets up csSockAddr (and pSock if not NULL), only needs to be called if Process returns 0, but can be called anyways if flow demands it
291 	int Finish();
292 
293 private:
294 	CS_STRING m_sHostname;
295 	Csock * m_pSock;
296 	CSSockAddr & m_csSockAddr;
297 	struct addrinfo * m_pAddrRes;
298 	struct addrinfo m_cHints;
299 	int m_iRet;
300 };
301 
302 //! backwards compatible wrapper around CGetAddrInfo and gethostbyname
303 int CS_GetAddrInfo( const CS_STRING & sHostname, Csock * pSock, CSSockAddr & csSockAddr );
304 
305 /**
306  * This returns the [ex_]data index position for SSL objects only. If you want to tie more data
307  * to the SSL object, you should generate your own at application start so as to avoid collision
308  * with Csocket SSL_set_ex_data()
309  */
310 int GetCsockSSLIdx();
311 
312 #ifdef HAVE_LIBSSL
313 //! returns the sock object associated to the particular context. returns NULL on failure or if not available
314 Csock * GetCsockFromCTX( X509_STORE_CTX * pCTX );
315 #endif /* HAVE_LIBSSL */
316 
317 
318 const uint32_t CS_BLOCKSIZE = 4096;
CS_Delete(T * & p)319 template <class T> inline void CS_Delete( T * & p ) { if( p ) { delete p; p = NULL; } }
320 
321 #ifdef HAVE_LIBSSL
322 enum ECompType
323 {
324     CT_NONE	= 0,
325     CT_ZLIB	= 1
326 };
327 
328 //! adjusts tv with a new timeout if iTimeoutMS is smaller
329 void CSAdjustTVTimeout( struct timeval & tv, long iTimeoutMS );
330 
331 void SSLErrors( const char *filename, uint32_t iLineNum );
332 
333 /**
334  * @brief You HAVE to call this in order to use the SSL library, calling InitCsocket() also calls this
335  * so unless you need to call InitSSL for a specific reason call InitCsocket()
336  * @return true on success
337  */
338 bool InitSSL( ECompType eCompressionType = CT_NONE );
339 
340 #endif /* HAVE_LIBSSL */
341 
342 /**
343  * This does all the csocket initialized inclusing InitSSL() and win32 specific initializations, only needs to be called once
344  */
345 bool InitCsocket();
346 /**
347  * Shutdown and release global allocated memory
348  */
349 void ShutdownCsocket();
350 
351 //! @todo need to make this sock specific via getsockopt
GetSockError()352 inline int GetSockError()
353 {
354 #ifdef _WIN32
355 	return( WSAGetLastError() );
356 #else
357 	return( errno );
358 #endif /* _WIN32 */
359 }
360 
361 //! wrappers for FD_SET and such to work in templates.
TFD_ZERO(fd_set * set)362 inline void TFD_ZERO( fd_set *set )
363 {
364 	FD_ZERO( set );
365 }
366 
TFD_SET(cs_sock_t iSock,fd_set * set)367 inline void TFD_SET( cs_sock_t iSock, fd_set *set )
368 {
369 	FD_SET( iSock, set );
370 }
371 
TFD_ISSET(cs_sock_t iSock,fd_set * set)372 inline bool TFD_ISSET( cs_sock_t iSock, fd_set *set )
373 {
374 	return( FD_ISSET( iSock, set ) != 0 );
375 }
376 
TFD_CLR(cs_sock_t iSock,fd_set * set)377 inline void TFD_CLR( cs_sock_t iSock, fd_set *set )
378 {
379 	FD_CLR( iSock, set );
380 }
381 
382 void __Perror( const CS_STRING & s, const char * pszFile, uint32_t iLineNo );
383 uint64_t millitime();
384 
385 
386 /**
387  * @class CCron
388  * @brief this is the main cron job class
389  *
390  * You should derive from this class, and override RunJob() with your code
391  * @author Jim Hull <csocket@jimloco.com>
392  */
393 class CS_EXPORT CCron
394 {
395 public:
396 	CCron();
~CCron()397 	virtual ~CCron() {}
398 
399 	//! This is used by the Job Manager, and not you directly
400 	void run( timeval & tNow );
401 
402 	/**
403 	 * @param TimeSequence	how often to run in seconds
404 	 * @param iMaxCycles		how many times to run, 0 makes it run forever
405 	 */
406 	void StartMaxCycles( double dTimeSequence, uint32_t iMaxCycles );
407 	void StartMaxCycles( const timeval& tTimeSequence, uint32_t iMaxCycles );
408 
409 	//! starts and runs infinity amount of times
410 	void Start( double dTimeSequence );
411 	void Start( const timeval& TimeSequence );
412 
413 	//! call this to turn off your cron, it will be removed
414 	void Stop();
415 
416 	//! pauses excution of your code in RunJob
417 	void Pause();
418 
419 	//! removes the pause on RunJon
420 	void UnPause();
421 
422 	//! reset the timer
423 	void Reset();
424 
425 	timeval GetInterval() const;
426 	uint32_t GetMaxCycles() const;
427 	uint32_t GetCyclesLeft() const;
428 
429 	//! returns true if cron is active
430 	bool isValid() const;
431 
432 	const CS_STRING & GetName() const;
433 	void SetName( const CS_STRING & sName );
434 
435 	//! returns the timestamp of the next estimated run time. Note that it may not run at this EXACT time, but it will run at least at this time or after
GetNextRun()436 	timeval GetNextRun() const { return( m_tTime ); }
437 
438 public:
439 
440 	//! this is the method you should override
441 	virtual void RunJob();
442 
443 protected:
444 	bool		m_bRunOnNextCall; //!< if set to true, RunJob() gets called on next invocation of run() despite the timeout
445 
446 private:
447 	timeval		m_tTime;
448 	bool		m_bActive, m_bPause;
449 	timeval		m_tTimeSequence;
450 	uint32_t		m_iMaxCycles, m_iCycles;
451 	CS_STRING	m_sName;
452 };
453 
454 /**
455  * @class CSMonitorFD
456  * @brief Class to tie sockets to for monitoring by Csocket at either the Csock or TSockManager.
457  */
458 class CS_EXPORT CSMonitorFD
459 {
460 public:
CSMonitorFD()461 	CSMonitorFD() { m_bEnabled = true; }
~CSMonitorFD()462 	virtual ~CSMonitorFD() {}
463 
464 	/**
465 	 * @brief called before select, typically you don't need to reimplement this just add sockets via Add and let the default implementation have its way
466 	 * @param miiReadyFds fill with fd's to monitor and the associated bit to check them for (@see CSockManager::ECheckType)
467 	 * @param iTimeoutMS the timeout to change to, setting this to -1 (the default)
468 	 * @return returning false will remove this from monitoring. The same effect can be had by setting m_bEnabled to false as it is returned from this
469 	 */
470 	virtual bool GatherFDsForSelect( std::map< cs_sock_t, short > & miiReadyFds, long & iTimeoutMS );
471 
472 	/**
473 	 * @brief called when there are fd's belonging to this class that have triggered
474 	 * @param miiReadyFds the map of fd's with the bits that triggered them (@see CSockManager::ECheckType)
475 	 * @return returning false will remove this from monitoring
476 	 */
FDsThatTriggered(const std::map<cs_sock_t,short> & miiReadyFds)477 	virtual bool FDsThatTriggered( const std::map< cs_sock_t, short > & miiReadyFds ) { return( true ); }
478 
479 	/**
480 	 * @brief gets called to diff miiReadyFds with m_miiMonitorFDs, and calls FDsThatTriggered when appropriate. Typically you don't need to reimplement this.
481 	 * @param miiReadyFds the map of all triggered fd's, not just the fd's from this class
482 	 * @return returning false will remove this from monitoring
483 	 */
484 	virtual bool CheckFDs( const std::map< cs_sock_t, short > & miiReadyFds );
485 
486 	/**
487 	 * @brief adds a file descriptor to be monitored
488 	 * @param iFD the file descriptor
489 	 * @param iMonitorEvents bitset of events to monitor for (@see CSockManager::ECheckType)
490 	 */
Add(cs_sock_t iFD,short iMonitorEvents)491 	void Add( cs_sock_t iFD, short iMonitorEvents ) { m_miiMonitorFDs[iFD] = iMonitorEvents; }
492 	//! removes this fd from monitoring
Remove(cs_sock_t iFD)493 	void Remove( cs_sock_t iFD ) { m_miiMonitorFDs.erase( iFD ); }
494 	//! causes this monitor to be removed
DisableMonitor()495 	void DisableMonitor() { m_bEnabled = false; }
496 
IsEnabled()497 	bool IsEnabled() const { return( m_bEnabled ); }
498 
499 protected:
500 	std::map< cs_sock_t, short > m_miiMonitorFDs;
501 	bool m_bEnabled;
502 };
503 
504 
505 /**
506  * @class CSockCommon
507  * @brief simple class to share common code to both TSockManager and Csock
508  */
509 class CS_EXPORT CSockCommon
510 {
511 public:
CSockCommon()512 	CSockCommon() {}
513 	virtual ~CSockCommon();
514 
515 	void CleanupCrons();
516 	void CleanupFDMonitors();
517 
518 	//! returns a const reference to the crons associated to this socket
GetCrons()519 	const std::vector<CCron *> & GetCrons() const { return( m_vcCrons ); }
520 	//! This has a garbage collecter, and is used internall to call the jobs
521 	virtual void Cron();
522 
523 	//! insert a newly created cron
524 	virtual void AddCron( CCron * pcCron );
525 	/**
526 	 * @brief deletes a cron by name
527 	 * @param sName the name of the cron
528 	 * @param bDeleteAll delete all crons that match sName
529 	 * @param bCaseSensitive use strcmp or strcasecmp
530 	 */
531 	virtual void DelCron( const CS_STRING & sName, bool bDeleteAll = true, bool bCaseSensitive = true );
532 	//! delete cron by idx
533 	virtual void DelCron( uint32_t iPos );
534 	//! delete cron by address
535 	virtual void DelCronByAddr( CCron * pcCron );
536 
537 	void CheckFDs( const std::map< cs_sock_t, short > & miiReadyFds );
538 	void AssignFDs( std::map< cs_sock_t, short > & miiReadyFds, struct timeval * tvtimeout );
539 
540 	//! add an FD set to monitor
MonitorFD(CSMonitorFD * pMonitorFD)541 	void MonitorFD( CSMonitorFD * pMonitorFD ) { m_vcMonitorFD.push_back( pMonitorFD ); }
542 
543 protected:
544 	std::vector<CCron *>		m_vcCrons;
545 	std::vector<CSMonitorFD *>	m_vcMonitorFD;
546 };
547 
548 
549 #ifdef HAVE_LIBSSL
550 typedef int ( *FPCertVerifyCB )( int, X509_STORE_CTX * );
551 #endif /* HAVE_LIBSSL */
552 
553 
554 /**
555  * @class Csock
556  * @brief Basic socket class.
557  *
558  * The most basic level socket class.
559  * You can use this class directly for quick things
560  * or use the socket manager.
561  * @see TSocketManager
562  * @author Jim Hull <csocket@jimloco.com>
563  */
564 class CS_EXPORT Csock : public CSockCommon
565 {
566 public:
567 	//! default constructor, sets a timeout of 60 seconds
568 	Csock( int iTimeout = 60 );
569 	/**
570 	 * @brief Advanced constructor, for creating a simple connection
571 	 * @param sHostname the hostname your are connecting to
572 	 * @param uPort the port you are connecting to
573 	 * @param itimeout how long to wait before ditching the connection, default is 60 seconds
574 	 */
575 	Csock( const CS_STRING & sHostname, uint16_t uPort, int itimeout = 60 );
576 
577 	//! override this for accept sockets
578 	virtual Csock *GetSockObj( const CS_STRING & sHostname, uint16_t iPort );
579 
580 	virtual ~Csock();
581 
582 	/**
583 	 * @brief in the event you pass this class to Copy(), you MUST call this function or
584 	 * on the original Csock other wise bad side effects will happen (double deletes, weird sock closures, etc)
585 	 * if you call this function and have not handled the internal pointers, other bad things can happend (memory leaks, fd leaks, etc)
586 	 * the whole point of this function is to allow this class to go away without shutting down
587 	 */
588 	virtual void Dereference();
589 	//! use this to copy a sock from one to the other, override it if you have special needs in the event of a copy
590 	virtual void Copy( const Csock & cCopy );
591 
592 	enum ETConn
593 	{
594 	    OUTBOUND			= 0,		//!< outbound connection
595 	    LISTENER			= 1,		//!< a socket accepting connections
596 	    INBOUND				= 2			//!< an inbound connection, passed from LISTENER
597 	};
598 
599 	enum EFRead
600 	{
601 	    READ_EOF			= 0,		//!< End Of File, done reading
602 	    READ_ERR			= -1,		//!< Error on the socket, socket closed, done reading
603 	    READ_EAGAIN			= -2,		//!< Try to get data again
604 	    READ_CONNREFUSED	= -3,		//!< Connection Refused
605 	    READ_TIMEDOUT		= -4		//!< Connection timed out
606 	};
607 
608 	enum EFSelect
609 	{
610 	    SEL_OK				= 0,		//!< Select passed ok
611 	    SEL_TIMEOUT			= -1,		//!< Select timed out
612 	    SEL_EAGAIN			= -2,		//!< Select wants you to try again
613 	    SEL_ERR				= -3		//!< Select recieved an error
614 	};
615 
616 	enum ESSLMethod
617 	{
618 	    TLS					= 0,
619 	    SSL23				= TLS,
620 	    SSL2				= 2,
621 	    SSL3				= 3,
622 	    TLS1				= 4,
623 	    TLS11				= 5,
624 	    TLS12				= 6
625 	};
626 
627 	enum EDisableProtocol
628 	{
629 		EDP_None		= 0, //!< disable nothing
630 		EDP_SSLv2		= 1, //!< disable SSL version 2
631 		EDP_SSLv3		= 2, //!< disable SSL version 3
632 		EDP_TLSv1		= 4, //!< disable TLS version 1
633 		EDP_TLSv1_1		= 8, //!< disable TLS version 1.1
634 		EDP_TLSv1_2		= 16, //!< disable TLS version 1.2
635 		EDP_SSL			= (EDP_SSLv2|EDP_SSLv3)
636 	};
637 
638 	enum ECONState
639 	{
640 	    CST_START		= 0,
641 	    CST_DNS			= CST_START,
642 	    CST_BINDVHOST	= 1,
643 	    CST_DESTDNS		= 2,
644 	    CST_CONNECT		= 3,
645 	    CST_CONNECTSSL	= 4,
646 	    CST_OK			= 5
647 	};
648 
649 	enum ECloseType
650 	{
651 	    CLT_DONT			= 0, //!< don't close DER
652 	    CLT_NOW				= 1, //!< close immediatly
653 	    CLT_AFTERWRITE		= 2, //!< close after finishing writing the buffer
654 	    CLT_DEREFERENCE		= 3	 //!< used after copy in Csock::Dereference() to cleanup a sock thats being shutdown
655 	};
656 
657 	Csock & operator<<( const CS_STRING & s );
658 	Csock & operator<<( std::ostream & ( *io )( std::ostream & ) );
659 	Csock & operator<<( int32_t i );
660 	Csock & operator<<( uint32_t i );
661 	Csock & operator<<( int64_t i );
662 	Csock & operator<<( uint64_t i );
663 	Csock & operator<<( float i );
664 	Csock & operator<<( double i );
665 
666 	/**
667 	 * @brief Create the connection, this is used by the socket manager, and shouldn't be called directly by the user
668 	 * @return true on success
669 	 */
670 	virtual bool Connect();
671 
672 #ifdef HAVE_UNIX_SOCKET
673 	/**
674 	 * @brief Connect to a UNIX socket.
675 	 * @param sPath the path to the UNIX socket.
676 	 */
677 	virtual bool ConnectUnix( const CS_STRING & sPath );
678 
679 	/**
680 	 * @brief Listens for connections on an UNIX socket
681 	 * @param sBindFile the socket on which to listen
682 	 * @param iMaxConns the maximum amount of pending connections to allow
683 	 * @param iTimeout if no connections come in by this timeout, the listener is closed
684 	 */
685 	virtual bool ListenUnix( const CS_STRING & sBindFile, int iMaxConns = SOMAXCONN, uint32_t iTimeout = 0 );
686 #endif
687 
688 	/**
689 	 * @brief Listens for connections
690 	 * @param iPort the port to listen on
691 	 * @param iMaxConns the maximum amount of pending connections to allow
692 	 * @param sBindHost the vhost on which to listen
693 	 * @param iTimeout if no connections come in by this timeout, the listener is closed
694 	 * @param bDetach don't block waiting for port to come up, instead detach and return immediately
695 	 */
696 	virtual bool Listen( uint16_t iPort, int iMaxConns = SOMAXCONN, const CS_STRING & sBindHost = "", uint32_t iTimeout = 0, bool bDetach = false );
697 
698 	//! Accept an inbound connection, this is used internally
699 	virtual cs_sock_t Accept( CS_STRING & sHost, uint16_t & iRPort );
700 
701 	//! Accept an inbound SSL connection, this is used internally and called after Accept
702 	virtual bool AcceptSSL();
703 
704 	//! This sets up the SSL Client, this is used internally
705 	virtual bool SSLClientSetup();
706 
707 	//! This sets up the SSL Server, this is used internally
708 	virtual bool SSLServerSetup();
709 
710 	/**
711 	 * @brief Create the SSL connection
712 	 * @return true on success
713 	 *
714 	 * This is used by the socket manager, and shouldn't be called directly by the user.
715 	 */
716 	virtual bool ConnectSSL();
717 
718 	//! start a TLS connection on an existing plain connection
719 	bool StartTLS();
720 
721 	/**
722 	 * @brief Write data to the socket
723 	 *
724 	 * If not all of the data is sent, it will be stored on
725 	 * an internal buffer, and tried again with next call to Write
726 	 * if the socket is blocking, it will send everything, its ok to check ernno after this (nothing else is processed)
727 	 *
728 	 * @param data the data to send
729 	 * @param len the length of data
730 	 */
731 	virtual bool Write( const char *data, size_t len );
732 
733 	/**
734 	 * @brief Write a text string to the socket
735 	 *
736 	 * Encoding is used, if set
737 	 *
738 	 * @param sData the string to send; if encoding is provided, sData should be UTF-8 and will be encoded
739 	 * @see Write( const char *, int )
740 	 */
741 	virtual bool Write( const CS_STRING & sData );
742 
743 	/**
744 	 * Read from the socket
745 	 * Just pass in a pointer, big enough to hold len bytes
746 	 *
747 	 * @param data the buffer to read into
748 	 * @param len the size of the buffer
749 	 *
750 	 * @return
751 	 * Returns READ_EOF for EOF
752 	 * Returns READ_ERR for ERROR
753 	 * Returns READ_EAGAIN for Try Again ( EAGAIN )
754 	 * Returns READ_CONNREFUSED for connection refused
755 	 * Returns READ_TIMEDOUT for a connection that timed out at the TCP level
756 	 * Otherwise returns the bytes read into data
757 	 */
758 	virtual cs_ssize_t Read( char *data, size_t len );
759 	CS_STRING GetLocalIP() const;
760 	CS_STRING GetRemoteIP() const;
761 
762 	//! Tells you if the socket is connected
763 	virtual bool IsConnected() const;
764 	//! Sets the sock, telling it its connected (internal use only)
765 	virtual void SetIsConnected( bool b );
766 
767 	//! returns a reference to the sock
768 	cs_sock_t & GetRSock();
769 	const cs_sock_t & GetRSock() const;
770 	void SetRSock( cs_sock_t iSock );
771 	cs_sock_t & GetWSock();
772 	const cs_sock_t & GetWSock() const;
773 	void SetWSock( cs_sock_t iSock );
774 
775 	void SetSock( cs_sock_t iSock );
776 	cs_sock_t & GetSock();
777 	const cs_sock_t & GetSock() const;
778 
779 	/**
780 	 * @brief calls SockError, if sDescription is not set, then strerror is used to pull out a default description
781 	 * @param iErrno the errno to send
782 	 * @param sDescription the description of the error that occurred
783 	 */
784 	void CallSockError( int iErrno, const CS_STRING & sDescription = "" );
785 	//! resets the time counter, this is virtual in the event you need an event on the timer being Reset
786 	virtual void ResetTimer();
787 
788 	//! will pause/unpause reading on this socket
789 	void PauseRead();
790 	void UnPauseRead();
791 	bool IsReadPaused() const;
792 	/**
793 	 * this timeout isn't just connection timeout, but also timeout on
794 	 * NOT recieving data, to disable this set it to 0
795 	 * then the normal TCP timeout will apply (basically TCP will kill a dead connection)
796 	 * Set the timeout, set to 0 to never timeout
797 	 */
798 	enum
799 	{
800 	    TMO_READ	= 1,
801 	    TMO_WRITE	= 2,
802 	    TMO_ACCEPT	= 4,
803 	    TMO_ALL		= TMO_READ|TMO_WRITE|TMO_ACCEPT
804 	};
805 
806 	//! Currently this uses the same value for all timeouts, and iTimeoutType merely states which event will be checked
807 	//! for timeouts
808 	void SetTimeout( int iTimeout, uint32_t iTimeoutType = TMO_ALL );
809 	void SetTimeoutType( uint32_t iTimeoutType );
810 	int GetTimeout() const;
811 	uint32_t GetTimeoutType() const;
812 
813 	//! returns true if the socket has timed out
814 	virtual bool CheckTimeout( time_t iNow );
815 
816 	/**
817 	* pushes data up on the buffer, if a line is ready
818 	* it calls the ReadLine event
819 	*/
820 	virtual void PushBuff( const char *data, size_t len, bool bStartAtZero = false );
821 
822 	//! This gives access to the internal read buffer, if your
823 	//! not going to use ReadLine(), then you may want to clear this out
824 	//! (if its binary data and not many '\\n')
825 	CS_STRING & GetInternalReadBuffer();
826 
827 	//! This gives access to the internal write buffer.
828 	//! If you want to check if the send queue fills up, check here.
829 	CS_STRING & GetInternalWriteBuffer();
830 
831 	//! sets the max buffered threshold when EnableReadLine() is enabled
832 	void SetMaxBufferThreshold( uint32_t iThreshold );
833 	uint32_t GetMaxBufferThreshold() const;
834 
835 	//! Returns the connection type from enum eConnType
836 	int GetType() const;
837 	void SetType( int iType );
838 
839 	//! Returns a reference to the socket name
840 	const CS_STRING & GetSockName() const;
841 	void SetSockName( const CS_STRING & sName );
842 
843 	//! Returns a reference to the host name
844 	const CS_STRING & GetHostName() const;
845 	void SetHostName( const CS_STRING & sHostname );
846 
847 
848 	//! Gets the starting time of this socket
849 	uint64_t GetStartTime() const;
850 	//! Resets the start time
851 	void ResetStartTime();
852 
853 	//! Gets the amount of data read during the existence of the socket
854 	uint64_t GetBytesRead() const;
855 	void ResetBytesRead();
856 
857 	//! Gets the amount of data written during the existence of the socket
858 	uint64_t GetBytesWritten() const;
859 	void ResetBytesWritten();
860 
861 	//! Get Avg Read Speed in sample milliseconds (default is 1000 milliseconds or 1 second)
862 	double GetAvgRead( uint64_t iSample = 1000 ) const;
863 
864 	//! Get Avg Write Speed in sample milliseconds (default is 1000 milliseconds or 1 second)
865 	double GetAvgWrite( uint64_t iSample = 1000 ) const;
866 
867 	//! Returns the remote port
868 	uint16_t GetRemotePort() const;
869 
870 	//! Returns the local port
871 	uint16_t GetLocalPort() const;
872 
873 	//! Returns the port
874 	uint16_t GetPort() const;
875 	void SetPort( uint16_t iPort );
876 
877 	//! just mark us as closed, the parent can pick it up
878 	void Close( ECloseType eCloseType = CLT_NOW );
879 	//! returns int of type to close @see ECloseType
GetCloseType()880 	ECloseType GetCloseType() const { return( m_eCloseType ); }
IsClosed()881 	bool IsClosed() const { return( GetCloseType() != CLT_DONT ); }
882 
883 	//! Use this to change your fd's to blocking or none blocking
884 	void NonBlockingIO();
885 
886 	//! Return true if this socket is using ssl. Note this does not mean the SSL state is finished, but simply that its configured to use ssl
887 	bool GetSSL() const;
888 	void SetSSL( bool b );
889 
890 #ifdef HAVE_LIBSSL
891 	//! bitwise setter, @see EDisableProtocol
DisableSSLProtocols(u_int uDisableOpts)892 	void DisableSSLProtocols( u_int uDisableOpts ) { m_uDisableProtocols = uDisableOpts; }
893 	//! allow disabling compression
DisableSSLCompression()894 	void DisableSSLCompression() { m_bNoSSLCompression = true; }
895 	//! select the ciphers in server-preferred order
FollowSSLCipherServerPreference()896 	void FollowSSLCipherServerPreference() { m_bSSLCipherServerPreference = true; }
897 	//! Set the cipher type ( openssl cipher [to see ciphers available] )
898 	void SetCipher( const CS_STRING & sCipher );
899 	const CS_STRING & GetCipher() const;
900 
901 	//! Set the pem file location
902 	void SetDHParamLocation( const CS_STRING & sDHParamFile );
903 	const CS_STRING & GetDHParamLocation() const;
904 	void SetKeyLocation( const CS_STRING & sKeyFile );
905 	const CS_STRING & GetKeyLocation() const;
906 	void SetPemLocation( const CS_STRING & sPemFile );
907 	const CS_STRING & GetPemLocation() const;
908 	void SetPemPass( const CS_STRING & sPassword );
909 	const CS_STRING & GetPemPass() const;
910 
911 	//! Set the SSL method type
912 	void SetSSLMethod( int iMethod );
913 	int GetSSLMethod() const;
914 
915 	void SetSSLObject( SSL *ssl, bool bDeleteExisting = false );
916 	SSL * GetSSLObject() const;
917 	void SetCTXObject( SSL_CTX *sslCtx, bool bDeleteExisting = false );
918 	SSL_SESSION * GetSSLSession() const;
919 
920 	//! setting this to NULL will allow the default openssl verification process kick in
SetCertVerifyCB(FPCertVerifyCB pFP)921 	void SetCertVerifyCB( FPCertVerifyCB pFP ) { m_pCerVerifyCB = pFP; }
922 #endif /* HAVE_LIBSSL */
923 
924 	//! Get the send buffer
925 	bool HasWriteBuffer() const;
926 	void ClearWriteBuffer();
927 
928 	//! is SSL_accept finished ?
929 	//! is the ssl properly finished (from write no error)
930 	bool SslIsEstablished() const;
931 
932 	//! Use this to bind this socket to inetd
933 	bool ConnectInetd( bool bIsSSL = false, const CS_STRING & sHostname = "" );
934 
935 	//! Tie this guy to an existing real file descriptor
936 	bool ConnectFD( int iReadFD, int iWriteFD, const CS_STRING & sName, bool bIsSSL = false, ETConn eDirection = INBOUND );
937 
938 	//! Get the peer's X509 cert
939 #ifdef HAVE_LIBSSL
940 	//! it is up to you, the caller to call X509_free() on this object
941 	X509 *GetX509() const;
942 
943 	//! Returns the peer's public key
944 	CS_STRING GetPeerPubKey() const;
945 	//! Returns the peer's certificate finger print
946 	long GetPeerFingerprint( CS_STRING & sFP ) const;
947 
948 	uint32_t GetRequireClientCertFlags() const;
949 	//! legacy, deprecated @see SetRequireClientCertFlags
950 	void SetRequiresClientCert( bool bRequiresCert );
951 	//! bitwise flags, 0 means don't require cert, SSL_VERIFY_PEER verifies peers, SSL_VERIFY_FAIL_IF_NO_PEER_CERT will cause the connection to fail if no cert
SetRequireClientCertFlags(uint32_t iRequireClientCertFlags)952 	void SetRequireClientCertFlags( uint32_t iRequireClientCertFlags ) { m_iRequireClientCertFlags = iRequireClientCertFlags; }
953 #endif /* HAVE_LIBSSL */
954 
955 	//! Set The INBOUND Parent sockname
956 	virtual void SetParentSockName( const CS_STRING & sParentName );
957 	const CS_STRING & GetParentSockName() const;
958 
959 	/**
960 	 * sets the rate at which we can send data
961 	 * @param iBytes the amount of bytes we can write
962 	 * @param iMilliseconds the amount of time we have to rate to iBytes
963 	 */
964 	virtual void SetRate( uint32_t iBytes, uint64_t iMilliseconds );
965 
966 	uint32_t GetRateBytes() const;
967 	uint64_t GetRateTime() const;
968 
969 	/**
970 	 * Connected event
971 	 */
Connected()972 	virtual void Connected() {}
973 	/**
974 	 * Disconnected event
975 	 */
Disconnected()976 	virtual void Disconnected() {}
977 	/**
978 	 * Sock Timed out event
979 	 */
Timeout()980 	virtual void Timeout() {}
981 	/**
982 	 * Ready to read data event
983 	 */
ReadData(const char * data,size_t len)984 	virtual void ReadData( const char *data, size_t len ) {}
985 	/**
986 	 *
987 	 * Ready to Read a full line event. If encoding is provided, this is guaranteed to be UTF-8
988 	 */
ReadLine(const CS_STRING & sLine)989 	virtual void ReadLine( const CS_STRING & sLine ) {}
990 	//! set the value of m_bEnableReadLine to true, we don't want to store a buffer for ReadLine, unless we want it
991 	void EnableReadLine();
992 	void DisableReadLine();
993 	//! returns the value of m_bEnableReadLine, if ReadLine is enabled
HasReadLine()994 	bool HasReadLine() const { return( m_bEnableReadLine ); }
995 
996 	/**
997 	 * This WARNING event is called when your buffer for readline exceeds the warning threshold
998 	 * and triggers this event. Either Override it and do nothing, or SetMaxBufferThreshold()
999 	 * This event will only get called if m_bEnableReadLine is enabled
1000 	 */
1001 	virtual void ReachedMaxBuffer();
1002 	/**
1003 	 * @brief A sock error occured event
1004 	 */
SockError(int iErrno,const CS_STRING & sDescription)1005 	virtual void SockError( int iErrno, const CS_STRING & sDescription ) {}
1006 	/**
1007 	 * Incoming Connection Event
1008 	 * return false and the connection will fail
1009 	 * default returns true
1010 	 */
ConnectionFrom(const CS_STRING & sHost,uint16_t iPort)1011 	virtual bool ConnectionFrom( const CS_STRING & sHost, uint16_t iPort ) { return( true ); }
1012 
1013 	/**
1014 	 * @brief called when type is LISTENER and the listening port is up and running
1015 	 * @param sBindIP the IP that is being bound to. Empty if no bind restriction
1016 	 * @param uPort the listening port
1017 	 */
Listening(const CS_STRING & sBindIP,uint16_t uPort)1018 	virtual void Listening( const CS_STRING & sBindIP, uint16_t uPort ) {}
1019 
1020 	/**
1021 	 * Connection Refused Event
1022 	 *
1023 	 */
ConnectionRefused()1024 	virtual void ConnectionRefused() {}
1025 	/**
1026 	 * This gets called every iteration of CSocketManager::Select() if the socket is ReadPaused
1027 	 */
ReadPaused()1028 	virtual void ReadPaused() {}
1029 
1030 #ifdef HAVE_LIBSSL
1031 	/**
1032 	 * Gets called immediatly after the m_ssl member is setup and initialized, useful if you need to assign anything
1033 	 * to this ssl session via SSL_set_ex_data
1034 	 */
SSLFinishSetup(SSL * pSSL)1035 	virtual void SSLFinishSetup( SSL * pSSL ) {}
1036 	/**
1037 	 * @brief gets called when a SNI request is sent, and used to configure a SNI session
1038 	 * @param sHostname the hostname sent from the client
1039 	 * @param sPemFile fill this with the location to the pemfile
1040 	 * @param sPemPass fill this with the pemfile password if there is one
1041 	 * @return return true to proceed with the SNI server configuration
1042 	 */
SNIConfigureServer(const CS_STRING & sHostname,CS_STRING & sPemFile,CS_STRING & sPemPass)1043 	virtual bool SNIConfigureServer( const CS_STRING & sHostname, CS_STRING & sPemFile, CS_STRING & sPemPass ) { return( false ); }
1044 	/**
1045 	 * @brief called to configure the SNI client
1046 	 * @param sHostname, the hostname to configure SNI with, you can fill this with GetHostname() if its a valid hostname and not an OP
1047 	 * @return returning true causes a call to configure SNI with the hostname returned
1048 	 */
1049 	virtual bool SNIConfigureClient( CS_STRING & sHostname );
1050 	//! creates a new SSL_CTX based on the setup of this sock
1051 	SSL_CTX * SetupServerCTX();
1052 
1053 	/**
1054 	 * @brief called once the SSL handshake is complete, this is triggered via SSL_CB_HANDSHAKE_DONE in SSL_set_info_callback()
1055 	 *
1056 	 * This is a spot where you can look at the finished peer certifificate ... IE
1057 	 * <pre>
1058 	 * X509 * pCert = GetX509();
1059 	 * char szName[256];
1060 	 * memset( szName, '\0', 256 );
1061 	 * X509_NAME_get_text_by_NID ( X509_get_subject_name( pCert ), NID_commonName, szName, 255 );
1062 	 * cerr << "Name! " << szName << endl;
1063 	 * X509_free( pCert );
1064 	 * </pre>
1065 	 */
SSLHandShakeFinished()1066 	virtual void SSLHandShakeFinished() {}
1067 	/**
1068 	 * @brief this is hooked in via SSL_set_verify, and be default it just returns 1 meaning success
1069 	 * @param iPreVerify the pre-verification status as determined by openssl internally
1070 	 * @param pStoreCTX the X509_STORE_CTX containing the certificate
1071 	 * @return 1 to continue, 0 to abort
1072 	 *
1073 	 * This may get called multiple times, for example with a chain certificate which is fairly typical with
1074 	 * certificates from godaddy, freessl, etc. Additionally, openssl does not do any host verification, they
1075 	 * leave that up to the you. One easy way to deal with this is to wait for SSLHandShakeFinished() and examine
1076 	 * the peer certificate @see SSLHandShakeFinished
1077 	 */
VerifyPeerCertificate(int iPreVerify,X509_STORE_CTX * pStoreCTX)1078 	virtual int VerifyPeerCertificate( int iPreVerify, X509_STORE_CTX * pStoreCTX ) { return( 1 ); }
1079 #endif /* HAVE_LIBSSL */
1080 
1081 
1082 	//! return how long it has been (in seconds) since the last read or successful write
1083 	time_t GetTimeSinceLastDataTransaction( time_t iNow = 0 ) const;
1084 
GetLastCheckTimeout()1085 	time_t GetLastCheckTimeout() const { return( m_iLastCheckTimeoutTime ); }
1086 
1087 	//! Returns the time when CheckTimeout() should be called next
1088 	time_t GetNextCheckTimeout( time_t iNow = 0 ) const;
1089 
1090 	//! return the data imediatly ready for read
1091 	virtual int GetPending() const;
1092 
1093 	//////////////////////////
1094 	// Connection State Stuff
1095 	//! returns the current connection state
GetConState()1096 	ECONState GetConState() const { return( m_eConState ); }
1097 	//! sets the connection state to eState
SetConState(ECONState eState)1098 	void SetConState( ECONState eState ) { m_eConState = eState; }
1099 
1100 	//! grabs fd's for the sockets
1101 	bool CreateSocksFD();
1102 
1103 	//! puts the socks back to the state they were prior to calling CreateSocksFD
1104 	void CloseSocksFD();
1105 
GetBindHost()1106 	const CS_STRING & GetBindHost() const { return( m_sBindHost ); }
SetBindHost(const CS_STRING & sBindHost)1107 	void SetBindHost( const CS_STRING & sBindHost ) { m_sBindHost = sBindHost; }
1108 
1109 	enum EDNSLType
1110 	{
1111 	    DNS_VHOST, //!< this lookup is for the vhost bind
1112 	    DNS_DEST //!< this lookup is for the destination address
1113 	};
1114 
1115 	/**
1116 	 * dns lookup @see EDNSLType
1117 	 * @return 0 for success, EAGAIN to check back again (same arguments as before), ETIMEDOUT on failure
1118 	 */
1119 	int DNSLookup( EDNSLType eDNSLType );
1120 
1121 	//! this is only used on outbound connections, listeners bind in a different spot
1122 	bool SetupVHost();
1123 
GetIPv6()1124 	bool GetIPv6() const { return( m_bIsIPv6 ); }
SetIPv6(bool b)1125 	void SetIPv6( bool b )
1126 	{
1127 		m_bIsIPv6 = b;
1128 		m_address.SetIPv6( b );
1129 		m_bindhost.SetIPv6( b );
1130 	}
1131 
SetAFRequire(CSSockAddr::EAFRequire iAFRequire)1132 	void SetAFRequire( CSSockAddr::EAFRequire iAFRequire )
1133 	{
1134 		m_address.SetAFRequire( iAFRequire );
1135 		m_bindhost.SetAFRequire( iAFRequire );
1136 	}
1137 
1138 	//! returns true if this socket can write its data, primarily used with rate shaping, initialize iNOW to 0 and it sets it on the first call
1139 	bool AllowWrite( uint64_t & iNOW ) const;
1140 
1141 
SetSkipConnect(bool b)1142 	void SetSkipConnect( bool b ) { m_bSkipConnect = b; }
1143 
1144 	/**
1145 	 * @brief override this call with your own DNS lookup method if you have one. By default this function is blocking
1146 	 * @param sHostname the hostname to resolve
1147 	 * @param csSockAddr the destination sock address info @see CSSockAddr
1148 	 * @return 0 on success, ETIMEDOUT if no lookup was found, EAGAIN if you should check again later for an answer
1149 	 */
1150 	virtual int GetAddrInfo( const CS_STRING & sHostname, CSSockAddr & csSockAddr );
1151 
1152 	/**
1153 	 * @brief retrieve name info (numeric only) for a given sockaddr_storage
1154 	 * @param pAddr the sockaddr_storage
1155 	 * @param iAddrLen the length
1156 	 * @param sIP filled with the IP from getnameinfo
1157 	 * @param piPort if not null, filled with the port
1158 	 * @return 0 on success.
1159 	 *
1160 	 * In the event you want to do additional work before or after getnameinfo is called, you can override this and do just that.
1161 	 * One example is in the event that an ipv6 ip is a mapped ipv4 mapped, you can check like so.
1162 	 * - if( pAddr->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED( &(((const struct sockaddr_in6 *)pAddr)->sin6_addr ) )
1163 	 */
1164 	virtual int ConvertAddress( const struct sockaddr_storage * pAddr, socklen_t iAddrLen, CS_STRING & sIP, uint16_t * piPort ) const;
1165 
1166 #ifdef HAVE_C_ARES
GetCurrentAddr()1167 	CSSockAddr * GetCurrentAddr() const { return( m_pCurrAddr ); }
SetAresFinished(int status)1168 	void SetAresFinished( int status ) { m_pCurrAddr = NULL; m_iARESStatus = status; }
GetAresChannel()1169 	ares_channel GetAresChannel() const { return( m_pARESChannel ); }
1170 #endif /* HAVE_C_ARES */
1171 
1172 	//! returns the number of max pending connections when type is LISTENER
GetMaxConns()1173 	int GetMaxConns() const { return( m_iMaxConns ); }
1174 
1175 #ifdef HAVE_ICU
1176 	void SetEncoding( const CS_STRING & sEncoding );
GetEncoding()1177 	CS_STRING GetEncoding() const { return m_sEncoding; }
1178 	virtual void IcuExtToUCallback(
1179 		UConverterToUnicodeArgs* toArgs,
1180 		const char* codeUnits,
1181 		int32_t length,
1182 		UConverterCallbackReason reason,
1183 		UErrorCode* err );
1184 	virtual void IcuExtFromUCallback(
1185 		UConverterFromUnicodeArgs* fromArgs,
1186 		const UChar* codeUnits,
1187 		int32_t length,
1188 		UChar32 codePoint,
1189 		UConverterCallbackReason reason,
1190 		UErrorCode* err );
1191 #endif /* HAVE_ICU */
1192 
1193 private:
1194 	//! making private for safety
Csock(const Csock & cCopy)1195 	Csock( const Csock & cCopy ) : CSockCommon() {}
1196 	//! shrink sendbuff by removing m_uSendBufferPos bytes from m_sSend
1197 	void ShrinkSendBuff();
1198 	void IncBuffPos( size_t uBytes );
1199 	//! checks for configured protocol disabling
1200 
1201 	// NOTE! if you add any new members, be sure to add them to Copy()
1202 	uint16_t	m_uPort;
1203 	cs_sock_t	m_iReadSock, m_iWriteSock;
1204 	int 		m_iTimeout, m_iConnType, m_iMethod, m_iTcount, m_iMaxConns;
1205 	bool		m_bUseSSL, m_bIsConnected;
1206 	bool		m_bsslEstablished, m_bEnableReadLine, m_bPauseRead;
1207 	CS_STRING	m_shostname, m_sbuffer, m_sSockName, m_sDHParamFile, m_sKeyFile, m_sPemFile, m_sCipherType, m_sParentName;
1208 	CS_STRING	m_sSend, m_sPemPass;
1209 	ECloseType	m_eCloseType;
1210 
1211 	// initialized lazily
1212 	mutable uint16_t	m_iRemotePort, m_iLocalPort;
1213 	mutable CS_STRING	m_sLocalIP, m_sRemoteIP;
1214 
1215 	uint64_t	m_iMaxMilliSeconds, m_iLastSendTime, m_iBytesRead, m_iBytesWritten, m_iStartTime;
1216 	uint32_t	m_iMaxBytes, m_iMaxStoredBufferLength, m_iTimeoutType;
1217 	size_t		m_iLastSend, m_uSendBufferPos;
1218 
1219 	CSSockAddr 	m_address, m_bindhost;
1220 	bool		m_bIsIPv6, m_bSkipConnect;
1221 	time_t		m_iLastCheckTimeoutTime;
1222 
1223 #ifdef HAVE_LIBSSL
1224 	CS_STRING	m_sSSLBuffer;
1225 	SSL	*		m_ssl;
1226 	SSL_CTX	*	m_ssl_ctx;
1227 	uint32_t	m_iRequireClientCertFlags;
1228 	u_int		m_uDisableProtocols;
1229 	bool		m_bNoSSLCompression;
1230 	bool		m_bSSLCipherServerPreference;
1231 
1232 	FPCertVerifyCB		m_pCerVerifyCB;
1233 
1234 	void FREE_SSL();
1235 	void FREE_CTX();
1236 	bool ConfigureCTXOptions( SSL_CTX * pCTX );
1237 
1238 #endif /* HAVE_LIBSSL */
1239 
1240 	//! Create the socket
1241 	cs_sock_t CreateSocket( bool bListen = false, bool bUnix = false );
1242 	void Init( const CS_STRING & sHostname, uint16_t uPort, int iTimeout = 60 );
1243 
1244 	// Connection State Info
1245 	ECONState		m_eConState;
1246 	CS_STRING		m_sBindHost;
1247 	uint32_t		m_iCurBindCount, m_iDNSTryCount;
1248 #ifdef HAVE_C_ARES
1249 	void FreeAres();
1250 	ares_channel	m_pARESChannel;
1251 	CSSockAddr	*	m_pCurrAddr;
1252 	int				m_iARESStatus;
1253 #endif /* HAVE_C_ARES */
1254 
1255 #ifdef HAVE_ICU
1256 	UConverter* m_cnvInt;
1257 	UConverter* m_cnvExt;
1258 	bool m_cnvTryUTF8;
1259 	bool m_cnvSendUTF8;
1260 	CS_STRING m_sEncoding;
1261 #endif
1262 };
1263 
1264 /**
1265  * @class CSConnection
1266  * @brief options for creating a connection
1267  */
1268 class CS_EXPORT CSConnection
1269 {
1270 public:
1271 	/**
1272 	 * @param sHostname hostname to connect to
1273 	 * @param iPort port to connect to
1274 	 * @param iTimeout connection timeout
1275 	 */
1276 	CSConnection( const CS_STRING & sHostname, uint16_t iPort, int iTimeout = 60 )
1277 	{
1278 		m_sHostname = sHostname;
1279 		m_iPort = iPort;
1280 		m_iTimeout = iTimeout;
1281 		m_bIsSSL = false;
1282 #ifdef HAVE_LIBSSL
1283 		m_sCipher = "HIGH";
1284 #endif /* HAVE_LIBSSL */
1285 		m_iAFrequire = CSSockAddr::RAF_ANY;
1286 	}
~CSConnection()1287 	virtual ~CSConnection() {}
1288 
GetHostname()1289 	const CS_STRING & GetHostname() const { return( m_sHostname ); }
GetSockName()1290 	const CS_STRING & GetSockName() const { return( m_sSockName ); }
GetBindHost()1291 	const CS_STRING & GetBindHost() const { return( m_sBindHost ); }
GetPort()1292 	uint16_t GetPort() const { return( m_iPort ); }
GetTimeout()1293 	int GetTimeout() const { return( m_iTimeout ); }
GetIsSSL()1294 	bool GetIsSSL() const { return( m_bIsSSL ); }
GetAFRequire()1295 	CSSockAddr::EAFRequire GetAFRequire() const { return( m_iAFrequire ); }
1296 
1297 #ifdef HAVE_LIBSSL
GetCipher()1298 	const CS_STRING & GetCipher() const { return( m_sCipher ); }
GetPemLocation()1299 	const CS_STRING & GetPemLocation() const { return( m_sPemLocation ); }
GetKeyLocation()1300 	const CS_STRING & GetKeyLocation() const { return( m_sKeyLocation ); }
GetDHParamLocation()1301 	const CS_STRING & GetDHParamLocation() const { return( m_sDHParamLocation ); }
GetPemPass()1302 	const CS_STRING & GetPemPass() const { return( m_sPemPass ); }
1303 #endif /* HAVE_LIBSSL */
1304 
1305 	//! sets the hostname to connect to
SetHostname(const CS_STRING & s)1306 	void SetHostname( const CS_STRING & s ) { m_sHostname = s; }
1307 	//! sets the name of the socket, used for reference, ie in FindSockByName()
SetSockName(const CS_STRING & s)1308 	void SetSockName( const CS_STRING & s ) { m_sSockName = s; }
1309 	//! sets the hostname to bind to (vhost support)
SetBindHost(const CS_STRING & s)1310 	void SetBindHost( const CS_STRING & s ) { m_sBindHost = s; }
1311 	//! sets the port to connect to
SetPort(uint16_t i)1312 	void SetPort( uint16_t i ) { m_iPort = i; }
1313 	//! sets the connection timeout
SetTimeout(int i)1314 	void SetTimeout( int i ) { m_iTimeout = i; }
1315 	//! set to true to enable SSL
SetIsSSL(bool b)1316 	void SetIsSSL( bool b ) { m_bIsSSL = b; }
1317 	//! sets the AF family type required
SetAFRequire(CSSockAddr::EAFRequire iAFRequire)1318 	void SetAFRequire( CSSockAddr::EAFRequire iAFRequire ) { m_iAFrequire = iAFRequire; }
1319 
1320 #ifdef HAVE_LIBSSL
1321 	//! set the cipher strength to use, default is HIGH
SetCipher(const CS_STRING & s)1322 	void SetCipher( const CS_STRING & s ) { m_sCipher = s; }
1323 	//! set the location of the pemfile
SetPemLocation(const CS_STRING & s)1324 	void SetPemLocation( const CS_STRING & s ) { m_sPemLocation = s; }
1325 	//! set the pemfile pass
SetPemPass(const CS_STRING & s)1326 	void SetPemPass( const CS_STRING & s ) { m_sPemPass = s; }
1327 #endif /* HAVE_LIBSSL */
1328 
1329 protected:
1330 	CS_STRING	m_sHostname, m_sSockName, m_sBindHost;
1331 	uint16_t	m_iPort;
1332 	int			m_iTimeout;
1333 	bool		m_bIsSSL;
1334 	CSSockAddr::EAFRequire	m_iAFrequire;
1335 #ifdef HAVE_LIBSSL
1336 	CS_STRING	m_sDHParamLocation, m_sKeyLocation, m_sPemLocation, m_sPemPass, m_sCipher;
1337 #endif /* HAVE_LIBSSL */
1338 };
1339 
1340 class CS_EXPORT CSSSLConnection : public CSConnection
1341 {
1342 public:
1343 	CSSSLConnection( const CS_STRING & sHostname, uint16_t iPort, int iTimeout = 60 ) :
CSConnection(sHostname,iPort,iTimeout)1344 		CSConnection( sHostname, iPort, iTimeout )
1345 	{
1346 		SetIsSSL( true );
1347 	}
1348 };
1349 
1350 
1351 /**
1352  * @class CSListener
1353  * @brief options container to create a listener
1354  */
1355 class CS_EXPORT CSListener
1356 {
1357 public:
1358 	/**
1359 	 * @param iPort port to listen on. Set to 0 to listen on a random port
1360 	 * @param sBindHost host to bind to
1361 	 * @param bDetach don't block while waiting for the port to come up, instead detach and return immediately
1362 	 */
1363 	CSListener( uint16_t iPort, const CS_STRING & sBindHost = "", bool bDetach = false )
1364 	{
1365 		m_iPort = iPort;
1366 		m_sBindHost = sBindHost;
1367 		m_bIsSSL = false;
1368 		m_iMaxConns = SOMAXCONN;
1369 		m_iTimeout = 0;
1370 		m_iAFrequire = CSSockAddr::RAF_ANY;
1371 		m_bDetach = bDetach;
1372 #ifdef HAVE_LIBSSL
1373 		m_sCipher = "HIGH";
1374 		m_iRequireCertFlags = 0;
1375 #endif /* HAVE_LIBSSL */
1376 	}
~CSListener()1377 	virtual ~CSListener() {}
1378 
SetDetach(bool b)1379 	void SetDetach( bool b ) { m_bDetach = b; }
GetDetach()1380 	bool GetDetach() const { return( m_bDetach ); }
GetPort()1381 	uint16_t GetPort() const { return( m_iPort ); }
GetSockName()1382 	const CS_STRING & GetSockName() const { return( m_sSockName ); }
GetBindHost()1383 	const CS_STRING & GetBindHost() const { return( m_sBindHost ); }
GetIsSSL()1384 	bool GetIsSSL() const { return( m_bIsSSL ); }
GetMaxConns()1385 	int GetMaxConns() const { return( m_iMaxConns ); }
GetTimeout()1386 	uint32_t GetTimeout() const { return( m_iTimeout ); }
GetAFRequire()1387 	CSSockAddr::EAFRequire GetAFRequire() const { return( m_iAFrequire ); }
1388 #ifdef HAVE_LIBSSL
GetCipher()1389 	const CS_STRING & GetCipher() const { return( m_sCipher ); }
GetDHParamLocation()1390 	const CS_STRING & GetDHParamLocation() const { return( m_sDHParamLocation ); }
GetKeyLocation()1391 	const CS_STRING & GetKeyLocation() const { return( m_sKeyLocation ); }
GetPemLocation()1392 	const CS_STRING & GetPemLocation() const { return( m_sPemLocation ); }
GetPemPass()1393 	const CS_STRING & GetPemPass() const { return( m_sPemPass ); }
GetRequireClientCertFlags()1394 	uint32_t GetRequireClientCertFlags() const { return( m_iRequireCertFlags ); }
1395 #endif /* HAVE_LIBSSL */
1396 
1397 	//! sets the port to listen on. Set to 0 to listen on a random port
SetPort(uint16_t iPort)1398 	void SetPort( uint16_t iPort ) { m_iPort = iPort; }
1399 	//! sets the sock name for later reference (ie FindSockByName)
SetSockName(const CS_STRING & sSockName)1400 	void SetSockName( const CS_STRING & sSockName ) { m_sSockName = sSockName; }
1401 	//! sets the host to bind to
SetBindHost(const CS_STRING & sBindHost)1402 	void SetBindHost( const CS_STRING & sBindHost ) { m_sBindHost = sBindHost; }
1403 	//! set to true to enable SSL
SetIsSSL(bool b)1404 	void SetIsSSL( bool b ) { m_bIsSSL = b; }
1405 	//! set max connections as called by accept()
SetMaxConns(int i)1406 	void SetMaxConns( int i ) { m_iMaxConns = i; }
1407 	//! sets the listen timeout. The listener class will close after timeout has been reached if not 0
SetTimeout(uint32_t i)1408 	void SetTimeout( uint32_t i ) { m_iTimeout = i; }
1409 	//! sets the AF family type required
SetAFRequire(CSSockAddr::EAFRequire iAFRequire)1410 	void SetAFRequire( CSSockAddr::EAFRequire iAFRequire ) { m_iAFrequire = iAFRequire; }
1411 
1412 #ifdef HAVE_LIBSSL
1413 	//! set the cipher strength to use, default is HIGH
SetCipher(const CS_STRING & s)1414 	void SetCipher( const CS_STRING & s ) { m_sCipher = s; }
1415 	//! set the location of the pemfile
SetPemLocation(const CS_STRING & s)1416 	void SetPemLocation( const CS_STRING & s ) { m_sPemLocation = s; }
1417 	//! set the location of the keyfile
SetKeyLocation(const CS_STRING & s)1418 	void SetKeyLocation( const CS_STRING & s ) { m_sKeyLocation = s; }
1419 	//! set the location of the dhparamfile
SetDHParamLocation(const CS_STRING & s)1420 	void SetDHParamLocation( const CS_STRING & s ) { m_sDHParamLocation = s; }
1421 	//! set the pemfile pass
SetPemPass(const CS_STRING & s)1422 	void SetPemPass( const CS_STRING & s ) { m_sPemPass = s; }
1423 	//! set to true if require a client certificate (deprecated @see SetRequireClientCertFlags)
SetRequiresClientCert(bool b)1424 	void SetRequiresClientCert( bool b ) { m_iRequireCertFlags = ( b ? SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0 ); }
1425 	//! bitwise flags, 0 means don't require cert, SSL_VERIFY_PEER verifies peers, SSL_VERIFY_FAIL_IF_NO_PEER_CERT will cause the connection to fail if no cert
SetRequireClientCertFlags(unsigned int iRequireCertFlags)1426 	void SetRequireClientCertFlags( unsigned int iRequireCertFlags ) { m_iRequireCertFlags = iRequireCertFlags; }
1427 #endif /* HAVE_LIBSSL */
1428 private:
1429 	uint16_t	m_iPort;
1430 	CS_STRING	m_sSockName, m_sBindHost;
1431 	bool		m_bIsSSL;
1432 	bool		m_bDetach;
1433 	int			m_iMaxConns;
1434 	uint32_t	m_iTimeout;
1435 	CSSockAddr::EAFRequire	m_iAFrequire;
1436 
1437 #ifdef HAVE_LIBSSL
1438 	CS_STRING	m_sDHParamLocation, m_sKeyLocation, m_sPemLocation, m_sPemPass, m_sCipher;
1439 	uint32_t		m_iRequireCertFlags;
1440 #endif /* HAVE_LIBSSL */
1441 };
1442 
1443 #ifdef HAVE_LIBSSL
1444 class CSSSListener : public CSListener
1445 {
1446 public:
1447 	CSSSListener( uint16_t iPort, const CS_STRING & sBindHost = "" ) :
CSListener(iPort,sBindHost)1448 		CSListener( iPort, sBindHost )
1449 	{
1450 		SetIsSSL( true );
1451 	}
1452 };
1453 #endif /* HAVE_LIBSSL */
1454 
1455 /**
1456  * @class CSocketManager
1457  * @brief Best class to use to interact with the sockets
1458  *
1459  * Handles SSL and NON Blocking IO.
1460  * Rather then use it directly, you'll probably get more use deriving from it.
1461  * Override GetSockObj since Csock derivatives need to be new'd correctly.
1462  * Makes it easier to use overall.
1463  * Another thing to note, is that all sockets are deleted implicitly, so obviously you
1464  * can't pass in Csock classes created on the stack. For those of you who don't
1465  * know STL very well, the reason I did this is because whenever you add to certain stl containers
1466  * (e.g. vector, or map), it is completely rebuilt using the copy constructor on each element.
1467  * That then means the constructor and destructor are called on every item in the container.
1468  * Not only is this more overhead then just moving pointers around, its dangerous as if you have
1469  * an object that is newed and deleted in the destructor the value of its pointer is copied in the
1470  * default copy constructor. This means everyone has to know better and create a copy constructor,
1471  * or I just make everyone new their object :).
1472  *
1473  * @see TSocketManager
1474  * @author Jim Hull <csocket@jimloco.com>
1475  */
1476 class CS_EXPORT CSocketManager : public std::vector<Csock *>, public CSockCommon
1477 {
1478 public:
1479 	CSocketManager();
1480 	virtual ~CSocketManager();
1481 	virtual void clear();
1482 	virtual void Cleanup();
1483 
1484 	virtual Csock * GetSockObj( const CS_STRING & sHostname, uint16_t uPort, int iTimeout = 60 );
1485 
1486 	enum EMessages
1487 	{
1488 	    SUCCESS			= 0,	//!< Select returned at least 1 fd ready for action
1489 	    SELECT_ERROR	= -1,	//!< An Error Happened, Probably dead socket. That socket is returned if available
1490 	    SELECT_TIMEOUT	= -2,	//!< Select Timeout
1491 	    SELECT_TRYAGAIN	= -3	//!< Select calls for you to try again
1492 	};
1493 
1494 	/**
1495 	 * @brief Create a connection
1496 	 * @param cCon the connection which should be established
1497 	 * @param pcSock the socket used for the connection, can be NULL
1498 	 */
1499 	void Connect( const CSConnection & cCon, Csock * pcSock = NULL );
1500 
1501 	/**
1502 	 * @brief Sets up a listening socket
1503 	 * @param cListen the listener configuration
1504 	 * @param pcSock preconfigured sock to use
1505 	 * @param piRandPort if listener is set to port 0, then a random port is used and this is assigned.
1506 	 *
1507 	 * IF you provide piRandPort to be assigned, AND you set bDetach to true, then Listen() still blocks. If you don't want this
1508 	 * behavior, then look for the port assignment to be called in Csock::Listening
1509 	 */
1510 	virtual bool Listen( const CSListener & cListen, Csock * pcSock = NULL, uint16_t * piRandPort = NULL );
1511 
1512 
1513 	//! simple method to see if there are file descriptors being processed, useful to know if all the work is done in the manager
1514 	bool HasFDs() const;
1515 
1516 	/**
1517 	 * Best place to call this class for running, all the call backs are called.
1518 	 * You should through this in your main while loop (long as its not blocking)
1519 	 * all the events are called as needed.
1520 	 */
1521 	virtual void Loop();
1522 
1523 	/**
1524 	 * @brief this is similar to loop, except that it dynamically adjusts the select time based on jobs and timeouts in sockets
1525 	 *
1526 	 *	- This type of behavior only works well in a scenario where there is low traffic. If you use this then its because you
1527 	 *	- are trying to spare yourself some of those idle loops where nothing is done. If you try to use this code where you have lots of
1528 	 *	- connections and/or lots of traffic you might end up causing more CPU usage than just a plain Loop() with a static sleep of 500ms
1529 	 *	- its a trade off at some point, and you'll probably find out that the vast majority of the time and in most cases Loop() works fine
1530 	 *	- by itself. I've tried to mitigate that as much as possible by not having it change the select if the previous call to select
1531 	 *	- was not a timeout. Anyways .... Caveat Emptor.
1532 	 *	- Sample useage is cFoo.DynamicSelectLoop( 500000, 5000000 ); which basically says min of 500ms and max of 5s
1533 	 *
1534 	 * @param iLowerBounds the lower bounds to use in MICROSECONDS
1535 	 * @param iUpperBounds the upper bounds to use in MICROSECONDS
1536 	 * @param iMaxResolution the maximum time to calculate overall in seconds
1537 	 */
1538 	void DynamicSelectLoop( uint64_t iLowerBounds, uint64_t iUpperBounds, time_t iMaxResolution = 3600 );
1539 
1540 	/**
1541 	 * Make this method virtual, so you can override it when a socket is added.
1542 	 * Assuming you might want to do some extra stuff
1543 	 */
1544 	virtual void AddSock( Csock * pcSock, const CS_STRING & sSockName );
1545 
1546 	//! returns a pointer to the FIRST sock found by port or NULL on no match
1547 	virtual Csock * FindSockByRemotePort( uint16_t iPort );
1548 
1549 	//! returns a pointer to the FIRST sock found by port or NULL on no match
1550 	virtual Csock * FindSockByLocalPort( uint16_t iPort );
1551 
1552 	//! returns a pointer to the FIRST sock found by name or NULL on no match
1553 	virtual Csock * FindSockByName( const CS_STRING & sName );
1554 
1555 	//! returns a pointer to the FIRST sock found by filedescriptor or NULL on no match
1556 	virtual Csock * FindSockByFD( cs_sock_t iFD );
1557 
1558 	virtual std::vector<Csock *> FindSocksByName( const CS_STRING & sName );
1559 
1560 	//! returns a vector of pointers to socks with sHostname as being connected
1561 	virtual std::vector<Csock *> FindSocksByRemoteHost( const CS_STRING & sHostname );
1562 
1563 	//! return the last known error as set by this class
GetErrno()1564 	int GetErrno() const { return( m_errno ); }
1565 
1566 	//! Get the Select Timeout in MICROSECONDS ( 1000 == 1 millisecond )
GetSelectTimeout()1567 	uint64_t GetSelectTimeout() const { return( m_iSelectWait ); }
1568 	//! Set the Select Timeout in MICROSECONDS ( 1000 == 1 millisecond )
1569 	//! Setting this to 0 will cause no timeout to happen, Select() will return instantly
SetSelectTimeout(uint64_t iTimeout)1570 	void  SetSelectTimeout( uint64_t iTimeout ) { m_iSelectWait = iTimeout; }
1571 
1572 	//! Delete a sock by addr
1573 	//! its position is looked up
1574 	//! the socket is deleted, the appropriate call backs are peformed
1575 	//! and its instance is removed from the manager
1576 	virtual void DelSockByAddr( Csock * pcSock );
1577 
1578 	//! Delete a sock by position in the vector
1579 	//! the socket is deleted, the appropriate call backs are peformed
1580 	//! and its instance is removed from the manager
1581 	//! deleting in a loop can be tricky, be sure you watch your position.
1582 	//! ie for( uint32_t a = 0; a < size(); a++ ) DelSock( a-- );
1583 	virtual void DelSock( size_t iPos );
1584 
1585 	/**
1586 	 * @brief swaps out a sock with a copy of the original sock
1587 	 * @param pNewSock the new sock to change out with. (this should be constructed by you with the default ctor)
1588 	 * @param iOrginalSockIdx the position in this sockmanager of the original sock
1589 	 * @return true on success
1590 	 */
1591 	virtual bool SwapSockByIdx( Csock * pNewSock, size_t iOrginalSockIdx );
1592 
1593 	/**
1594 	 * @brief swaps out a sock with a copy of the original sock
1595 	 * @param pNewSock the new sock to change out with. (this should be constructed by you with the default ctor)
1596 	 * @param pOrigSock the address of the original socket
1597 	 * @return true on success
1598 	 */
1599 	virtual bool SwapSockByAddr( Csock * pNewSock, Csock * pOrigSock );
1600 
1601 	//! Get the bytes read from all sockets current and past
1602 	uint64_t GetBytesRead() const;
1603 
1604 	//! Get the bytes written to all sockets current and past
1605 	uint64_t GetBytesWritten() const;
1606 
1607 	//! this is a strict wrapper around C-api select(). Added in the event you need to do special work here
1608 	enum ECheckType
1609 	{
1610 	    ECT_Read = 1,
1611 	    ECT_Write = 2
1612 	};
1613 
1614 	void FDSetCheck( cs_sock_t iFd, std::map< cs_sock_t, short > & miiReadyFds, ECheckType eType );
1615 	bool FDHasCheck( cs_sock_t iFd, std::map< cs_sock_t, short > & miiReadyFds, ECheckType eType );
1616 
1617 protected:
1618 
1619 	virtual int Select( std::map< cs_sock_t, short > & miiReadyFds, struct timeval *tvtimeout );
1620 
1621 private:
1622 	/**
1623 	 * @brief fills a map of socks to a message for check
1624 	 * map is empty if none are ready, check GetErrno() for the error, if not SUCCESS Select() failed
1625 	 * each struct contains the socks error
1626 	 * @see GetErrno()
1627 	 */
1628 	void Select( std::map<Csock *, EMessages> & mpeSocks );
1629 
1630 	timeval GetDynamicSleepTime( const timeval& tNow, const timeval& tMaxResolution ) const;
1631 
1632 	//! internal use only
1633 	virtual void SelectSock( std::map<Csock *, EMessages> & mpeSocks, EMessages eErrno, Csock * pcSock );
1634 
1635 	////////
1636 	// Connection State Functions
1637 
1638 	///////////
1639 	// members
1640 	EMessages		m_errno;
1641 	uint64_t		m_iCallTimeouts;
1642 	uint64_t		m_iBytesRead;
1643 	uint64_t		m_iBytesWritten;
1644 	uint64_t		m_iSelectWait;
1645 };
1646 
1647 
1648 /**
1649  * @class TSocketManager
1650  * @brief Ease of use templated socket manager
1651  *
1652  * class CBlahSock : public TSocketManager<SomeSock>
1653  */
1654 template<class T>
1655 class TSocketManager : public CSocketManager
1656 {
1657 public:
TSocketManager()1658 	TSocketManager() : CSocketManager() {}
~TSocketManager()1659 	virtual ~TSocketManager() {}
1660 	virtual T * GetSockObj( const CS_STRING & sHostname, uint16_t uPort, int iTimeout = 60 )
1661 	{
1662 		return( new T( sHostname, uPort, iTimeout ) );
1663 	}
1664 };
1665 
1666 #ifndef _NO_CSOCKET_NS
1667 }
1668 #endif /* _NO_CSOCKET_NS */
1669 
1670 #endif /* _HAS_CSOCKET_ */
1671 
1672