privacore-open-source-searc.../TcpServer.h
2017-11-16 17:19:43 +01:00

198 lines
7.7 KiB
C++

// Copyright Matt Wells Nov 2000
// . TODO: don't keep alloc'ing TcpSockets, re-use "empty" TcpSockets from
// an array of them (grow array if needed) (do same for UdpServer)
// . used as client AND server
// . used to do non-blocking sends/recieves of messages using TCP/IP
// . re-uses sockets (keep alive) in server AND client directions
// . uses custom dns client (Dns.h) for non-blocking domain name lookups
// . a callback can be specified for each TcpSocket
// . a pointer to custom callback data can also be specified for each socket
// . that callback is called on connect/read/write/dnsLookup TIMEOUT or ERROR
// . callback is also called on reception of REPLY
// . receptions of REQUESTS are received thru TcpSocket*TcpServer::read(int sd)
// . if a msg being received is too big we make call(s) to putMsgPiece() to
// empty the receive buffer when it gets full (m_maxReadBufSize)
#ifndef GB_TCPSERVER_H
#define GB_TCPSERVER_H
#include <openssl/ssl.h> // for ssl stuff
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <atomic>
#include "TcpSocket.h"
// raised from 5k to 15k in case we are a spider compression proxy
#define MAX_TCP_SOCKS 15000
class TcpServer {
friend class HttpServer;
public:
// free all TcpSockets and their bufs
void reset();
TcpServer();
// . creates a tcp socket which listens on port "port"
// . will close unused sockets to ensure we stay under "maxSockets"
// . receiving msgs bigger then "16k" will result in a call to
// TcpSocket::putMsgPiece(), if not NULL
// . we call "requestHandler" when an incoming request arrives
// . IMPORTANT: requestHandler MUST call sendMsg(s,...) eventually
// . getMsgSize is called to get the total size of an incoming msg
// . it returns -1 if it doesn't yet know
bool init ( void (* requestHandler)(TcpSocket *s) ,
int32_t (* getMsgSize )(const char *msg, int32_t msgBytesRead, TcpSocket *s),
int32_t (* getMsgPiece )(TcpSocket *s ),
int16_t port ,
int32_t *maxSocketsPtr = NULL , //MAX_TCP_SOCS def
bool useSSL = false );
//int32_t maxReadBufSize = 128*1024 ,
//int32_t maxSendBufSize = 128*1024 );
bool testBind ( uint16_t port , bool printMsg ) ;
// . returns false if blocked, true otherwise
// . sets errno on error
// . uses g_dns to find the ip then calls sendRequest() below
// . callback is called on completion of TRANSACTION
// . that is, when both m_sendBuf and m_readBuf have been filled
// . callback is also called on error
// . default timeout of 60 secs of no read OR no write
bool sendMsg( const char *hostname, int32_t hostnameLen, int16_t port, char *sendBuf, int32_t sendBufSize,
int32_t sendBufUsed, int32_t msgTotalSize, void *state,
void ( *callback )( void *state, TcpSocket *s ), int32_t timeout, int32_t maxTextDocLen,
int32_t maxOtherDocLen );
bool sendChunk( class TcpSocket *s, class SafeBuf *sb, void *state,
// call this function when done sending this chunk
// so that it can read another chunk and call
// sendChunk() again.
void ( *doneSendingWrapper )( void *state, TcpSocket * ) );
// . returns false if blocked, true otherwise
// . sets errno on error
// . use this for sending a msg to another host
// . if a reply is expected then you should specify the "done" callback
// which will be called on complete reception of the reply
// . after completion/done this will call reseTcpSocket()
// . upon successful transmision of "msg" we shift socket into readMode
// . default timeout of 60 secs of no read OR no write
bool sendMsg( const char *hostname, int32_t hostnameLen, int32_t ip, int16_t port, char *sendBuf,
int32_t sendBufSize, int32_t sendBufUsed, int32_t msgTotalSize, void *state,
void ( *callback )( void *state, TcpSocket *s ), int32_t timeout, int32_t maxTextDocLen,
int32_t maxOtherDocLen, bool useHttpTunnel = false );
// . send request over an available (pre-connected) TcpSocket
// . destroys the socket on error
// . calls callback on completion of transaction
// . default timeout of 60 secs of no read OR no write
bool sendMsg( TcpSocket *s, char *sendBuf, int32_t sendBufSize, int32_t sendBufUsed, int32_t msgTotalSize,
void *state, void ( *callback )( void *state, TcpSocket *s ), int32_t timeout = 60 * 1000,
int32_t maxTextDocLen = -1, int32_t maxOtherDocLen = -1 );
// . the following public funcs are public so C wrappers can call them
// . you should not call them
// . we use this as a callback called by DnsServer
// . gotta keep this public cuz getIpWrapper() calls it
// . returns true if didn't block when sending msg (using sendRequest)
bool gotTcpServerIp ( class TcpState *tst , int32_t ip );
// get a TcpSocket from a socket descriptor
TcpSocket *getSocket ( int sd ) ;
int32_t readSocket ( TcpSocket *s );
int32_t writeSocket ( TcpSocket *s );
void readTimeoutPoll ( ) ;
TcpSocket *acceptSocket ( ) ;
bool sslAccept ( class TcpSocket *s ) ;
// keep public so PageResults can call if had error getting query results
void destroySocket ( TcpSocket *s ) ;
// calls s->m_callback ( s->m_state , s )
void makeCallback ( TcpSocket * s ) ;
void recycleSocket ( TcpSocket *s ) ;
// only wrappers should call this
int32_t connectSocket ( TcpSocket *s ) ;
// set from init() to handle incoming requests
void (* m_requestHandler)(TcpSocket *s) ;
// cancel the transaction that had this state
void cancel ( void *state );
// void (*callback)(void *state, TcpSocket *s) ) ;
// private:
TcpSocket *getAvailableSocket ( int32_t ip, int16_t port ) ;
TcpSocket *getNewSocket ( ) ;
TcpSocket *wrapSocket ( int sd , int32_t niceness, bool incoming);
bool closeLeastUsed ( int32_t maxIdleTime = -1 ) ;
bool setTotalToRead ( TcpSocket *s ) ;
int sslHandshake ( TcpSocket *s ) ;
// . we call this to try to figure out the size of the WHOLE msg
// being read so that we might pre-allocate memory for it
// . overriden for different protocols
// . this is called upon reception of every packet
// of the msg being read until a non-negative msg size is returned.
// this is used to avoid doing excessive reallocs and extract the
// reply size from things like "Content-Length: xxx" so we can do
// one alloc() and forget about having to do more...
// . up to 128 bytes of the reply can be stored in a static buffer
// contained in TcpSocket, until we need to alloc...
// virtual int32_t getMsgSize ( char *buf , int32_t bufSize ) ;
int m_sock ; // for listening for connections
int16_t m_port ; // for listening for connections
// handlers set in the init() routine
// ptrs to our TcpSockets 1-1 w/ real sockets
TcpSocket *m_tcpSockets [ MAX_TCP_SOCKS ];
int32_t m_lastFilled;
std::atomic<int32_t> m_numUsed;
// # used for incoming connections
int32_t m_numIncomingUsed;
// let's have them all pre-allocated, it's only ~1.1MB...
TcpSocket m_actualSockets [ MAX_TCP_SOCKS ];
// . how many socket descriptors can we use simultaneously?
// . just applies to incoming sockets
int32_t m_dummy;
int32_t *m_maxSocketsPtr;
bool m_doReadRateTimeouts;
// these callbacks should be set in init()
int32_t (* m_getMsgSize )(const char *msg, int32_t msgBytesRead, TcpSocket *s);
int32_t (* m_getMsgPiece )(TcpSocket *s );
// flag to specify SSL or not
bool m_useSSL;
// SSL members
SSL_CTX *m_ctx;
// ready to go or not
bool m_ready;
int32_t m_numOpen;
int32_t m_numClosed;
};
#endif // GB_TCPSERVER_H