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