mirror of
https://github.com/stefanocasazza/ULib.git
synced 2025-09-28 19:05:55 +08:00
825 lines
30 KiB
C++
825 lines
30 KiB
C++
// ============================================================================
|
|
//
|
|
// = LIBRARY
|
|
// ULib - c++ library
|
|
//
|
|
// = FILENAME
|
|
// server.h
|
|
//
|
|
// = AUTHOR
|
|
// Stefano Casazza
|
|
//
|
|
// ============================================================================
|
|
|
|
#ifndef U_SERVER_H
|
|
#define U_SERVER_H 1
|
|
|
|
#include <ulib/log.h>
|
|
#include <ulib/process.h>
|
|
#include <ulib/command.h>
|
|
#include <ulib/notifier.h>
|
|
#include <ulib/file_config.h>
|
|
#include <ulib/utility/interrupt.h>
|
|
#include <ulib/utility/socket_ext.h>
|
|
#include <ulib/net/server/client_image.h>
|
|
#include <ulib/net/server/server_plugin.h>
|
|
|
|
/**
|
|
* @class UServer
|
|
*
|
|
* @brief Handles incoming connections.
|
|
*
|
|
* The UServer class contains the methods needed to write a portable server.
|
|
* In general, a server listens for incoming network requests on a well-known
|
|
* IP address and port number. When a connection request is received,
|
|
* the UServer makes this connection available to the server program as a socket.
|
|
* The socket represents a two-way (full-duplex) connection with the client.
|
|
*
|
|
* In common with normal socket programming, the life-cycle of a UServer follows this basic course:
|
|
* 1) bind() to an IP-address/port number and listen for incoming connections
|
|
* 2) accept() a connection request
|
|
* 3) deal with the request, or pass the created socket to another thread or process to be dealt with
|
|
* 4) return to step 2 for the next client connection request
|
|
*/
|
|
|
|
// ---------------------------------------------------------------------------------------------
|
|
// For example: U_MACROSERVER(UServerExample, UClientExample, UTCPSocket);
|
|
// ---------------------------------------------------------------------------------------------
|
|
#if defined(DEBUG) && defined(U_STDCPP_ENABLE)
|
|
# define U_MACROSERVER(server_class,client_type,socket_type) \
|
|
class server_class : public UServer<socket_type> { \
|
|
public: \
|
|
server_class(UFileConfig* pcfg) : UServer<socket_type>(pcfg) { U_TRACE_REGISTER_OBJECT( 5, server_class, "%p", pcfg) } \
|
|
~server_class() { U_TRACE_UNREGISTER_OBJECT(5, server_class) } \
|
|
const char* dump(bool reset) const { return UServer<socket_type>::dump(reset); } \
|
|
protected: \
|
|
virtual void preallocate() U_DECL_FINAL { \
|
|
U_TRACE(5+256, #server_class "::preallocate()") \
|
|
vClientImage = new client_type[UNotifier::max_connection]; } \
|
|
virtual void deallocate() U_DECL_FINAL { \
|
|
U_TRACE(5+256, #server_class "::deallocate()") \
|
|
delete[] (client_type*)vClientImage; } \
|
|
virtual bool check_memory() U_DECL_FINAL { return u_check_memory_vector<client_type>((client_type*)vClientImage, UNotifier::max_connection); } }
|
|
#else
|
|
# define U_MACROSERVER(server_class,client_type,socket_type) \
|
|
class server_class : public UServer<socket_type> { \
|
|
public: \
|
|
server_class(UFileConfig* pcfg) : UServer<socket_type>(pcfg) {} \
|
|
~server_class() {} \
|
|
protected: \
|
|
virtual void preallocate() U_DECL_FINAL { \
|
|
vClientImage = new client_type[UNotifier::max_connection]; } }
|
|
#endif
|
|
// ---------------------------------------------------------------------------------------------
|
|
|
|
// manage server write to log
|
|
|
|
#define U_SERVER_LOG_PREFIX "(pid %P)> "
|
|
|
|
#ifdef U_LOG_DISABLE
|
|
# define U_RESET_MODULE_NAME
|
|
# define U_SET_MODULE_NAME(name)
|
|
|
|
# define U_SRV_LOG( fmt,args...) {}
|
|
# define U_SRV_LOG_WITH_ADDR(fmt,args...) {}
|
|
#else
|
|
# define U_LOG_ENABLE
|
|
# define U_RESET_MODULE_NAME { if (UServer_Base::isLog()) (void) strcpy(UServer_Base::mod_name[0], UServer_Base::mod_name[1]); }
|
|
# define U_SET_MODULE_NAME(name) { if (UServer_Base::isLog()) { (void) strcpy(UServer_Base::mod_name[1], UServer_Base::mod_name[0]); \
|
|
(void) strcpy(UServer_Base::mod_name[0], "["#name"] "); } }
|
|
|
|
# define U_SRV_LOG( fmt,args...) { if (UServer_Base::isLog()) ULog::log("%s" fmt, UServer_Base::mod_name[0] , ##args); }
|
|
# define U_SRV_LOG_WITH_ADDR(fmt,args...) { if (UServer_Base::isLog()) ULog::log("%s" fmt " %v", UServer_Base::mod_name[0] , ##args, UServer_Base::pClientImage->logbuf->rep); }
|
|
#endif
|
|
|
|
class UHTTP;
|
|
class UHTTP2;
|
|
class UCommand;
|
|
class USSLSocket;
|
|
class USSIPlugIn;
|
|
class UWebSocket;
|
|
class USocketExt;
|
|
class Application;
|
|
class UTimeThread;
|
|
class UFileConfig;
|
|
class UHttpPlugIn;
|
|
class UFCGIPlugIn;
|
|
class USCGIPlugIn;
|
|
class UNoCatPlugIn;
|
|
class UGeoIPPlugIn;
|
|
class UClient_Base;
|
|
class UProxyPlugIn;
|
|
class UStreamPlugIn;
|
|
class UModNoCatPeer;
|
|
class UClientThread;
|
|
class UOCSPStapling;
|
|
class UHttpClient_Base;
|
|
class UWebSocketPlugIn;
|
|
class UModProxyService;
|
|
|
|
class U_EXPORT UServer_Base : public UEventFd {
|
|
public:
|
|
|
|
// Check for memory error
|
|
U_MEMORY_TEST
|
|
|
|
// Allocator e Deallocator
|
|
U_MEMORY_ALLOCATOR
|
|
U_MEMORY_DEALLOCATOR
|
|
|
|
// -----------------------------------------------------------------------------------------------------------------------------
|
|
// UServer - configuration parameters
|
|
// -----------------------------------------------------------------------------------------------------------------------------
|
|
// ENABLE_IPV6 flag indicating the use of ipv6
|
|
// SERVER host name or ip address for the listening socket
|
|
// PORT port number for the listening socket
|
|
// SOCKET_NAME file name for the listening socket
|
|
// IP_ADDRESS ip address of host for the interface connected to the Internet (autodetected if not specified)
|
|
//
|
|
// ALLOWED_IP list of comma separated client address for IP-based access control (IPADDR[/MASK])
|
|
// ALLOWED_IP_PRIVATE list of comma separated client private address for IP-based access control (IPADDR[/MASK]) for public server
|
|
// ENABLE_RFC1918_FILTER reject request from private IP to public server address
|
|
// MIN_SIZE_FOR_SENDFILE for major size it is better to use sendfile() to serve static content
|
|
//
|
|
// LISTEN_BACKLOG max number of ready to be delivered connections to accept()
|
|
// SET_REALTIME_PRIORITY flag indicating that the preforked processes will be scheduled under the real-time policies SCHED_FIFO
|
|
//
|
|
// CLIENT_THRESHOLD min number of clients to active polling
|
|
// CLIENT_FOR_PARALLELIZATION min number of clients to active parallelization
|
|
//
|
|
// PID_FILE write pid on file indicated
|
|
// WELCOME_MSG message of welcome to send initially to client
|
|
// RUN_AS_USER downgrade the privileges to that of user account
|
|
// DOCUMENT_ROOT The directory out of which you will serve your documents
|
|
//
|
|
// LOG_FILE locations for file log
|
|
// LOG_FILE_SZ memory size for file log
|
|
// LOG_MSG_SIZE limit length of print network message to LOG_MSG_SIZE chars (default 128)
|
|
//
|
|
// PLUGIN list of plugins to load, a flexible way to add specific functionality to the server
|
|
// PLUGIN_DIR directory where there are plugins to load
|
|
//
|
|
// ORM_DRIVER list of ORM drivers to load, a flexible way to add specific functionality to the ORM
|
|
// ORM_DRIVER_DIR directory where there are ORM drivers to load
|
|
//
|
|
// REQ_TIMEOUT timeout for request from client
|
|
// MAX_KEEP_ALIVE Specifies the maximum number of requests that can be served through a Keep-Alive (Persistent) session.
|
|
// (Value <= 0 will disable Keep-Alive)
|
|
//
|
|
// DH_FILE dh param (these are the bit DH parameters from "Assigned Number for SKIP Protocols")
|
|
// CERT_FILE server certificate
|
|
// KEY_FILE server private key
|
|
// PASSWORD password for server private key
|
|
// CA_FILE locations of trusted CA certificates used in the verification
|
|
// CA_PATH locations of trusted CA certificates used in the verification
|
|
// VERIFY_MODE mode of verification (SSL_VERIFY_NONE=0, SSL_VERIFY_PEER=1, SSL_VERIFY_FAIL_IF_NO_PEER_CERT=2, SSL_VERIFY_CLIENT_ONCE=4)
|
|
//
|
|
// PREFORK_CHILD number of child server processes created at startup ( 0 - serialize, no forking
|
|
// 1 - classic, forking after client accept
|
|
// >1 - pool of serialized processes plus monitoring process)
|
|
// -----------------------------------------------------------------------------------------------------------------------------
|
|
|
|
static void run(); // loop waiting for connection
|
|
|
|
// tipologia server...
|
|
|
|
static bool bssl, bipc;
|
|
static UFileConfig* cfg;
|
|
static unsigned int port; // the port number to bind to
|
|
|
|
static int getReqTimeout() { return (ptime ? ptime->UTimeVal::tv_sec : 0); }
|
|
static bool isIPv6() { return UClientImage_Base::bIPv6; }
|
|
static UString getHost() { return *host; }
|
|
static unsigned int getPort() { return port; }
|
|
|
|
static UCommand* loadConfigCommand() { return UCommand::loadConfigCommand(cfg); }
|
|
|
|
// The directory out of which you will serve your documents...
|
|
|
|
static UString* document_root;
|
|
static uint32_t document_root_size;
|
|
static const char* document_root_ptr;
|
|
|
|
static UString getDocumentRoot()
|
|
{
|
|
U_TRACE(0, "UServer_Base::getDocumentRoot()")
|
|
|
|
U_INTERNAL_ASSERT_POINTER(document_root)
|
|
|
|
U_RETURN_STRING(*document_root);
|
|
}
|
|
|
|
static bool setDocumentRoot(const UString& dir);
|
|
|
|
#ifdef U_WELCOME_SUPPORT
|
|
static void setMsgWelcome(const UString& msg);
|
|
#endif
|
|
|
|
// -------------------------------------------------------------------
|
|
// MANAGE PLUGIN MODULES
|
|
// -------------------------------------------------------------------
|
|
|
|
static char mod_name[2][16];
|
|
static UEventFd* handler_other;
|
|
static UEventFd* handler_inotify;
|
|
|
|
// load plugin modules and call server-wide hooks handlerConfig()...
|
|
static int loadPlugins(UString& plugin_dir, const UString& plugin_list);
|
|
|
|
// ---------------------------------
|
|
// Server-wide hooks
|
|
// ---------------------------------
|
|
static int pluginsHandlerInit();
|
|
static int pluginsHandlerRun();
|
|
static int pluginsHandlerFork();
|
|
static int pluginsHandlerStop();
|
|
// ---------------------------------
|
|
// Connection-wide hooks
|
|
// ---------------------------------
|
|
static int pluginsHandlerREAD();
|
|
static int pluginsHandlerRequest();
|
|
static int pluginsHandlerReset();
|
|
// ---------------------------------
|
|
// SigHUP hook
|
|
// ---------------------------------
|
|
static int pluginsHandlerSigHUP();
|
|
// ---------------------------------
|
|
|
|
static void setCallerHandlerReset() { UClientImage_Base::callerHandlerReset = pluginsHandlerReset; }
|
|
static void resetCallerHandlerReset() { UClientImage_Base::callerHandlerReset = 0; }
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------------------
|
|
// Manage process server
|
|
// ----------------------------------------------------------------------------------------------------------------------------
|
|
// PREFORK_CHILD number of child server processes created at startup: -1 - thread approach (experimental)
|
|
// 0 - serialize, no forking
|
|
// 1 - classic, forking after client accept
|
|
// >1 - pool of serialized processes plus monitoring process
|
|
// ----------------------------------------------------------------------------------------------------------------------------
|
|
|
|
typedef struct shared_data {
|
|
// ---------------------------------
|
|
uint32_t cnt_user1;
|
|
uint32_t cnt_user2;
|
|
uint64_t cnt_user3;
|
|
uint64_t cnt_user4;
|
|
sig_atomic_t cnt_connection;
|
|
sig_atomic_t cnt_parallelization;
|
|
// ---------------------------------
|
|
sem_t lock_user1;
|
|
sem_t lock_user2;
|
|
sem_t lock_rdb_server;
|
|
sem_t lock_data_session;
|
|
sem_t lock_db_not_found;
|
|
char spinlock_user1[1];
|
|
char spinlock_user2[1];
|
|
char spinlock_rdb_server[1];
|
|
char spinlock_data_session[1];
|
|
char spinlock_db_not_found[1];
|
|
# ifdef USE_LIBSSL
|
|
sem_t lock_ssl_session;
|
|
char spinlock_ssl_session[1];
|
|
# if defined(ENABLE_THREAD) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB)
|
|
sem_t lock_ocsp_staple;
|
|
char spinlock_ocsp_staple[1];
|
|
# endif
|
|
# endif
|
|
// ------------------------------------------------------------------------------
|
|
# if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
|
|
pthread_rwlock_t rwlock;
|
|
struct timeval now_shared; // => u_now
|
|
ULog::log_date log_date_shared;
|
|
# endif
|
|
ULog::log_data log_data_shared;
|
|
// -> maybe unnamed array of char for gzip compression (log rotate)
|
|
// --------------------------------------------------------------------------------
|
|
} shared_data;
|
|
|
|
#define U_CNT_USER1 UServer_Base::ptr_shared_data->cnt_user1
|
|
#define U_CNT_USER2 UServer_Base::ptr_shared_data->cnt_user2
|
|
#define U_CNT_USER3 UServer_Base::ptr_shared_data->cnt_user3
|
|
#define U_CNT_USER4 UServer_Base::ptr_shared_data->cnt_user4
|
|
#define U_TOT_CONNECTION UServer_Base::ptr_shared_data->cnt_connection
|
|
#define U_CNT_PARALLELIZATION UServer_Base::ptr_shared_data->cnt_parallelization
|
|
#define U_LOCK_USER1 &(UServer_Base::ptr_shared_data->lock_user1)
|
|
#define U_LOCK_USER2 &(UServer_Base::ptr_shared_data->lock_user2)
|
|
#define U_LOCK_RDB_SERVER &(UServer_Base::ptr_shared_data->lock_rdb_server)
|
|
#define U_LOCK_SSL_SESSION &(UServer_Base::ptr_shared_data->lock_ssl_session)
|
|
#define U_LOCK_DATA_SESSION &(UServer_Base::ptr_shared_data->lock_data_session)
|
|
#define U_LOCK_DB_NOT_FOUND &(UServer_Base::ptr_shared_data->lock_db_not_found)
|
|
#define U_SPINLOCK_USER1 UServer_Base::ptr_shared_data->spinlock_user1
|
|
#define U_SPINLOCK_USER2 UServer_Base::ptr_shared_data->spinlock_user2
|
|
#define U_SPINLOCK_RDB_SERVER UServer_Base::ptr_shared_data->spinlock_rdb_server
|
|
#define U_SPINLOCK_SSL_SESSION UServer_Base::ptr_shared_data->spinlock_ssl_session
|
|
#define U_SPINLOCK_DATA_SESSION UServer_Base::ptr_shared_data->spinlock_data_session
|
|
#define U_SPINLOCK_DB_NOT_FOUND UServer_Base::ptr_shared_data->spinlock_db_not_found
|
|
|
|
static pid_t pid;
|
|
static ULock* lock_user1;
|
|
static ULock* lock_user2;
|
|
static int preforked_num_kids; // keeping a pool of children and that they accept connections themselves
|
|
static shared_data* ptr_shared_data;
|
|
static uint32_t shared_data_add, map_size;
|
|
static bool update_date, update_date1, update_date2, update_date3;
|
|
|
|
static void setLockUser1()
|
|
{
|
|
U_TRACE(0, "UServer_Base::setLockUser1()")
|
|
|
|
U_INTERNAL_ASSERT_EQUALS(lock_user1, 0)
|
|
|
|
lock_user1 = U_NEW(ULock);
|
|
|
|
lock_user1->init(&(ptr_shared_data->lock_user1), ptr_shared_data->spinlock_user1);
|
|
}
|
|
|
|
static void setLockUser2()
|
|
{
|
|
U_TRACE(0, "UServer_Base::setLockUser2()")
|
|
|
|
U_INTERNAL_ASSERT_EQUALS(lock_user2, 0)
|
|
|
|
lock_user2 = U_NEW(ULock);
|
|
|
|
lock_user2->init(&(ptr_shared_data->lock_user2), ptr_shared_data->spinlock_user2);
|
|
}
|
|
|
|
// NB: two step acquisition - first we get the offset, after the pointer...
|
|
|
|
static void* getOffsetToDataShare(uint32_t shared_data_size)
|
|
{
|
|
U_TRACE(0, "UServer_Base::getOffsetToDataShare(%u)", shared_data_size)
|
|
|
|
long offset = sizeof(shared_data) + shared_data_add;
|
|
shared_data_add += shared_data_size;
|
|
|
|
U_RETURN_POINTER(offset, void);
|
|
}
|
|
|
|
static void* getPointerToDataShare(void* shared_data_ptr)
|
|
{
|
|
U_TRACE(0, "UServer_Base::getPointerToDataShare(%p)", shared_data_ptr)
|
|
|
|
U_INTERNAL_ASSERT_POINTER(ptr_shared_data)
|
|
|
|
shared_data_ptr = (void*)((ptrdiff_t)ptr_shared_data + (ptrdiff_t)shared_data_ptr);
|
|
|
|
U_RETURN_POINTER(shared_data_ptr, void);
|
|
}
|
|
|
|
static uint32_t nClientIndex;
|
|
static UClientImage_Base* pClientImage;
|
|
static UClientImage_Base* vClientImage;
|
|
static UClientImage_Base* eClientImage;
|
|
|
|
static bool isPreForked()
|
|
{
|
|
U_TRACE(0, "UServer_Base::isPreForked()")
|
|
|
|
U_INTERNAL_DUMP("preforked_num_kids = %d", preforked_num_kids)
|
|
|
|
if (preforked_num_kids > 1) U_RETURN(true);
|
|
|
|
U_RETURN(false);
|
|
}
|
|
|
|
static bool isClassic()
|
|
{
|
|
U_TRACE(0, "UServer_Base::isClassic()")
|
|
|
|
U_INTERNAL_DUMP("preforked_num_kids = %d", preforked_num_kids)
|
|
|
|
if (preforked_num_kids == 1) U_RETURN(true);
|
|
|
|
U_RETURN(false);
|
|
}
|
|
|
|
static bool isChild()
|
|
{
|
|
U_TRACE(0, "UServer_Base::isChild()")
|
|
|
|
U_INTERNAL_DUMP("preforked_num_kids = %d", preforked_num_kids)
|
|
|
|
if (preforked_num_kids >= 1 &&
|
|
proc->child())
|
|
{
|
|
U_RETURN(true);
|
|
}
|
|
|
|
U_RETURN(false);
|
|
}
|
|
|
|
static void removeZombies();
|
|
|
|
// PARALLELIZATION
|
|
|
|
static uint32_t num_client_for_parallelization, num_client_threshold;
|
|
|
|
static bool isParallelizationChild()
|
|
{
|
|
U_TRACE(0, "UServer_Base::isParallelizationChild()")
|
|
|
|
U_INTERNAL_DUMP("U_ClientImage_parallelization = %d proc->child() = %b",
|
|
U_ClientImage_parallelization, proc->child())
|
|
|
|
if (U_ClientImage_parallelization == 1) U_RETURN(true); // 1 => child of parallelization
|
|
|
|
U_RETURN(false);
|
|
}
|
|
|
|
static bool isParallelizationParent()
|
|
{
|
|
U_TRACE(0, "UServer_Base::isParallelizationParent()")
|
|
|
|
U_INTERNAL_DUMP("U_ClientImage_parallelization = %d proc->parent() = %b",
|
|
U_ClientImage_parallelization, proc->parent())
|
|
|
|
if (U_ClientImage_parallelization == 2) U_RETURN(true); // 2 => parent of parallelization
|
|
|
|
U_RETURN(false);
|
|
}
|
|
|
|
// it creates a copy of itself, return true if parent...
|
|
|
|
static void endNewChild() __noreturn;
|
|
static pid_t startNewChild();
|
|
|
|
static bool startParallelization( uint32_t nclient = 1);
|
|
static bool isParallelizationGoingToStart(uint32_t nclient = 1) __pure;
|
|
|
|
// manage log server...
|
|
|
|
typedef struct file_LOG {
|
|
UFile* LOG;
|
|
int flags;
|
|
} file_LOG;
|
|
|
|
static ULog* log;
|
|
static ULog* apache_like_log;
|
|
static UVector<file_LOG*>* vlog;
|
|
|
|
static void closeLog();
|
|
static void reopenLog();
|
|
|
|
static bool isLog() { return (log != 0); }
|
|
static bool isOtherLog() { return (vlog->empty() == false); }
|
|
|
|
static bool addLog(UFile* log, int flags = O_APPEND | O_WRONLY);
|
|
|
|
static void logCommandMsgError(const char* cmd, bool balways);
|
|
|
|
// NETWORK CTX
|
|
|
|
static char* client_address;
|
|
static int iAddressType, socket_flags, tcp_linger_set;
|
|
static uint32_t client_address_len, min_size_for_sendfile;
|
|
|
|
#define U_CLIENT_ADDRESS_TO_PARAM UServer_Base::client_address, UServer_Base::client_address_len
|
|
#define U_CLIENT_ADDRESS_TO_TRACE UServer_Base::client_address_len, UServer_Base::client_address
|
|
|
|
static UString getIPAddress() { return *IP_address; }
|
|
static UString getNetworkDevice( const char* exclude) { return USocketExt::getNetworkDevice(exclude); }
|
|
static UString getNetworkAddress(const char* device) { return USocketExt::getNetworkAddress(socket->getFd(), device); }
|
|
|
|
// DEBUG
|
|
|
|
#if defined(DEBUG) && defined(U_STDCPP_ENABLE)
|
|
const char* dump(bool reset) const;
|
|
#endif
|
|
|
|
static USocket* socket;
|
|
static USocket* csocket;
|
|
protected:
|
|
static int timeoutMS, // the time-out value in milliseconds for client request
|
|
verify_mode; // mode of verification ssl connection
|
|
|
|
static UString* server; // host name or ip address for the listening socket
|
|
static UString* as_user; // change the current working directory to the user's home dir, and downgrade security to that user account
|
|
static UString* dh_file; // These are the 1024 bit DH parameters from "Assigned Number for SKIP Protocols"
|
|
static UString* cert_file; // locations for certificate of server
|
|
static UString* key_file; // locations for private key of server
|
|
static UString* password; // password for private key of server
|
|
static UString* ca_file; // locations of trusted CA certificates used in the verification
|
|
static UString* ca_path; // locations of trusted CA certificates used in the verification
|
|
static UString* name_sock; // name file for the listening socket
|
|
static UString* IP_address; // IP address of this server
|
|
|
|
static UString* host;
|
|
static sigset_t mask;
|
|
static UProcess* proc;
|
|
static UEventTime* ptime;
|
|
static time_t last_event;
|
|
static int rkids, old_pid;
|
|
static UServer_Base* pthis;
|
|
static UString* cenvironment;
|
|
static UString* senvironment;
|
|
static UString* str_preforked_num_kids;
|
|
static uint32_t max_depth, wakeup_for_nothing, nread, nread_again;
|
|
static bool flag_loop, flag_sigterm, monitoring_process, set_realtime_priority, public_address, binsert, set_tcp_keep_alive;
|
|
|
|
static uint32_t vplugin_size;
|
|
static UVector<UString>* vplugin_name;
|
|
static UVector<UString>* vplugin_name_static;
|
|
static UVector<UServerPlugIn*>* vplugin;
|
|
|
|
static void init();
|
|
static void loadConfigParam();
|
|
static void runLoop(const char* user);
|
|
static bool handlerTimeoutConnection(void* cimg);
|
|
|
|
#ifdef U_WELCOME_SUPPORT
|
|
static UString* msg_welcome;
|
|
#endif
|
|
|
|
#ifdef U_ACL_SUPPORT
|
|
static UString* allow_IP;
|
|
static UVector<UIPAllow*>* vallow_IP;
|
|
#endif
|
|
|
|
#ifdef U_RFC1918_SUPPORT
|
|
static UString* allow_IP_prv;
|
|
static bool enable_rfc1918_filter;
|
|
static UVector<UIPAllow*>* vallow_IP_prv;
|
|
#endif
|
|
|
|
#if defined(USE_LIBSSL) && defined(ENABLE_THREAD) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB)
|
|
static ULock* lock_ocsp_staple;
|
|
static UOCSPStapling* pthread_ocsp;
|
|
|
|
static void setLockOCSPStaple()
|
|
{
|
|
U_TRACE(0, "UServer_Base::setLockOCSPStaple()")
|
|
|
|
U_INTERNAL_ASSERT_EQUALS(lock_ocsp_staple, 0)
|
|
|
|
lock_ocsp_staple = U_NEW(ULock);
|
|
|
|
lock_ocsp_staple->init(&(ptr_shared_data->lock_ocsp_staple), ptr_shared_data->spinlock_ocsp_staple);
|
|
}
|
|
#endif
|
|
|
|
// COSTRUTTORI
|
|
|
|
UServer_Base(UFileConfig* pcfg);
|
|
virtual ~UServer_Base();
|
|
|
|
// VARIE
|
|
|
|
class U_NO_EXPORT UTimeoutConnection : public UEventTime {
|
|
public:
|
|
|
|
// COSTRUTTORI
|
|
|
|
UTimeoutConnection() : UEventTime(timeoutMS / 1000L, 0L)
|
|
{
|
|
U_TRACE_REGISTER_OBJECT(0, UTimeoutConnection, "", 0)
|
|
}
|
|
|
|
virtual ~UTimeoutConnection()
|
|
{
|
|
U_TRACE_UNREGISTER_OBJECT(0, UTimeoutConnection)
|
|
}
|
|
|
|
// define method VIRTUAL of class UEventTime
|
|
|
|
virtual int handlerTime() U_DECL_FINAL;
|
|
|
|
#if defined(DEBUG) && defined(U_STDCPP_ENABLE)
|
|
const char* dump(bool _reset) const { return UEventTime::dump(_reset); }
|
|
#endif
|
|
|
|
private:
|
|
UTimeoutConnection(const UTimeoutConnection&) : UEventTime() {}
|
|
UTimeoutConnection& operator=(const UTimeoutConnection&) { return *this; }
|
|
};
|
|
|
|
#ifdef U_LOG_ENABLE
|
|
static bool called_from_handlerTime;
|
|
|
|
static uint32_t getNumConnection(char* buffer);
|
|
#endif
|
|
|
|
// define method VIRTUAL of class UEventFd
|
|
|
|
virtual int handlerRead() U_DECL_FINAL; // This method is called to accept a new connection on the server socket
|
|
virtual void handlerDelete() U_DECL_FINAL
|
|
{
|
|
U_TRACE(0, "UServer_Base::handlerDelete()")
|
|
|
|
U_INTERNAL_DUMP("UEventFd::fd = %d", UEventFd::fd)
|
|
|
|
UEventFd::fd = -1;
|
|
}
|
|
|
|
// method VIRTUAL to redefine
|
|
|
|
virtual void handlerSignal()
|
|
{
|
|
U_TRACE(0, "UServer_Base::handlerSignal()")
|
|
}
|
|
|
|
virtual void preallocate() = 0;
|
|
#ifdef DEBUG
|
|
virtual void deallocate() = 0;
|
|
virtual bool check_memory() = 0;
|
|
#endif
|
|
|
|
// SERVICES
|
|
|
|
static void _preallocate()
|
|
{
|
|
U_TRACE(0, "UServer_Base::_preallocate()")
|
|
|
|
U_INTERNAL_ASSERT_POINTER(pthis)
|
|
|
|
pthis->preallocate();
|
|
}
|
|
|
|
static RETSIGTYPE handlerForSigHUP( int signo);
|
|
static RETSIGTYPE handlerForSigTERM(int signo);
|
|
static RETSIGTYPE handlerForSigCHLD(int signo);
|
|
|
|
private:
|
|
friend class UHTTP;
|
|
friend class UHTTP2;
|
|
friend class USSLSocket;
|
|
friend class USSIPlugIn;
|
|
friend class UWebSocket;
|
|
friend class USocketExt;
|
|
friend class Application;
|
|
friend class UTimeThread;
|
|
friend class UHttpPlugIn;
|
|
friend class USCGIPlugIn;
|
|
friend class UFCGIPlugIn;
|
|
friend class UProxyPlugIn;
|
|
friend class UNoCatPlugIn;
|
|
friend class UGeoIPPlugIn;
|
|
friend class UClient_Base;
|
|
friend class UOCSPStapling;
|
|
friend class UStreamPlugIn;
|
|
friend class UClientThread;
|
|
friend class UModNoCatPeer;
|
|
friend class UHttpClient_Base;
|
|
friend class UWebSocketPlugIn;
|
|
friend class UModProxyService;
|
|
friend class UClientImage_Base;
|
|
|
|
static void manageSigHUP() U_NO_EXPORT;
|
|
static bool clientImageHandlerRead() U_NO_EXPORT;
|
|
static void logMemUsage(const char* signame) U_NO_EXPORT;
|
|
static void loadStaticLinkedModules(const char* name) U_NO_EXPORT;
|
|
|
|
#ifdef U_COMPILER_DELETE_MEMBERS
|
|
UServer_Base(const UServer_Base&) = delete;
|
|
UServer_Base& operator=(const UServer_Base&) = delete;
|
|
#else
|
|
UServer_Base(const UServer_Base&) : UEventFd() {}
|
|
UServer_Base& operator=(const UServer_Base&) { return *this; }
|
|
#endif
|
|
};
|
|
|
|
template <class Socket> class U_EXPORT UServer : public UServer_Base {
|
|
public:
|
|
|
|
typedef UClientImage<Socket> client_type;
|
|
|
|
UServer(UFileConfig* pcfg) : UServer_Base(pcfg)
|
|
{
|
|
U_TRACE_REGISTER_OBJECT(0, UServer, "%p", pcfg)
|
|
|
|
socket = U_NEW(Socket(UClientImage_Base::bIPv6));
|
|
}
|
|
|
|
virtual ~UServer()
|
|
{
|
|
U_TRACE_UNREGISTER_OBJECT(0, UServer)
|
|
}
|
|
|
|
// DEBUG
|
|
|
|
#if defined(DEBUG) && defined(U_STDCPP_ENABLE)
|
|
const char* dump(bool reset) const { return UServer_Base::dump(reset); }
|
|
#endif
|
|
|
|
protected:
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// method VIRTUAL to redefine
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// Create a new UClientImage object representing a client connection to the server.
|
|
// Derived classes that have overridden UClientImage object may call this function to implement the creation logic
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
|
|
virtual void preallocate() U_DECL_OVERRIDE
|
|
{
|
|
U_TRACE(0+256, "UServer<Socket>::preallocate()")
|
|
|
|
// NB: array are not pointers (virtual table can shift the address of this)...
|
|
|
|
vClientImage = new client_type[UNotifier::max_connection];
|
|
|
|
U_INTERNAL_DUMP("vClientImage = %p pClientImage = %p", vClientImage, pClientImage)
|
|
|
|
U_INTERNAL_ASSERT_EQUALS(vClientImage, pClientImage)
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
virtual void deallocate() U_DECL_OVERRIDE
|
|
{
|
|
U_TRACE(0+256, "UServer<Socket>::deallocate()")
|
|
|
|
// NB: array are not pointers (virtual table can shift the address of this)...
|
|
|
|
delete[] (client_type*)vClientImage;
|
|
}
|
|
|
|
virtual bool check_memory() U_DECL_OVERRIDE { return u_check_memory_vector<client_type>((client_type*)vClientImage, UNotifier::max_connection); }
|
|
#endif
|
|
|
|
private:
|
|
#ifdef U_COMPILER_DELETE_MEMBERS
|
|
UServer(const UServer&) = delete;
|
|
UServer& operator=(const UServer&) = delete;
|
|
#else
|
|
UServer(const UServer&) : UServer_Base(0) {}
|
|
UServer& operator=(const UServer&) { return *this; }
|
|
#endif
|
|
};
|
|
|
|
#ifdef USE_LIBSSL // specializzazione con USSLSocket
|
|
|
|
template <> class U_EXPORT UServer<USSLSocket> : public UServer_Base {
|
|
public:
|
|
|
|
typedef UClientImage<USSLSocket> client_type;
|
|
|
|
UServer(UFileConfig* pcfg) : UServer_Base(pcfg)
|
|
{
|
|
U_TRACE_REGISTER_OBJECT(0, UServer<USSLSocket>, "%p", pcfg)
|
|
|
|
# ifdef DEBUG
|
|
if (pcfg &&
|
|
bssl == false)
|
|
{
|
|
U_ERROR("you need to set bssl before loading the configuration");
|
|
}
|
|
# endif
|
|
|
|
socket = U_NEW(USSLSocket(UClientImage_Base::bIPv6, 0, true));
|
|
}
|
|
|
|
virtual ~UServer()
|
|
{
|
|
U_TRACE_UNREGISTER_OBJECT(0, UServer<USSLSocket>)
|
|
}
|
|
|
|
// DEBUG
|
|
|
|
#if defined(DEBUG) && defined(U_STDCPP_ENABLE)
|
|
const char* dump(bool reset) const { return UServer_Base::dump(reset); }
|
|
#endif
|
|
|
|
protected:
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// method VIRTUAL to redefine
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// Create a new UClientImage object representing a client connection to the server.
|
|
// Derived classes that have overridden UClientImage object may call this function to implement the creation logic
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
|
|
virtual void preallocate() U_DECL_OVERRIDE
|
|
{
|
|
U_TRACE(0+256, "UServer<USSLSocket>::preallocate()")
|
|
|
|
// NB: array are not pointers (virtual table can shift the address of this)...
|
|
|
|
vClientImage = new client_type[UNotifier::max_connection];
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
virtual void deallocate() U_DECL_OVERRIDE
|
|
{
|
|
U_TRACE(0+256, "UServer<USSLSocket>::deallocate()")
|
|
|
|
// NB: array are not pointers (virtual table can shift the address of this)...
|
|
|
|
delete[] (client_type*)vClientImage;
|
|
}
|
|
|
|
virtual bool check_memory() U_DECL_OVERRIDE { return u_check_memory_vector<client_type>((client_type*)vClientImage, UNotifier::max_connection); }
|
|
#endif
|
|
|
|
private:
|
|
#ifdef U_COMPILER_DELETE_MEMBERS
|
|
UServer<USSLSocket>(const UServer<USSLSocket>&) = delete;
|
|
UServer<USSLSocket>& operator=(const UServer<USSLSocket>&) = delete;
|
|
#else
|
|
UServer<USSLSocket>(const UServer<USSLSocket>&) : UServer_Base(0) {}
|
|
UServer<USSLSocket>& operator=(const UServer<USSLSocket>&) { return *this; }
|
|
#endif
|
|
};
|
|
|
|
#endif
|
|
#endif
|