diff --git a/configure b/configure index 9a13840f..9eba79e0 100755 --- a/configure +++ b/configure @@ -24472,7 +24472,10 @@ $as_echo "$msg" >&6; } $as_echo "#define USE_LIBEXPAT 1" >>confdefs.h - expat_version=$(strings $expatdir/lib*/libexpat.* 2>/dev/null | grep "^expat_[0-9]" | head -n1 | cut -d'_' -f2) + expat_version=$(strings $expatdir/lib*/libexpat.* 2>/dev/null | grep "^expat_[0-9]*" | head -n1 | cut -d'_' -f2) + if test -z "${expat_version}"; then + expat_version=$(ls $expatdir/libexpat.so.*.* 2>/dev/null | head -n 1 | awk -F'.so.' '{n=2; print $n}' 2>/dev/null) + fi if test -z "${expat_version}"; then expat_version="unknown" fi diff --git a/include/ulib/base/utility.h b/include/ulib/base/utility.h index 3cf5f14b..a222a388 100644 --- a/include/ulib/base/utility.h +++ b/include/ulib/base/utility.h @@ -142,7 +142,7 @@ U_EXPORT void u_printSize(char* restrict buffer, uint64_t bytes); /* prin U_EXPORT char* u_getPathRelativ(const char* restrict path, uint32_t* restrict path_len); U_EXPORT bool u_rmatch(const char* restrict haystack, uint32_t haystack_len, const char* restrict needle, uint32_t needle_len) __pure; U_EXPORT double u_calcRate(uint64_t bytes, uint32_t msecs, int* restrict units); /* Calculate the transfert rate */ -U_EXPORT uint32_t u_findEndHeader( const char* restrict s, uint32_t n); /* find sequence of U_CRLF2 or U_LF2 */ +U_EXPORT uint32_t u_findEndHeader( const char* restrict s, uint32_t n) __pure; /* find sequence of U_CRLF2 or U_LF2 */ U_EXPORT uint32_t u_findEndHeader1(const char* restrict s, uint32_t n) __pure; /* find sequence of U_CRLF2 */ U_EXPORT const char* u_get_mimetype(const char* restrict suffix, int* pmime_index); diff --git a/include/ulib/container/vector.h b/include/ulib/container/vector.h index a7cd6fcb..d353a8fd 100644 --- a/include/ulib/container/vector.h +++ b/include/ulib/container/vector.h @@ -1129,7 +1129,7 @@ public: // Check equality with string at pos - bool isEqual(uint32_t pos, const UString& str, bool ignore_case = false); + bool isEqual(uint32_t pos, const UString& str, bool ignore_case = false) __pure; // Check equality with an existing vector object diff --git a/include/ulib/date.h b/include/ulib/date.h index 9f61f1bd..be2ff58e 100644 --- a/include/ulib/date.h +++ b/include/ulib/date.h @@ -139,7 +139,7 @@ public: { U_TRACE(0, "UTimeDate::updateTime(%.5S)", ptr) - U_INTERNAL_ASSERT_DIFFERS(u_now->tv_sec % U_ONE_HOUR_IN_SECOND, 0) + U_INTERNAL_ASSERT(u_now->tv_sec % U_ONE_HOUR_IN_SECOND) U_NUM2STR16(ptr, (u_now->tv_sec / 60) % 60); U_NUM2STR16(ptr+3,u_now->tv_sec % 60); diff --git a/include/ulib/examples/wi_auth_declaration.h b/include/ulib/examples/wi_auth_declaration.h index 936d1520..eb70e4fb 100644 --- a/include/ulib/examples/wi_auth_declaration.h +++ b/include/ulib/examples/wi_auth_declaration.h @@ -1706,6 +1706,7 @@ static void usp_init_wi_auth() file_RECOVERY = U_NEW(UFile(dir + U_STRING_FROM_CONSTANT("/wifi-recovery"))); file_UTILIZZO = U_NEW(UFile(dir + U_STRING_FROM_CONSTANT("/wifi-utilizzo"))); + UServer_Base::update_date = UServer_Base::update_date1 = true; (void) UServer_Base::addLog(file_LOG); diff --git a/include/ulib/log.h b/include/ulib/log.h index cbb19d96..b83e8607 100644 --- a/include/ulib/log.h +++ b/include/ulib/log.h @@ -35,15 +35,11 @@ class UClientImage_Base; class U_EXPORT ULog : public UFile { public: - typedef struct static_date { - struct timeval _timeval; // => u_now - char spinlock1[1]; + typedef struct log_date { char date1[17+1]; // 18/06/12 18:45:56 - char spinlock2[1]; char date2[26+1]; // 04/Jun/2012:18:18:37 +0200 - char spinlock3[1]; char date3[6+29+2+12+2+19+1]; // Date: Wed, 20 Jun 2012 11:43:17 GMT\r\nServer: ULib\r\nConnection: close\r\n - } static_date; + } log_date; typedef struct log_data { uint32_t file_ptr; @@ -55,9 +51,13 @@ public: } log_data; static ULog* pthis; + static log_date date; static const char* prefix; static struct iovec iov_vec[5]; - static static_date* ptr_static_date; + static log_date* ptr_shared_date; +#ifdef ENABLE_THREAD + static pthread_rwlock_t* prwlock; +#endif // COSTRUTTORI @@ -137,6 +137,8 @@ protected: bool checkForLogRotateDataToWrite(); #endif + static long tv_sec_old_1, tv_sec_old_2, tv_sec_old_3; + void write(const struct iovec* iov, int n); #ifdef USE_LIBZ @@ -145,27 +147,13 @@ protected: static void close(); static void startup(); - static void initStaticDate(); - static void _updateStaticDate(char* ptr, int which); + static void initDate(); + static void updateDate1(); + static void updateDate2(); + static void updateDate3(); static void logResponse(const UString& data, const char* name, const char* format, ...); static void log(const struct iovec* iov, const char* name, const char* type, int ncount, const char* msg, uint32_t msg_len, const char* format, ...); - static void updateStaticDate(char* ptr, int which) - { - U_TRACE(0, "ULog::updateStaticDate(%p,%d)", ptr, which) - - U_INTERNAL_ASSERT_POINTER(ptr) - U_INTERNAL_ASSERT_DIFFERS(ptr[0], '\0') - -# ifdef ENABLE_THREAD - if (u_pthread_time == 0) -# endif - _updateStaticDate(ptr, which); - - U_INTERNAL_DUMP("ptr_static_date->date1 = %.17S ptr_static_date->date2 = %.26S ptr_static_date->date3+6 = %.29S", - ptr_static_date->date1, ptr_static_date->date2, ptr_static_date->date3+6) - } - private: static int decode(const char* name, uint32_t len, bool bfacility) __pure U_NO_EXPORT; diff --git a/include/ulib/net/server/server.h b/include/ulib/net/server/server.h index 130c2b26..7b454133 100644 --- a/include/ulib/net/server/server.h +++ b/include/ulib/net/server/server.h @@ -268,40 +268,27 @@ public: sem_t lock_user1; sem_t lock_user2; sem_t lock_rdb_server; -# ifdef USE_LIBSSL - sem_t lock_ssl_session; -# if defined(ENABLE_THREAD) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) - sem_t lock_ocsp_staple; -# endif -# endif - sem_t lock_static_date; 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 - char spinlock_static_date[1]; - char spinlock_data_session[1]; - char spinlock_db_not_found[1]; -# ifdef ENABLE_THREAD - /* typedef struct static_date { - struct timeval _timeval; // => u_now - char spinlock1[1]; - char date1[17+1]; // 18/06/12 18:45:56 - char spinlock2[1]; - char date2[26+1]; // 04/Jun/2012:18:18:37 +0200 - char spinlock3[1]; - char date3[6+29+2+12+2+19+1]; // Date: Wed, 20 Jun 2012 11:43:17 GMT\r\nServer: ULib\r\nConnection: close\r\n - } static_date; */ - ULog::static_date static_date; # endif // ------------------------------------------------------------------------------ +# ifdef ENABLE_THREAD + 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) // -------------------------------------------------------------------------------- @@ -316,33 +303,23 @@ public: #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_STATIC_DATE &(UServer_Base::ptr_shared_data->lock_static_date) #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_STATIC_DATE UServer_Base::ptr_shared_data->spinlock_static_date #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 -#define U_HTTP_DATE1_SPINLOCK UServer_Base::ptr_static_date->spinlock1 -#define U_HTTP_DATE1 ((char*)&(UServer_Base::ptr_static_date->date1[0])) -#define U_HTTP_DATE2_SPINLOCK UServer_Base::ptr_static_date->spinlock2 -#define U_HTTP_DATE2 ((char*)&(UServer_Base::ptr_static_date->date2[0])) -#define U_HTTP_DATE3_SPINLOCK UServer_Base::ptr_static_date->spinlock3 -#define U_HTTP_DATE3 ((char*)&(UServer_Base::ptr_static_date->date3[6])) -#define U_LOG_DATA_SHARED &(UServer_Base::ptr_shared_data->log_data_shared) 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 ULog::static_date* ptr_static_date; static uint32_t shared_data_add, map_size; - static bool update_date1, update_date2, update_date3; + static bool update_date, update_date1, update_date2, update_date3; static void setLockUser1() { diff --git a/include/ulib/string.h b/include/ulib/string.h index a4bef4fd..b487337b 100644 --- a/include/ulib/string.h +++ b/include/ulib/string.h @@ -191,7 +191,7 @@ public: U_RETURN(0); } - uint32_t remain(const char* ptr) const + ptrdiff_t remain(const char* ptr) const { U_TRACE(0, "UStringRep::remain(%p)", ptr) @@ -329,7 +329,7 @@ public: bool equal(const UStringRep* rep) const { return equal(rep->str, rep->_length); } __pure bool equal(const char* s, uint32_t n) const { - U_TRACE(0, "UStringRep::equal(%#.*S,%u)", n, s, n) // problem with sanitize address + U_TRACE(0, "UStringRep::equal(%#.*S,%u)", n, s, n) U_CHECK_MEMORY @@ -1109,7 +1109,7 @@ public: explicit UString(uint32_t n) { - U_TRACE_REGISTER_OBJECT_WITHOUT_CHECK_MEMORY(0, UString, "%u", n) // problem with sanitize address + U_TRACE_REGISTER_OBJECT_WITHOUT_CHECK_MEMORY(0, UString, "%u", n) rep = UStringRep::create(0U, n, 0); @@ -1379,7 +1379,7 @@ public: UString& append(const char* s, uint32_t n) { - U_TRACE(0, "UString::append(%.*S,%u)", n, s, n) // problem with sanitize address + U_TRACE(0, "UString::append(%.*S,%u)", n, s, n) if (n) { @@ -1656,7 +1656,7 @@ public: char c_char(uint32_t pos) const { return rep->at(pos); } char* c_pointer(uint32_t pos) const { return (char*)rep->c_pointer(pos); } - uint32_t remain( const char* ptr) const { return rep->remain(ptr); } + ptrdiff_t remain( const char* ptr) const { return rep->remain(ptr); } __pure uint32_t distance(const char* ptr) const { return rep->distance(ptr); } void setFromInode(uint64_t* p) { (void) replace((const char*)p, sizeof(uint64_t)); } diff --git a/include/ulib/thread.h b/include/ulib/thread.h index 8f16627b..fc5d31ac 100644 --- a/include/ulib/thread.h +++ b/include/ulib/thread.h @@ -69,6 +69,22 @@ public: (void) U_SYSCALL(pthread_mutex_unlock, "%p", mutex); } + static bool initRwLock(pthread_rwlock_t* rwlock) + { + U_TRACE(1, "UThread::initRwLock(%p)", rwlock) + + pthread_rwlockattr_t rwlockattr; + + if (U_SYSCALL(pthread_rwlockattr_init, "%p", &rwlockattr) != 0 || + U_SYSCALL(pthread_rwlockattr_setpshared, "%p,%d", &rwlockattr, PTHREAD_PROCESS_SHARED) != 0 || + U_SYSCALL(pthread_rwlock_init, "%p,%p", rwlock, &rwlockattr) != 0) + { + U_RETURN(false); + } + + U_RETURN(true); + } + static bool initIPC(pthread_mutex_t* mutex, pthread_cond_t* cond); static void doIPC(pthread_mutex_t* mutex, pthread_cond_t* cond, vPF function, bool wait); @@ -179,7 +195,14 @@ protected: static void sigHandler(int signo); static void execHandler(UThread* th); - static void threadCleanup(UThread* th); + + static void threadCleanup(UThread* th) + { + U_TRACE(0, "UThread::threadCleanup(%p)", th) + + th->close(); + } + // A special global function, getThread(), is provided to identify the thread object that represents the current // execution context you are running under. This is sometimes needed to deliver signals to the correct thread diff --git a/include/ulib/utility/hpack_huffman_table.h b/include/ulib/utility/hpack_huffman_table.h index b04809e9..60ef746c 100644 --- a/include/ulib/utility/hpack_huffman_table.h +++ b/include/ulib/utility/hpack_huffman_table.h @@ -1,6 +1,6 @@ // source: https://github.com/tatsuhiro-t/nghttp2/ @ 76b3ba2, under the following license -/* +/** * nghttp2 - HTTP/2 C Library * * Copyright (c) 2013 Tatsuhiro Tsujikawa diff --git a/include/ulib/utility/http2.h b/include/ulib/utility/http2.h index 359324e9..4bf99403 100644 --- a/include/ulib/utility/http2.h +++ b/include/ulib/utility/http2.h @@ -17,11 +17,6 @@ #include #include -#define HTTP2_CONNECTION_UPGRADE \ - "HTTP/1.1 101 Switching Protocols\r\n" \ - "Connection: Upgrade\r\n" \ - "Upgrade: h2c\r\n\r\n" - #define HTTP2_CONNECTION_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" // (24 bytes) class UHTTP; @@ -119,14 +114,11 @@ protected: }; enum StreamState { - STREAM_STATE_RECV_PSUEDO_HEADERS = 0x001, - STREAM_STATE_RECV_HEADERS = 0x002, - STREAM_STATE_RECV_BODY = 0x004, - STREAM_STATE_REQ_PENDING = 0x008, - STREAM_STATE_SEND_HEADERS = 0x010, - STREAM_STATE_SEND_BODY = 0x020, - STREAM_STATE_END_STREAM = 0x040, - STREAM_STATE_HALF_CLOSED = 0x080 + STREAM_STATE_IDLE = 0x000, + STREAM_STATE_RESERVED = 0x001, + STREAM_STATE_OPEN = 0x002, + STREAM_STATE_HALF_CLOSED = 0x004, + STREAM_STATE_CLOSED = 0x008 }; enum ConnectionState { @@ -146,22 +138,18 @@ protected: }; struct Connection { - // headers - UHashMap* itable; - UHashMap* otable; - // streams - Stream open_streams[100]; - // settings - Settings peer_settings; + ConnectionState state; // state + Settings peer_settings; // settings + UHashMap itable; // headers request + // internal + uint32_t input_window; + uint32_t output_window; + int32_t hpack_max_capacity; // the value set by SETTINGS_HEADER_TABLE_SIZE // streams int max_open_stream_id; uint32_t num_responding_streams; uint32_t max_processed_stream_id; - // internal - ConnectionState state; - uint32_t input_window; - uint32_t output_window; - int32_t hpack_max_capacity; // the value set by SETTINGS_HEADER_TABLE_SIZE + Stream streams[100]; }; struct HpackHeaderTableEntry { @@ -238,32 +226,25 @@ protected: static int nerror; static Stream* pStream; + static bool settings_ack; static FrameHeader frame; static void* pConnectionEnd; static Connection* pConnection; + static const Settings settings; static const char* upgrade_settings; - static const Settings SETTINGS_HOST; - static const Settings SETTINGS_DEFAULT; static uint32_t hash_static_table[61]; static HpackHeaderTableEntry hpack_static_table[61]; // SERVICES - static void readFrame(); - static void decodeFrame(); - + static void readFrame(); + static void sendError(); static void manageData(); - static void managePriority(); - static void manageWindowUpdate(); - - static void setStream(); - static void setConnection(); - static void sendError(int err); - static void resetReadBuffer(uint32_t length); + static void manageHeaders(); + static bool readBodyRequest(); static bool updateSetting(const char* ptr, uint32_t len); static void decodeHeaders(const char* ptr, const char* endptr); - static bool manageHeaders(const char** ptr, const char** endptr); #ifdef DEBUG static const char* getFrameTypeDescription(); @@ -317,8 +298,11 @@ protected: static const HuffSym huff_sym_table[]; static const HuffDecode huff_decode_table[][16]; - static uint32_t hpackDecodeInt( const unsigned char* src, const unsigned char* src_end, int32_t* pvalue, uint8_t prefix_max); - static uint32_t hpackDecodeString(const unsigned char* src, const unsigned char* src_end, UString* pvalue); + static uint32_t hpackDecodeString(const unsigned char* src, const unsigned char* src_end, UString* pvalue); + static uint32_t hpackEncodeString( unsigned char* dst, const char* src, uint32_t len); + + static unsigned char* hpackEncodeInt( unsigned char* dst, uint32_t value, uint8_t prefix_max); + static uint32_t hpackDecodeInt( const unsigned char* src, const unsigned char* src_end, int32_t* pvalue, uint8_t prefix_max); private: friend class UHTTP; diff --git a/include/ulib/utility/services.h b/include/ulib/utility/services.h index b2eff086..e9af449c 100644 --- a/include/ulib/utility/services.h +++ b/include/ulib/utility/services.h @@ -30,10 +30,6 @@ typedef int (*verify_cb)(int,X509_STORE_CTX*); /* error callback */ # define U_STORE_FLAGS (X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL) #endif -#ifdef USE_LIBUUID -# include -#endif - #ifndef FNM_CASEFOLD #define FNM_CASEFOLD FNM_IGNORECASE #endif @@ -44,7 +40,7 @@ typedef int (*verify_cb)(int,X509_STORE_CTX*); /* error callback */ struct U_EXPORT UServices { - static bool isSetuidRoot(); // UID handling: are we setuid-root... + static bool isSetuidRoot(); // UID handling: check if we are setuid-root static void closeStdInputOutput(); // move stdin and stdout to /dev/null static int getDevNull(const char* file); // return open(/dev/null) @@ -171,22 +167,18 @@ struct U_EXPORT UServices { static void generateDigest(int alg, uint32_t keylen, const UString& data, UString& output, int base64 = 0) { generateDigest(alg, keylen, (unsigned char*)U_STRING_TO_PARAM(data), output, base64); } -#ifdef USE_LIBUUID // creat a new unique UUID value - 16 bytes (128 bits) long // return from the binary representation a 36-byte string (plus tailing '\0') of the form 1b4e28ba-2fa1-11d2-883f-0016d3cca427 - static uuid_t uuid; // typedef unsigned char uuid_t[16]; - - static UString getUUID(); -#endif - - static uint64_t getUniqUID(); + static UString getUUID(); + static uint64_t getUniqUID(); // creat a new unique UUID value - 8 bytes (64 bits) long #ifdef USE_LIBSSL - /* setup OPENSSL standard certificate directory. The X509_STORE holds the tables etc for verification stuff. - A X509_STORE_CTX is used while validating a single certificate. The X509_STORE has X509_LOOKUPs for looking - up certs. The X509_STORE then calls a function to actually verify the certificate chain - */ + /** + * setup OPENSSL standard certificate directory. The X509_STORE holds the tables etc for verification stuff. + * A X509_STORE_CTX is used while validating a single certificate. The X509_STORE has X509_LOOKUPs for looking + * up certs. The X509_STORE then calls a function to actually verify the certificate chain + */ static UString* CApath; static X509_STORE* store; @@ -227,8 +219,8 @@ struct U_EXPORT UServices { * passwd is the corresponsding password for the private key */ - static UString getSignatureValue(int alg, const UString& data, const UString& pkey, const UString& passwd, int base64, ENGINE* e = 0); static bool verifySignature( int alg, const UString& data, const UString& signature, const UString& pkey, ENGINE* e = 0); + static UString getSignatureValue(int alg, const UString& data, const UString& pkey, const UString& passwd, int base64, ENGINE* e = 0); #endif }; diff --git a/include/ulib/utility/uhttp.h b/include/ulib/utility/uhttp.h index 98f8ccd3..1f15652b 100644 --- a/include/ulib/utility/uhttp.h +++ b/include/ulib/utility/uhttp.h @@ -271,6 +271,7 @@ public: static int handlerREAD(); static bool handlerCache(); + static int manageRequest(); static int processRequest(); static void initDbNotFound(); static void setEndRequestProcessing(); diff --git a/m4/ac_check_package.m4 b/m4/ac_check_package.m4 index d3e4534b..248b2db1 100644 --- a/m4/ac_check_package.m4 +++ b/m4/ac_check_package.m4 @@ -361,7 +361,10 @@ AC_DEFUN([AC_CHECK_PACKAGE],[ echo "${T_MD}libexpat found in $expatdir${T_ME}" USE_LIBEXPAT=yes AC_DEFINE(USE_LIBEXPAT, 1, [Define if enable libexpat support]) - expat_version=$(strings $expatdir/lib*/libexpat.* 2>/dev/null | grep "^expat_[[0-9]]" | head -n1 | cut -d'_' -f2) + expat_version=$(strings $expatdir/lib*/libexpat.* 2>/dev/null | grep "^expat_[[0-9]]*" | head -n1 | cut -d'_' -f2) + if test -z "${expat_version}"; then + expat_version=$(ls $expatdir/libexpat.so.*.* 2>/dev/null | head -n 1 | awk -F'.so.' '{n=2; print $n}' 2>/dev/null) + fi if test -z "${expat_version}"; then expat_version="unknown" fi diff --git a/src/ulib/base/base.c b/src/ulib/base/base.c index 358ce0d0..e083d894 100644 --- a/src/ulib/base/base.c +++ b/src/ulib/base/base.c @@ -58,13 +58,14 @@ void u_debug_at_exit(void); #ifdef HAVE_ENDIAN_H # include #endif - +#ifdef HAVE_SYS_SYSCALL_H +# include +#endif #ifndef _MSWINDOWS_ # include # include # include #endif - /* For TIOCGWINSZ and friends: */ #ifdef HAVE_SYS_IOCTL_H # include @@ -386,14 +387,29 @@ bool u_setStartTime(void) (void) gettimeofday(u_now, 0); - /* + /** * The "hash seed" is a feature to perturb the results to avoid "algorithmic complexity attacks" * * http://lwn.net/Articles/474365 */ - + u_seed_hash = u_random((uint32_t)u_pid ^ (uint32_t)u_now->tv_usec); +#ifdef SYS_getrandom + if (syscall(SYS_getrandom, &u_seed_hash, sizeof(u_seed_hash), 0) == sizeof(u_seed_hash)) u_seed_hash |= 1; + else +#endif + { + int fd = open("/dev/urandom", O_CLOEXEC | O_RDONLY); + if (fd < 0) fd = open("/dev/random", O_CLOEXEC | O_RDONLY); + if (fd > 0) + { + if (read(fd, &u_seed_hash, sizeof(u_seed_hash)) == sizeof(u_seed_hash)) u_seed_hash |= 1; + + (void) close(fd); + } + } + /* seed the random generator */ u_set_seed_random(u_seed_hash >> 16, u_seed_hash % 4294967296); diff --git a/src/ulib/base/utility.c b/src/ulib/base/utility.c index d89765eb..f944506e 100644 --- a/src/ulib/base/utility.c +++ b/src/ulib/base/utility.c @@ -582,7 +582,7 @@ __pure uint32_t u_findEndHeader1(const char* restrict str, uint32_t n) /* find sequence of U_LF2 or U_CRLF2 */ -uint32_t u_findEndHeader(const char* restrict str, uint32_t n) +__pure uint32_t u_findEndHeader(const char* restrict str, uint32_t n) { const char* restrict p; const char* restrict end = str + n; diff --git a/src/ulib/container/vector.cpp b/src/ulib/container/vector.cpp index f4ca393a..f860f950 100644 --- a/src/ulib/container/vector.cpp +++ b/src/ulib/container/vector.cpp @@ -282,7 +282,7 @@ __pure uint32_t UVector::find(const UString& str, bool ignore_case) // Check equality with string at pos -bool UVector::isEqual(uint32_t pos, const UString& str, bool ignore_case) +__pure bool UVector::isEqual(uint32_t pos, const UString& str, bool ignore_case) { U_TRACE(0, "UVector::isEqual(%u,%V,%b)", pos, str.rep, ignore_case) diff --git a/src/ulib/log.cpp b/src/ulib/log.cpp index b3ff0b6d..25cb36a5 100644 --- a/src/ulib/log.cpp +++ b/src/ulib/log.cpp @@ -34,18 +34,26 @@ #define U_MARK_END "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" // 24 #define U_FMT_START_STOP "*** %s %N (%ubit, pid %P) [%U@%H] ***" -ULog* ULog::pthis; -const char* ULog::prefix; -struct iovec ULog::iov_vec[5]; -ULog::static_date* ULog::ptr_static_date; +long ULog::tv_sec_old_1; +long ULog::tv_sec_old_2; +long ULog::tv_sec_old_3; +ULog* ULog::pthis; +const char* ULog::prefix; +struct iovec ULog::iov_vec[5]; +ULog::log_date ULog::date; +ULog::log_date* ULog::ptr_shared_date; +#ifdef ENABLE_THREAD +pthread_rwlock_t* ULog::prwlock; +#endif ULog::ULog(const UString& path, uint32_t _size, const char* dir_log_gz) : UFile(path, 0) { U_TRACE_REGISTER_OBJECT(0, ULog, "%V,%u,%S", path.rep, _size, dir_log_gz) lock = 0; - log_file_sz = log_gzip_sz = 0; ptr_log_data = 0; + log_file_sz = + log_gzip_sz = 0; U_Log_start_stop_msg(this) = false; @@ -74,16 +82,16 @@ ULog::ULog(const UString& path, uint32_t _size, const char* dir_log_gz) : UFile( return; } - /* - typedef struct log_data { - uint32_t file_ptr; - uint32_t file_page; - uint32_t gzip_len; - sem_t lock_shared; - char spinlock_shared[1]; - // --------------> maybe unnamed array of char for gzip compression... - } log_data; - */ + /** + * typedef struct log_data { + * uint32_t file_ptr; + * uint32_t file_page; + * uint32_t gzip_len; + * sem_t lock_shared; + * char spinlock_shared[1]; + * // --------------> maybe unnamed array of char for gzip compression... + * } log_data; + */ ptr_log_data = U_MALLOC_TYPE(log_data); @@ -186,38 +194,30 @@ ULog::~ULog() #endif } -void ULog::initStaticDate() +void ULog::initDate() { - U_TRACE(1, "ULog::initStaticDate()") - - U_INTERNAL_ASSERT_EQUALS(ptr_static_date, 0) - - ptr_static_date = U_MALLOC_TYPE(static_date); - - (void) U_SYSCALL(memset, "%p,%d,%u", ptr_static_date, 0, sizeof(static_date)); - - u_now = &(ptr_static_date->_timeval); + U_TRACE(1, "ULog::initDate()") iov_vec[0].iov_len = 17; iov_vec[1].iov_len = iov_vec[4].iov_len = 1; - iov_vec[0].iov_base = (caddr_t) ptr_static_date->date1; - iov_vec[1].iov_base = (caddr_t) " "; - iov_vec[2].iov_base = (caddr_t) u_buffer; - iov_vec[4].iov_base = (caddr_t) U_LF; + iov_vec[0].iov_base = (caddr_t)date.date1; + iov_vec[1].iov_base = (caddr_t)" "; + iov_vec[2].iov_base = (caddr_t)u_buffer; + iov_vec[4].iov_base = (caddr_t)U_LF; (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); - (void) u_strftime2(ptr_static_date->date1, 17, "%d/%m/%y %T", u_now->tv_sec + u_now_adjust); - (void) u_strftime2(ptr_static_date->date2, 26, "%d/%b/%Y:%T %z", u_now->tv_sec + u_now_adjust); - (void) u_strftime2(ptr_static_date->date3, 6+29+2+12+2+17+2, "Date: %a, %d %b %Y %T GMT\r\nServer: ULib\r\nConnection: close\r\n", u_now->tv_sec); + (void) u_strftime2(date.date1, 17, "%d/%m/%y %T", u_now->tv_sec + u_now_adjust); + (void) u_strftime2(date.date2, 26, "%d/%b/%Y:%T %z", u_now->tv_sec + u_now_adjust); + (void) u_strftime2(date.date3, 6+29+2+12+2+17+2, "Date: %a, %d %b %Y %T GMT\r\nServer: ULib\r\nConnection: close\r\n", u_now->tv_sec); } void ULog::startup() { U_TRACE(1, "ULog::startup()") - initStaticDate(); + initDate(); log(U_FMT_START_STOP, "STARTUP", sizeof(void*) * 8); @@ -267,101 +267,233 @@ void ULog::setPrefix(const char* _prefix) } } -void ULog::_updateStaticDate(char* ptr, int which) +void ULog::updateDate1() { - U_TRACE(1, "ULog::_updateStaticDate(%p,%d)", ptr, which) + U_TRACE(1, "ULog::updateDate1()") + /** + * 18/06/12 18:45:56 + * 012345678901234567890123456789 + */ + +#ifdef ENABLE_THREAD + if (u_pthread_time) + { +# if defined(U_LOG_ENABLE) && defined(USE_LIBZ) + (void) U_SYSCALL(pthread_rwlock_rdlock, "%p", prwlock); +# endif + + if (tv_sec_old_1 != u_now->tv_sec) + { + long tv_sec = u_now->tv_sec; + + U_INTERNAL_DUMP("tv_sec_old_1 = %lu u_now->tv_sec = %lu", tv_sec_old_1, tv_sec) + + if ((tv_sec - tv_sec_old_1) != 1 || + (tv_sec % U_ONE_HOUR_IN_SECOND) == 0) + { + tv_sec_old_1 = tv_sec; + + U_MEMCPY(date.date1, ptr_shared_date->date1, 17); + } + else + { + ++tv_sec_old_1; + + u_put_unalignedp16(date.date1+12, U_MULTICHAR_CONSTANT16(ptr_shared_date->date1[12],ptr_shared_date->date1[13])); + u_put_unalignedp16(date.date1+12+3,U_MULTICHAR_CONSTANT16(ptr_shared_date->date1[15],ptr_shared_date->date1[16])); + } + + U_INTERNAL_ASSERT_EQUALS(tv_sec, tv_sec_old_1) + } + +# if defined(U_LOG_ENABLE) && defined(USE_LIBZ) + (void) U_SYSCALL(pthread_rwlock_unlock, "%p", prwlock); +# endif + } + else +#endif + { U_INTERNAL_ASSERT_EQUALS(u_pthread_time, 0) (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); - bool bchange = ((u_now->tv_sec % U_ONE_HOUR_IN_SECOND) == 0); - - if (which == 1) + if (tv_sec_old_1 != u_now->tv_sec) { - static long tv_sec_old_1; + long tv_sec = u_now->tv_sec; - /** - * 18/06/12 18:45:56 - * 012345678901234567890123456789 - */ + U_INTERNAL_DUMP("tv_sec_old_1 = %lu u_now->tv_sec = %lu", tv_sec_old_1, tv_sec) - if (tv_sec_old_1 == u_now->tv_sec) return; - - U_INTERNAL_ASSERT_MINOR(tv_sec_old_1, u_now->tv_sec) - - if (bchange || - (u_now->tv_sec - tv_sec_old_1) != 1) + if ((tv_sec - tv_sec_old_1) != 1 || + (tv_sec % U_ONE_HOUR_IN_SECOND) == 0) { - (void) u_strftime2(ptr, 17, "%d/%m/%y %T", (tv_sec_old_1 = u_now->tv_sec) + u_now_adjust); + (void) u_strftime2(date.date1, 17, "%d/%m/%y %T", (tv_sec_old_1 = tv_sec) + u_now_adjust); } else { ++tv_sec_old_1; - UTimeDate::updateTime(ptr+12); + UTimeDate::updateTime(date.date1+12); } - U_INTERNAL_ASSERT_EQUALS(u_now->tv_sec, tv_sec_old_1) + U_INTERNAL_ASSERT_EQUALS(tv_sec, tv_sec_old_1) } - else if (which == 3) + } + + U_INTERNAL_DUMP("date.date1 = %.17S", date.date1) +} + +void ULog::updateDate2() +{ + U_TRACE(1, "ULog::updateDate2()") + + /** + * 04/Jun/2012:18:18:37 +0200 + * 012345678901234567890123456789 + */ + +#ifdef ENABLE_THREAD + if (u_pthread_time) { - static long tv_sec_old_3; +# if defined(U_LOG_ENABLE) && defined(USE_LIBZ) + (void) U_SYSCALL(pthread_rwlock_rdlock, "%p", prwlock); +# endif - /** - * Date: Wed, 20 Jun 2012 11:43:17 GMT\r\nServer: ULib\r\n - * 0123456789012345678901234567890123456789 - */ - - if (tv_sec_old_3 == u_now->tv_sec) return; - - U_INTERNAL_ASSERT_MINOR(tv_sec_old_3, u_now->tv_sec) - - if (bchange || - (u_now->tv_sec - tv_sec_old_3) != 1) + if (tv_sec_old_2 != u_now->tv_sec) { - (void) u_strftime2(ptr, 29-4, "%a, %d %b %Y %T", (tv_sec_old_3 = u_now->tv_sec)); // GMT can't change... + long tv_sec = u_now->tv_sec; + + U_INTERNAL_DUMP("tv_sec_old_2 = %lu u_now->tv_sec = %lu", tv_sec_old_2, tv_sec) + + if ((tv_sec - tv_sec_old_2) != 1 || + (tv_sec % U_ONE_HOUR_IN_SECOND) == 0) + { + tv_sec_old_2 = tv_sec; + + U_MEMCPY(date.date2, ptr_shared_date->date2, 26); + } + else + { + ++tv_sec_old_2; + + u_put_unalignedp16(date.date2+15, U_MULTICHAR_CONSTANT16(ptr_shared_date->date2[15],ptr_shared_date->date2[16])); + u_put_unalignedp16(date.date2+15+3,U_MULTICHAR_CONSTANT16(ptr_shared_date->date2[18],ptr_shared_date->date2[19])); + } + + U_INTERNAL_ASSERT_EQUALS(tv_sec, tv_sec_old_2) + } + +# if defined(U_LOG_ENABLE) && defined(USE_LIBZ) + (void) U_SYSCALL(pthread_rwlock_unlock, "%p", prwlock); +# endif + } + else +#endif + { + U_INTERNAL_ASSERT_EQUALS(u_pthread_time, 0) + + (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); + + if (tv_sec_old_2 != u_now->tv_sec) + { + long tv_sec = u_now->tv_sec; + + U_INTERNAL_DUMP("tv_sec_old_2 = %lu u_now->tv_sec = %lu", tv_sec_old_2, tv_sec) + + if ((tv_sec - tv_sec_old_2) != 1 || + (tv_sec % U_ONE_HOUR_IN_SECOND) == 0) + { + (void) u_strftime2(date.date2, 26-6, "%d/%b/%Y:%T", (tv_sec_old_2 = tv_sec) + u_now_adjust); + } + else + { + ++tv_sec_old_2; + + UTimeDate::updateTime(date.date2+15); + } + + U_INTERNAL_ASSERT_EQUALS(tv_sec, tv_sec_old_2) + } + } + + U_INTERNAL_DUMP("date.date2 = %.26S", date.date2) +} + +void ULog::updateDate3() +{ + U_TRACE(1, "ULog::updateDate3()") + + /** + * Date: Wed, 20 Jun 2012 11:43:17 GMT\r\nServer: ULib\r\n + * 0123456789012345678901234567890123 + * 0123456789012345678901234567890123456789 + */ + +#ifdef ENABLE_THREAD + if (u_pthread_time) + { +# if defined(U_LOG_ENABLE) && defined(USE_LIBZ) + (void) U_SYSCALL(pthread_rwlock_rdlock, "%p", prwlock); +# endif + + if (tv_sec_old_3 != u_now->tv_sec) + { + long tv_sec = u_now->tv_sec; + + U_INTERNAL_DUMP("tv_sec_old_3 = %lu u_now->tv_sec = %lu", tv_sec_old_3, tv_sec) + + if ((tv_sec - tv_sec_old_3) != 1 || + (tv_sec % U_ONE_HOUR_IN_SECOND) == 0) + { + tv_sec_old_3 = tv_sec; + + U_MEMCPY(date.date3+6, ptr_shared_date->date3+6, 29-4); + } + else + { + ++tv_sec_old_3; + + u_put_unalignedp16(date.date3+26, U_MULTICHAR_CONSTANT16(ptr_shared_date->date3[26],ptr_shared_date->date3[27])); + u_put_unalignedp16(date.date3+26+3,U_MULTICHAR_CONSTANT16(ptr_shared_date->date3[29],ptr_shared_date->date3[30])); + } + + U_INTERNAL_ASSERT_EQUALS(tv_sec, tv_sec_old_3) + } + +# if defined(U_LOG_ENABLE) && defined(USE_LIBZ) + (void) U_SYSCALL(pthread_rwlock_unlock, "%p", prwlock); +# endif + } + else +#endif + { + U_INTERNAL_ASSERT_EQUALS(u_pthread_time, 0) + + (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); + + if (tv_sec_old_3 != u_now->tv_sec) + { + long tv_sec = u_now->tv_sec; + + U_INTERNAL_DUMP("tv_sec_old_3 = %lu u_now->tv_sec = %lu", tv_sec_old_3, tv_sec) + + if ((tv_sec - tv_sec_old_3) != 1 || + (tv_sec % U_ONE_HOUR_IN_SECOND) == 0) + { + (void) u_strftime2(date.date3+6, 29-4, "%a, %d %b %Y %T", (tv_sec_old_3 = tv_sec)); // GMT can't change... } else { ++tv_sec_old_3; - UTimeDate::updateTime(ptr+20); + UTimeDate::updateTime(date.date3+26); } - U_INTERNAL_ASSERT_EQUALS(u_now->tv_sec, tv_sec_old_3) + U_INTERNAL_ASSERT_EQUALS(tv_sec, tv_sec_old_3) } - else - { - static long tv_sec_old_2; + } - U_INTERNAL_ASSERT_EQUALS(which, 2) - - /** - * 04/Jun/2012:18:18:37 +0200 - * 012345678901234567890123456789 - */ - - if (tv_sec_old_2 == u_now->tv_sec) return; - - U_INTERNAL_ASSERT_MINOR(tv_sec_old_2, u_now->tv_sec) - - if (bchange || - (u_now->tv_sec - tv_sec_old_2) != 1) - { - (void) u_strftime2(ptr, 26-6, "%d/%b/%Y:%T", (tv_sec_old_2 = u_now->tv_sec) + u_now_adjust); - } - else - { - ++tv_sec_old_2; - - UTimeDate::updateTime(ptr+15); - } - - U_INTERNAL_ASSERT_EQUALS(u_now->tv_sec, tv_sec_old_2) - } - - U_INTERNAL_ASSERT_EQUALS(ptr_static_date->date1, iov_vec[0].iov_base) + U_INTERNAL_DUMP("date.date3+6 = %.29S", date.date3+6) } void ULog::setShared(log_data* ptr, uint32_t _size, bool breference) @@ -559,7 +691,7 @@ void ULog::write(const char* msg, uint32_t len) iov_vec[3].iov_len = len; iov_vec[3].iov_base = (caddr_t) msg; - updateStaticDate(ptr_static_date->date1, 1); + updateDate1(); pthis->write(iov_vec, 5); @@ -606,7 +738,7 @@ void ULog::log(int _fd, const char* fmt, ...) iov_vec[3].iov_len = len; iov_vec[3].iov_base = (caddr_t)buffer; - updateStaticDate(ptr_static_date->date1, 1); + updateDate1(); (void) U_SYSCALL(writev, "%d,%p,%d", _fd, iov_vec, 5); } diff --git a/src/ulib/net/server/client_image.cpp b/src/ulib/net/server/client_image.cpp index 722dd091..e519db26 100644 --- a/src/ulib/net/server/client_image.cpp +++ b/src/ulib/net/server/client_image.cpp @@ -20,7 +20,7 @@ # include #endif -int UClientImage_Base::idx; +int UClientImage_Base::idx; int UClientImage_Base::csfd; int UClientImage_Base::iovcnt; iPF UClientImage_Base::callerHandlerRead; @@ -129,8 +129,23 @@ UClientImage_Base::UClientImage_Base() last_event = u_now->tv_sec; pending_close = 0; + // NB: array are not pointers (virtual table can shift the address of 'this')... + + if (UServer_Base::pClientImage == 0) + { + UServer_Base::pClientImage = this; + UServer_Base::eClientImage = this + UNotifier::max_connection; + + U_INTERNAL_DUMP("UServer_Base::pClientImage = %p UServer_Base::eClientImage = %p UNotifier::max_connection = %u", + UServer_Base::pClientImage, UServer_Base::eClientImage, UNotifier::max_connection) + } + + U_INTERNAL_DUMP("new T[%u]: elem %u of %u", UNotifier::max_connection, (this - UServer_Base::pClientImage), UNotifier::max_connection) + #ifndef U_HTTP2_DISABLE connection = U_NEW(UHTTP2::Connection); + + ((UHTTP2::Connection*)connection)->itable.setIndexFunction(UHTTP2::setIndexStaticTable); #endif } @@ -160,19 +175,6 @@ void UClientImage_Base::set() { U_TRACE(0, "UClientImage_Base::set()") - // NB: array are not pointers (virtual table can shift the address of 'this')... - - if (UServer_Base::pClientImage == 0) - { - UServer_Base::pClientImage = this; - UServer_Base::eClientImage = this + UNotifier::max_connection; - - U_INTERNAL_DUMP("UServer_Base::pClientImage = %p UServer_Base::eClientImage = %p UNotifier::max_connection = %u", - UServer_Base::pClientImage, UServer_Base::eClientImage, UNotifier::max_connection) - } - - U_INTERNAL_DUMP("new T[%u]: elem %u of %u", UNotifier::max_connection, (this - UServer_Base::pClientImage), UNotifier::max_connection) - U_INTERNAL_DUMP("this = %p socket = %p UEventFd::fd = %d", this, socket, UEventFd::fd) U_INTERNAL_ASSERT_POINTER(socket) @@ -223,7 +225,7 @@ bool UClientImage_Base::check_memory() { U_TRACE(0, "UClientImage_Base::check_memory()") - U_INTERNAL_DUMP("u_check_memory_vector: elem %u of %u", this - UServer_Base::pClientImage, UNotifier::max_connection) + U_INTERNAL_DUMP("u_check_memory_vector: elem %u of %u", this-UServer_Base::pClientImage, UNotifier::max_connection) U_INTERNAL_DUMP("this = %p socket = %p UEventFd::fd = %d", this, socket, UEventFd::fd) @@ -778,12 +780,27 @@ void UClientImage_Base::manageReadBufferResize(uint32_t n) { U_TRACE(0, "UClientImage_Base::manageReadBufferResize(%u)", n) - ptrdiff_t diff; - const char* ptr; - U_DUMP("U_ClientImage_pipeline = %b size_request = %u rbuffer->size() = %u rbuffer->capacity() = %u request->size() = %u rstart = %u", U_ClientImage_pipeline, size_request, rbuffer->size(), rbuffer->capacity(), request->size(), rstart) +#ifndef U_HTTP2_DISABLE + if (U_http_version == '2') + { + if (rstart) + { + rbuffer->moveToBeginDataInBuffer(rstart); + rstart = 0; + } + + UString::_reserve(*rbuffer, n); + + return; + } +#endif + + ptrdiff_t diff; + const char* ptr; + request->clear(); if (U_ClientImage_pipeline) @@ -811,8 +828,7 @@ next1: UString::_reserve(*rbuffer, n); - if (U_http_method_type && - U_http_version != '2') + if (U_http_method_type) { diff = rbuffer->data() - ptr; next2: @@ -1447,9 +1463,9 @@ bool UClientImage_Base::writeResponse() msg_len = (U_ClientImage_pipeline ? U_CONSTANT_SIZE("[pipeline] ") : 0); iov_vec[2].iov_len = sz1; - iov_vec[2].iov_base = (caddr_t) wbuffer->data(); + iov_vec[2].iov_base = (caddr_t)wbuffer->data(); iov_vec[3].iov_len = sz2; - iov_vec[3].iov_base = (caddr_t) body->data(); + iov_vec[3].iov_base = (caddr_t)body->data(); ncount = sz1 + sz2; @@ -1478,7 +1494,14 @@ bool UClientImage_Base::writeResponse() u__memcpy(iov_sav, iov_vec, U_IOV_TO_SAVE, __PRETTY_FUNCTION__); - ULog::updateStaticDate(UServer_Base::ptr_static_date->date3+6, 3); +# if defined(ENABLE_THREAD) && !defined(U_LOG_ENABLE) && !defined(USE_LIBZ) + U_INTERNAL_ASSERT_POINTER(u_pthread_time) + U_INTERNAL_ASSERT_EQUALS(iov_vec[1].iov_base, UServer_Base::ptr_shared_data->log_date_shared.date3) +# else + U_INTERNAL_ASSERT_EQUALS(iov_vec[1].iov_base, ULog::date.date3) + + ULog::updateDate3(); +# endif # ifdef U_LOG_ENABLE if (logbuf) ULog::log(iov_vec+idx, UServer_Base::mod_name[0], "response", ncount, "[pipeline] ", msg_len, " to %v", logbuf->rep); diff --git a/src/ulib/net/server/plugin/mod_http.cpp b/src/ulib/net/server/plugin/mod_http.cpp index 6c9b1bfe..30627c94 100644 --- a/src/ulib/net/server/plugin/mod_http.cpp +++ b/src/ulib/net/server/plugin/mod_http.cpp @@ -348,6 +348,7 @@ int UHttpPlugIn::handlerConfig(UFileConfig& cfg) if (x) { + UServer_Base::update_date = UServer_Base::update_date2 = true; uint32_t size = cfg.readLong(*UString::str_LOG_FILE_SZ); @@ -446,11 +447,18 @@ int UHttpPlugIn::handlerRun() // NB: we use this method because now we have the if (UServer_Base::vplugin_name->last() == *UString::str_http) { + UServer_Base::update_date = UServer_Base::update_date3 = true; - UClientImage_Base::iov_vec[1].iov_base = (caddr_t) UServer_Base::ptr_static_date->date3; // Date: Wed, 20 Jun 2012 11:43:17 GMT\r\nServer: ULib\r\n... + UClientImage_Base::iov_vec[1].iov_base = (caddr_t)ULog::date.date3; // Date: Wed, 20 Jun 2012 11:43:17 GMT\r\nServer: ULib\r\n... UClientImage_Base::iov_vec[1].iov_len = 6+29+2+12+2+17+2; +# if defined(ENABLE_THREAD) && !defined(U_LOG_ENABLE) && !defined(USE_LIBZ) + U_INTERNAL_ASSERT_POINTER(u_pthread_time) + + UClientImage_Base::iov_vec[1].iov_base = (caddr_t)UServer_Base::ptr_shared_data->log_date_shared.date3; +# endif + U_INTERNAL_DUMP("UClientImage_Base::iov_vec[0] = %.*S UClientImage_Base::iov_vec[1] = %.*S", UClientImage_Base::iov_vec[0].iov_len, UClientImage_Base::iov_vec[0].iov_base, UClientImage_Base::iov_vec[1].iov_len, UClientImage_Base::iov_vec[1].iov_base) diff --git a/src/ulib/net/server/server.cpp b/src/ulib/net/server/server.cpp index 4dda4572..f3cffe9f 100644 --- a/src/ulib/net/server/server.cpp +++ b/src/ulib/net/server/server.cpp @@ -89,6 +89,7 @@ bool UServer_Base::public_address; bool UServer_Base::monitoring_process; bool UServer_Base::set_tcp_keep_alive; bool UServer_Base::set_realtime_priority; +bool UServer_Base::update_date; bool UServer_Base::update_date1; bool UServer_Base::update_date2; bool UServer_Base::update_date3; @@ -143,7 +144,6 @@ UVector* UServer_Base::vplugin_name_static; UClientImage_Base* UServer_Base::pClientImage; UClientImage_Base* UServer_Base::vClientImage; UClientImage_Base* UServer_Base::eClientImage; -ULog::static_date* UServer_Base::ptr_static_date; UVector* UServer_Base::vplugin; UServer_Base::shared_data* UServer_Base::ptr_shared_data; UVector* UServer_Base::vlog; @@ -167,24 +167,14 @@ UVector* UServer_Base::vallow_IP_prv; class UTimeThread : public UThread { public: - UTimeThread() : UThread(true, false) { watch_counter = 1; } - -#ifdef DEBUG - UTimeVal before; -#endif - int watch_counter; + UTimeThread() : UThread(true, false) {} virtual void run() { U_TRACE(0, "UTimeThread::run()") -# ifdef DEBUG - long delta; - UTimeVal after; -# endif - bool bchange; struct timespec ts; - long tv_sec_old = u_now->tv_sec; + u_timeval.tv_sec = u_now->tv_sec; U_SRV_LOG("UTimeThread optimization for time resolution of one second activated (pid %u)", UThread::getTID()); @@ -196,74 +186,46 @@ public: (void) U_SYSCALL(nanosleep, "%p,%p", &ts, 0); # if defined(U_LOG_ENABLE) && defined(USE_LIBZ) - if ((UServer_Base::log && UServer_Base::log->checkForLogRotateDataToWrite()) || - (UServer_Base::apache_like_log && UServer_Base::apache_like_log->checkForLogRotateDataToWrite())) - { - watch_counter = 1; - } + if (UServer_Base::log) (void) UServer_Base::log->checkForLogRotateDataToWrite(); + if (UServer_Base::apache_like_log) (void) UServer_Base::apache_like_log->checkForLogRotateDataToWrite(); # endif - U_INTERNAL_DUMP("watch_counter = %d tv_sec_old = %ld u_now->tv_sec = %ld", watch_counter, tv_sec_old, u_now->tv_sec) + U_INTERNAL_DUMP("u_timeval.tv_sec = %ld u_now->tv_sec = %ld", u_timeval.tv_sec, u_now->tv_sec) - if (tv_sec_old == u_now->tv_sec) + if (u_timeval.tv_sec == u_now->tv_sec) { - if (--watch_counter > 0) u_now->tv_sec++; + (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); + + if (u_timeval.tv_sec == u_now->tv_sec) continue; + } + + U_INTERNAL_ASSERT_DIFFERS(u_now->tv_sec, u_timeval.tv_sec) + + u_timeval.tv_sec = u_now->tv_sec; + + if (UServer_Base::update_date) + { +# if defined(U_LOG_ENABLE) && defined(USE_LIBZ) + (void) U_SYSCALL(pthread_rwlock_wrlock, "%p", ULog::prwlock); +# endif + + if ((u_timeval.tv_sec % U_ONE_HOUR_IN_SECOND) != 0) + { + if (UServer_Base::update_date1) UTimeDate::updateTime(ULog::ptr_shared_date->date1 + 12); + if (UServer_Base::update_date2) UTimeDate::updateTime(ULog::ptr_shared_date->date2 + 15); + if (UServer_Base::update_date3) UTimeDate::updateTime(ULog::ptr_shared_date->date3 + 26); + } else { -# ifdef DEBUG - if (watch_counter == 0) - { - before.tv_sec = u_now->tv_sec + 1; - before.tv_usec = u_now->tv_usec; - } -# endif - - (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); - -# ifdef DEBUG - after.set(*u_now); - - after -= before; - delta = after.getMilliSecond(); - - if (delta >= 1000L || - delta <= -1000L) - { - U_SRV_LOG("UTimeThread delta time exceed 1 sec: diff(%ld ms)", delta); - - if (delta <= -30000L) U_ERROR("UTimeThread delta time exceed too much - ts = { %ld, %ld }", ts.tv_sec, ts.tv_nsec); - } -# endif - - watch_counter = 30; - - if (tv_sec_old == u_now->tv_sec) continue; + if (UServer_Base::update_date1) (void) u_strftime2(ULog::ptr_shared_date->date1, 17, "%d/%m/%y %T", u_timeval.tv_sec + u_now_adjust); + if (UServer_Base::update_date2) (void) u_strftime2(ULog::ptr_shared_date->date2, 26-6, "%d/%b/%Y:%T", u_timeval.tv_sec + u_now_adjust); // %z in general don't change... + if (UServer_Base::update_date3) (void) u_strftime2(ULog::ptr_shared_date->date3+6, 29-4, "%a, %d %b %Y %T", u_timeval.tv_sec); // GMT can't change... } + +# if defined(U_LOG_ENABLE) && defined(USE_LIBZ) + (void) U_SYSCALL(pthread_rwlock_unlock, "%p", ULog::prwlock); +# endif } - - U_INTERNAL_ASSERT_DIFFERS(u_now->tv_sec, tv_sec_old) - - bchange = ((u_now->tv_sec % U_ONE_HOUR_IN_SECOND) == 0); - - if (UServer_Base::update_date1) - { - if (bchange == false) UTimeDate::updateTime(U_HTTP_DATE1 + 12); - else (void) u_strftime2(U_HTTP_DATE1, 17, "%d/%m/%y %T", u_now->tv_sec + u_now_adjust); - } - - if (UServer_Base::update_date2) - { - if (bchange == false) UTimeDate::updateTime(U_HTTP_DATE2 + 15); - else (void) u_strftime2(U_HTTP_DATE2, 26-6, "%d/%b/%Y:%T", u_now->tv_sec + u_now_adjust); // NB: %z in general don't change... - } - - if (UServer_Base::update_date3) - { - if (bchange == false) UTimeDate::updateTime(U_HTTP_DATE3 + 20); - else (void) u_strftime2(U_HTTP_DATE3, 29-4, "%a, %d %b %Y %T", u_now->tv_sec); // GMT can't change... - } - - tv_sec_old = u_now->tv_sec; } } }; @@ -395,9 +357,11 @@ UServer_Base::~UServer_Base() ((UTimeThread*)u_pthread_time)->suspend(); delete (UTimeThread*)u_pthread_time; // delete to join + + (void) U_SYSCALL(pthread_rwlock_destroy, "%p", ULog::prwlock); } -# if defined(USE_LIBSSL) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) +# if defined(USE_LIBSSL) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) if (bssl) { if (pthread_ocsp) @@ -411,7 +375,7 @@ UServer_Base::~UServer_Base() if (UServer_Base::lock_ocsp_staple) delete UServer_Base::lock_ocsp_staple; } -# endif +# endif #endif UClientImage_Base::clear(); @@ -876,6 +840,7 @@ void UServer_Base::loadConfigParam() { // open log + update_date = update_date1 = true; log = U_NEW(ULog(x, cfg->readLong(*UString::str_LOG_FILE_SZ))); @@ -1394,7 +1359,7 @@ void UServer_Base::init() } #else /** - * This code does NOT make a connection or send any packets (to 64.233.187.99 which is google). + * This code does NOT make a connection or send any packets (to 8.8.8.8 which is google DNS). * Since UDP is a stateless protocol connect() merely makes a system call which figures out how to * route the packets based on the address and what interface (and therefore IP address) it should * bind to. Returns an array containing the family (AF_INET), local port, and local address (which @@ -1545,7 +1510,7 @@ void UServer_Base::init() #ifdef U_LOG_ENABLE uint32_t log_rotate_size = 0; -# ifdef USE_LIBZ +# ifdef USE_LIBZ if (isLog()) { // The zlib documentation states that destination buffer size must be at least 0.1% larger than avail_in plus 12 bytes @@ -1553,7 +1518,7 @@ void UServer_Base::init() log_rotate_size = shared_data_add = log->UFile::st_size + (log->UFile::st_size / 10) + 12U; } -# endif +# endif U_INTERNAL_DUMP("log_rotate_size = %u", log_rotate_size) #endif @@ -1585,61 +1550,56 @@ void UServer_Base::init() #ifdef U_LOG_ENABLE if (isLog() == false) #endif - ULog::initStaticDate(); - - if (bpthread_time == false) ptr_static_date = ULog::ptr_static_date; -#ifdef ENABLE_THREAD - else - { - ptr_static_date = &(ptr_shared_data->static_date); - - U_INTERNAL_ASSERT_POINTER( ULog::ptr_static_date) - U_INTERNAL_ASSERT_EQUALS((void*)u_now, (void*)ULog::ptr_static_date) - - U_MEMCPY(ptr_static_date, ULog::ptr_static_date, sizeof(ULog::static_date)); - - u_now = &(ptr_static_date->_timeval); - ULog::iov_vec[0].iov_base = (caddr_t)ptr_static_date->date1; - - U_FREE_TYPE(ULog::ptr_static_date, ULog::static_date); - - ULog::ptr_static_date = ptr_static_date; - } -#endif - - U_INTERNAL_ASSERT_EQUALS((void*)u_now, (void*)ptr_static_date) - U_INTERNAL_ASSERT_EQUALS((void*)u_now, (void*)ULog::ptr_static_date) - -#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_) - // NB: we block SIGHUP and SIGTERM; the threads created will inherit a copy of the signal mask... -# ifdef sigemptyset - sigemptyset(&mask); -# else - (void) U_SYSCALL(sigemptyset, "%p", &mask); -# endif - -# ifdef sigaddset - sigaddset(&mask, SIGHUP); - sigaddset(&mask, SIGTERM); -# else - (void) U_SYSCALL(sigaddset, "%p,%d", &mask, SIGHUP); - (void) U_SYSCALL(sigaddset, "%p,%d", &mask, SIGTERM); -# endif - - (void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_BLOCK, &mask, 0); -#endif - - flag_loop = true; // NB: UTimeThread loop depend on this... + ULog::initDate(); #ifdef ENABLE_THREAD if (bpthread_time) { + U_INTERNAL_ASSERT_POINTER(ptr_shared_data) + U_INTERNAL_ASSERT_EQUALS(ULog::ptr_shared_date, 0) + + u_now = &(ptr_shared_data->now_shared); + ULog::ptr_shared_date = &(ptr_shared_data->log_date_shared); + + (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); + + U_MEMCPY(ULog::ptr_shared_date, &ULog::date, sizeof(ULog::log_date)); + } +#endif + +#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_) + // NB: we block SIGHUP and SIGTERM; the threads created will inherit a copy of the signal mask... +# ifdef sigemptyset + sigemptyset(&mask); +# else + (void) U_SYSCALL(sigemptyset, "%p", &mask); +# endif + +# ifdef sigaddset + sigaddset(&mask, SIGHUP); + sigaddset(&mask, SIGTERM); +# else + (void) U_SYSCALL(sigaddset, "%p,%d", &mask, SIGHUP); + (void) U_SYSCALL(sigaddset, "%p,%d", &mask, SIGTERM); +# endif + + (void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_BLOCK, &mask, 0); +#endif + + flag_loop = true; // NB: UTimeThread loop depend on this setting... + +#ifdef ENABLE_THREAD + if (bpthread_time) + { + U_INTERNAL_ASSERT_EQUALS(ULog::prwlock, 0) U_INTERNAL_ASSERT_EQUALS(u_pthread_time, 0) U_NEW_ULIB_OBJECT(u_pthread_time, UTimeThread); U_INTERNAL_DUMP("u_pthread_time = %p", u_pthread_time) + (void) UThread::initRwLock((ULog::prwlock = &(ptr_shared_data->rwlock))); + ((UTimeThread*)u_pthread_time)->start(50); } #endif @@ -1647,9 +1607,9 @@ void UServer_Base::init() #ifdef U_LOG_ENABLE if (isLog()) { - // NB: if log is mapped must be always shared cause of possibility of fork() by parallelization + // NB: if log is mapped must be always shared because of possibility of fork() by parallelization... - if (log->isMemoryMapped()) log->setShared(U_LOG_DATA_SHARED, log_rotate_size); + if (log->isMemoryMapped()) log->setShared(&(ptr_shared_data->log_data_shared), log_rotate_size); U_SRV_LOG("Mapped %u bytes (%u KB) of shared memory for %d preforked process", sizeof(shared_data) + shared_data_add, map_size / 1024, preforked_num_kids); } @@ -1690,8 +1650,8 @@ void UServer_Base::init() /** * There may not always be a connection waiting after a SIGIO is delivered or select(2) or poll(2) return a readability - * event because the connection might have been removed by an asynchronous network error or another thread before - * accept() is called. If this happens then the call will block waiting for the next connection to arrive. To ensure + * event because the connection might have been removed by an asynchronous network error or another thread before + * accept() is called. If this happens then the call will block waiting for the next connection to arrive. To ensure * that accept() never blocks, the passed socket sockfd needs to have the O_NONBLOCK flag set (see socket(7)) */ @@ -1874,13 +1834,13 @@ RETSIGTYPE UServer_Base::handlerForSigHUP(int signo) (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); #ifdef ENABLE_THREAD -# if defined(USE_LIBSSL) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) - if (pthread_ocsp) pthread_ocsp->suspend(); -# endif +# if defined(USE_LIBSSL) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) + if (pthread_ocsp) pthread_ocsp->suspend(); +# endif if (u_pthread_time) ((UTimeThread*)u_pthread_time)->suspend(); #endif - pthis->handlerSignal(); // manage before regenering preforked pool of children... + pthis->handlerSignal(); // manage signal before we regenering the preforked pool of children... // NB: we can't use UInterrupt::erase() because it restore the old action (UInterrupt::init)... @@ -1896,19 +1856,9 @@ RETSIGTYPE UServer_Base::handlerForSigHUP(int signo) #ifdef ENABLE_THREAD # if defined(USE_LIBSSL) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) - if (pthread_ocsp) pthread_ocsp->resume(); + if (pthread_ocsp) pthread_ocsp->resume(); # endif - if (u_pthread_time) - { -# ifdef DEBUG - (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); - - ((UTimeThread*)u_pthread_time)->before.set(*u_now); -# endif - ((UTimeThread*)u_pthread_time)->watch_counter = 0; - - ((UTimeThread*)u_pthread_time)->resume(); - } + if (u_pthread_time) ((UTimeThread*)u_pthread_time)->resume(); #endif #ifdef U_LOG_ENABLE @@ -2174,7 +2124,7 @@ try_accept: # ifdef U_LOG_ENABLE if (isLog() && flag_loop && // NB: we check to avoid SIGTERM event... - CSOCKET->iState != -EINTR && // NB: we check to avoid log spurious EINTR on accept() by timer... + CSOCKET->iState != -EINTR && // NB: we check to avoid log spurious EINTR on accept() by any timer... CSOCKET->iState != -EAGAIN) { CSOCKET->setMsgError(); @@ -2772,18 +2722,6 @@ void UServer_Base::run() if (preforked_num_kids <= 0) pid_to_wait = pid; if (set_realtime_priority) u_switch_to_realtime_priority(pid); - -# ifdef ENABLE_THREAD - if (u_pthread_time) - { -# ifdef DEBUG - (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); - - ((UTimeThread*)u_pthread_time)->before.set(*u_now); -# endif - ((UTimeThread*)u_pthread_time)->watch_counter = 0; - } -# endif } if (proc->child()) @@ -3069,7 +3007,6 @@ const char* UServer_Base::dump(bool reset) const << "last_event " << last_event << '\n' << "verify_mode " << verify_mode << '\n' << "shared_data_add " << shared_data_add << '\n' - << "ptr_static_date " << (void*)ptr_static_date << '\n' << "ptr_shared_data " << (void*)ptr_shared_data << '\n' << "preforked_num_kids " << preforked_num_kids << '\n' << "log (ULog " << (void*)log << ")\n" diff --git a/src/ulib/options.cpp b/src/ulib/options.cpp index f8d7d538..99c8daa0 100644 --- a/src/ulib/options.cpp +++ b/src/ulib/options.cpp @@ -712,7 +712,7 @@ uint32_t UOptions::getopt(int argc, char** argv, int* poptind) "SSL support..........:%W " LIBSSL_ENABLE "%W\n" "SSH support..........:%W " LIBSSH_ENABLE "%W\n" "LDAP support.........:%W " LIBLDAP_ENABLE "%W\n" - "LDAP support.........:%W " LIBLDAP_ENABLE "%W\n" + "cURL support.........:%W " LIBCURL_ENABLE "%W\n" "XML support..........:%W " LIBEXPAT_ENABLE "%W\n" "MAGIC support........:%W " MAGIC_ENABLE "%W\n" "SQLite support.......:%W " SQLITE_ENABLE "%W\n" diff --git a/src/ulib/thread.cpp b/src/ulib/thread.cpp index 3f8e2017..49308ff7 100644 --- a/src/ulib/thread.cpp +++ b/src/ulib/thread.cpp @@ -19,7 +19,7 @@ # include #endif -typedef void* (*exec_t)(void*); +typedef void* (*exec_t) (void*); typedef void (*cleanup_t)(void*); #ifndef HAVE_NANOSLEEP @@ -138,15 +138,9 @@ void UThread::stop() (void) U_SYSCALL(pthread_cancel, "%p", priv->_tid); - if (bdetached == false) - { - (void) U_SYSCALL(pthread_join, "%p,%p", priv->_tid, 0); - } + if (bdetached == false) (void) U_SYSCALL(pthread_join, "%p,%p", priv->_tid, 0); #ifdef HAVE_PTHREAD_YIELD - else - { - (void) U_SYSCALL_NO_PARAM(pthread_yield); - } + else (void) U_SYSCALL_NO_PARAM(pthread_yield); #endif } @@ -179,13 +173,6 @@ void UThread::close() } } -void UThread::threadCleanup(UThread* th) -{ - U_TRACE(0, "UThread::threadCleanup(%p)", th) - - th->close(); -} - void UThread::yield() { U_TRACE(1, "UThread::yield()") @@ -202,17 +189,17 @@ void UThread::yield() if (bcancel) { -# ifdef sigemptyset +# ifdef sigemptyset sigemptyset(&cancel); -# else +# else (void) U_SYSCALL(sigemptyset, "%p", &cancel); -# endif +# endif -# ifdef sigaddset +# ifdef sigaddset sigaddset(&cancel, CCXX_SIG_THREAD_CANCEL); -# else +# else (void) U_SYSCALL(sigaddset, "%p,%d", &cancel, CCXX_SIG_THREAD_CANCEL); -# endif +# endif (void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_UNBLOCK, &cancel, &old); } @@ -254,11 +241,11 @@ void UThread::sigInstall(int signo) struct sigaction sa; -# ifdef sigemptyset +#ifdef sigemptyset sigemptyset(&sa.sa_mask); -# else +#else (void) U_SYSCALL(sigemptyset, "%p", &sa.sa_mask); -# endif +#endif #ifdef SA_RESTART sa.sa_flags = SA_RESTART; @@ -364,25 +351,25 @@ void UThread::execHandler(UThread* th) sigset_t mask; -# ifdef sigemptyset +#ifdef sigemptyset sigemptyset(&mask); -# else +#else (void) U_SYSCALL(sigemptyset, "%p", &mask); -# endif +#endif -# ifdef sigaddset +#ifdef sigaddset // sigaddset(&mask, SIGHUP); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGABRT); sigaddset(&mask, SIGPIPE); sigaddset(&mask, SIGALRM); -# else +#else // (void) U_SYSCALL(sigaddset, "%p,%d", &mask, SIGHUP); (void) U_SYSCALL(sigaddset, "%p,%d", &mask, SIGINT); (void) U_SYSCALL(sigaddset, "%p,%d", &mask, SIGABRT); (void) U_SYSCALL(sigaddset, "%p,%d", &mask, SIGPIPE); (void) U_SYSCALL(sigaddset, "%p,%d", &mask, SIGALRM); -# endif +#endif (void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_BLOCK, &mask, 0); @@ -394,19 +381,19 @@ void UThread::execHandler(UThread* th) // of Linux threads, it was possible to stop a single thread with SIGSTOP, but this behaviour has now been fixed // to conform to the Posix standard (so it stops all threads in the process) -# ifdef sigemptyset +# ifdef sigemptyset sigemptyset(&mask); -# else +# else (void) U_SYSCALL(sigemptyset, "%p", &mask); -# endif +# endif -# ifdef sigaddset +# ifdef sigaddset sigaddset(&mask, U_SIGSTOP); sigaddset(&mask, U_SIGCONT); -# else +# else (void) U_SYSCALL(sigaddset, "%p,%d", &mask, U_SIGSTOP); (void) U_SYSCALL(sigaddset, "%p,%d", &mask, U_SIGCONT); -# endif +# endif (void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_UNBLOCK, &mask, 0); @@ -575,10 +562,10 @@ bool UThread::initIPC(pthread_mutex_t* mutex, pthread_cond_t* cond) { pthread_mutexattr_t mutexattr; - if (U_SYSCALL(pthread_mutexattr_init, "%p", &mutexattr) == -1 || - U_SYSCALL(pthread_mutexattr_setrobust, "%p,%d", &mutexattr, PTHREAD_MUTEX_ROBUST) == -1 || - U_SYSCALL(pthread_mutexattr_setpshared, "%p,%d", &mutexattr, PTHREAD_PROCESS_SHARED) == -1 || - U_SYSCALL(pthread_mutex_init, "%p,%p", mutex, &mutexattr) == -1) + if (U_SYSCALL(pthread_mutexattr_init, "%p", &mutexattr) != 0 || + U_SYSCALL(pthread_mutexattr_setrobust, "%p,%d", &mutexattr, PTHREAD_MUTEX_ROBUST) != 0 || + U_SYSCALL(pthread_mutexattr_setpshared, "%p,%d", &mutexattr, PTHREAD_PROCESS_SHARED) != 0 || + U_SYSCALL(pthread_mutex_init, "%p,%p", mutex, &mutexattr) != 0) { U_RETURN(false); } @@ -588,9 +575,9 @@ bool UThread::initIPC(pthread_mutex_t* mutex, pthread_cond_t* cond) { pthread_condattr_t condattr; - if (U_SYSCALL(pthread_condattr_init, "%p", &condattr) == -1 || - U_SYSCALL(pthread_condattr_setpshared, "%p,%d", &condattr, PTHREAD_PROCESS_SHARED) == -1 || - U_SYSCALL(pthread_cond_init, "%p,%p", cond, &condattr) == -1) + if (U_SYSCALL(pthread_condattr_init, "%p", &condattr) != 0 || + U_SYSCALL(pthread_condattr_setpshared, "%p,%d", &condattr, PTHREAD_PROCESS_SHARED) != 0 || + U_SYSCALL(pthread_cond_init, "%p,%p", cond, &condattr) != 0) { U_RETURN(false); } diff --git a/src/ulib/timeval.cpp b/src/ulib/timeval.cpp index 4f4e36b1..ea91f0bd 100644 --- a/src/ulib/timeval.cpp +++ b/src/ulib/timeval.cpp @@ -127,8 +127,14 @@ long UTimeVal::restart() { U_TRACE(1, "UTimeVal::restart()") +#ifdef DEBUG + long tv_sec_old = u_now->tv_sec; +#endif + (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); + U_INTERNAL_ASSERT(tv_sec_old <= u_now->tv_sec) + struct timeval time_from_last_start = { u_now->tv_sec - tv_sec, u_now->tv_usec - tv_usec }; tv_sec = u_now->tv_sec; @@ -151,8 +157,14 @@ long UTimeVal::stop() { U_TRACE(1, "UTimeVal::stop()") +#ifdef DEBUG + long tv_sec_old = u_now->tv_sec; +#endif + (void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); + U_INTERNAL_ASSERT(tv_sec_old <= u_now->tv_sec) + struct timeval time_elapsed = { u_now->tv_sec - tv_sec, u_now->tv_usec - tv_usec }; if (time_elapsed.tv_usec < 0L) diff --git a/src/ulib/utility/http2.cpp b/src/ulib/utility/http2.cpp index 155c1838..1489d346 100644 --- a/src/ulib/utility/http2.cpp +++ b/src/ulib/utility/http2.cpp @@ -15,66 +15,75 @@ #include #include #include -#include - -// ============================ -// SETTINGS FRAME -// ============================ -// frame size = 18 (3*6) -// settings frame -// no flags -// stream id = 0 -// enable_push = 0 -// max_concurrent_streams = 100 -// initial_window_size = 262144 -// ============================ -// frame size = 0 -// settings frame -// flags ACK -// stream id = 0 -// ============================ -// (36 bytes) -// ============================ - -#define HTTP2_SETTINGS_HOST_BIN \ - "\x00\x00\x12" \ - "\x04" \ - "\x00" \ - "\x00\x00\x00\x00" \ - "\x00\x02" "\x00\x00\x00\x00" \ - "\x00\x03" "\x00\x00\x00\x64" \ - "\x00\x04" "\x00\x04\x00\x00" \ - "\x00\x00\x00" \ - "\x04" \ - "\x01" \ - "\x00\x00\x00\x00" - -#define HTTP2_FRAME_HEADER_SIZE 9 // The number of bytes of the frame header -#define HTTP2_INITIAL_WINDOW_SIZE_DEFAULT 65535 +#include // huff_sym_table, huff_decode_table int UHTTP2::nerror; +bool UHTTP2::settings_ack; void* UHTTP2::pConnectionEnd; uint32_t UHTTP2::hash_static_table[61]; const char* UHTTP2::upgrade_settings; UHTTP2::Stream* UHTTP2::pStream; -UHTTP2::Connection* UHTTP2::pConnection; UHTTP2::FrameHeader UHTTP2::frame; +UHTTP2::Connection* UHTTP2::pConnection; UHTTP2::HpackHeaderTableEntry UHTTP2::hpack_static_table[61]; -const UHTTP2::Settings UHTTP2::SETTINGS_DEFAULT = { - /* header_table_size */ 4096, - /* enable_push */ 1, - /* max_concurrent_streams */ UINT32_MAX, - /* initial_window_size */ HTTP2_INITIAL_WINDOW_SIZE_DEFAULT, - /* max_frame_size */ 16777215, - /* max_header_list_size */ UINT32_MAX -}; +// ================================ +// SETTINGS FRAME +// ================================ +// frame size = 18 (3*6) +// settings frame +// no flags +// stream id = 0 +// ================================ +// max_concurrent_streams = 100 +// initial_window_size = 2147483646 +// max_frame_size = 16777215 +// ================================ +// 9 + 18 = 27 bytes +// ================================ -const UHTTP2::Settings UHTTP2::SETTINGS_HOST = { +#define HTTP2_SETTINGS_BIN \ + "\x00\x00\x12" \ + "\x04" \ + "\x00" \ + "\x00\x00\x00\x00" \ + "\x00\x03" "\x00\x00\x00\x64" \ + "\x00\x04" "\x7f\xff\xff\xfe" \ + "\x00\x05" "\x00\xff\xff\xff" + +#define HTTP2_CONNECTION_UPGRADE_AND_SETTING_BIN \ + "HTTP/1.1 101 Switching Protocols\r\n" \ + "Connection: Upgrade\r\n" \ + "Upgrade: h2c\r\n\r\n" \ + "\x00\x00\x12" \ + "\x04" \ + "\x00" \ + "\x00\x00\x00\x00" \ + "\x00\x03" "\x00\x00\x00\x64" \ + "\x00\x04" "\x7f\xff\xff\xfe" \ + "\x00\x05" "\x00\xff\xff\xff" + +// ================================ +// SETTINGS ACK FRAME +// ================================ +// frame size = 0 +// settings frame +// flags ACK +// stream id = 0 +// ================================ +// (9 bytes) +// ================================ +#define HTTP2_SETTINGS_ACK \ + "\x00\x00\x00" \ + "\x04" \ + "\x01" \ + "\x00\x00\x00\x00" + +const UHTTP2::Settings UHTTP2::settings = { /* header_table_size = */ 4096, - /* enable_push = */ 0, + /* enable_push = */ 1, /* max_concurrent_streams = */ 100, - /* initial_window_size = */ 262144, + /* initial_window_size = */ 2147483646, // (2e31-1) - disables flow control for that receiver /* max_frame_size = */ 16777215, /* max_header_list_size */ UINT32_MAX }; @@ -420,24 +429,28 @@ void UHTTP2::dtor() U_TRACE(0, "UHTTP2::dtor()") } -void UHTTP2::sendError(int err) +#define HTTP2_FRAME_HEADER_SIZE 9 // The number of bytes of the frame header + +void UHTTP2::sendError() { - U_TRACE(0, "UHTTP2::sendError(%d)", err) + U_TRACE(0, "UHTTP2::sendError()") - char buffer[HTTP2_FRAME_HEADER_SIZE + 8]; + U_INTERNAL_ASSERT_DIFFERS(nerror, NO_ERROR) + + char buffer[HTTP2_FRAME_HEADER_SIZE+8] = { 0, 0, 4, // frame size + RST_STREAM, // header frame + 0, // end header flags + 0, 0, 0, 0, // stream id + 0, 0, 0, 0, + 0, 0, 0, 0 }; char* ptr = buffer; - ptr[0] = - ptr[1] = - ptr[4] = 0; - if (frame.stream_id) { - ptr[2] = 4; - ptr[3] = RST_STREAM; - *(uint32_t*)(ptr+5) = htonl(frame.stream_id); - *(uint32_t*)(ptr+9) = htonl(err); + *(uint32_t*)(ptr+9) = htonl(nerror); + + if (USocketExt::write(UServer_Base::csocket, buffer, HTTP2_FRAME_HEADER_SIZE+4, UServer_Base::timeoutMS) != HTTP2_FRAME_HEADER_SIZE+4) U_ClientImage_state = U_PLUGIN_HANDLER_ERROR; } else { @@ -450,79 +463,16 @@ void UHTTP2::sendError(int err) *(uint32_t*)(ptr+ 5) = 0; *(uint32_t*)(ptr+ 9) = htonl(pConnection->max_processed_stream_id); - *(uint32_t*)(ptr+13) = htonl(err); + *(uint32_t*)(ptr+13) = htonl(nerror); + + if (USocketExt::write(UServer_Base::csocket, buffer, HTTP2_FRAME_HEADER_SIZE+8, UServer_Base::timeoutMS) != HTTP2_FRAME_HEADER_SIZE+8) U_ClientImage_state = U_PLUGIN_HANDLER_ERROR; } - - if (USocketExt::write(UServer_Base::csocket, buffer, HTTP2_FRAME_HEADER_SIZE + 4, UServer_Base::timeoutMS) != HTTP2_FRAME_HEADER_SIZE + 4) - { - U_ClientImage_state = U_PLUGIN_HANDLER_ERROR; - } -} - -void UHTTP2::setConnection() -{ - U_TRACE(0, "UHTTP2::setConnection()") - - if (pConnection != UServer_Base::pClientImage->connection) - { - pConnection = (Connection*) UServer_Base::pClientImage->connection; - pConnectionEnd = (char*)pConnection + sizeof(Connection); - - pConnection->state = CONN_STATE_OPEN; - pConnection->peer_settings = SETTINGS_DEFAULT; - - pConnection->max_open_stream_id = - pConnection->num_responding_streams = - pConnection->max_processed_stream_id = 0; - - pStream = pConnection->open_streams; - - pStream->state = 0; - } -} - -void UHTTP2::setStream() -{ - U_TRACE(0, "UHTTP2::setStream()") - - U_INTERNAL_ASSERT_POINTER(pStream) - - if (pStream->id != frame.stream_id) - { - U_INTERNAL_ASSERT_POINTER(pConnection) - - if (frame.stream_id <= pConnection->max_open_stream_id) - { - for (pStream = pConnection->open_streams; pStream < pConnectionEnd; ++pStream) - { - if (pStream->id == frame.stream_id) return; - } - } - - nerror = FLOW_CONTROL_ERROR; - } -} - -void UHTTP2::resetReadBuffer(uint32_t length) -{ - U_TRACE(0, "UHTTP2::resetReadBuffer(%u)", length) - - UClientImage_Base::rstart = 0; - - UClientImage_Base::request->clear(); - - // NB: maybe we have read more data than necessary... - - if (UClientImage_Base::rbuffer->size() <= length) UClientImage_Base::rbuffer->setEmpty(); - else UClientImage_Base::rbuffer->moveToBeginDataInBuffer(length); } bool UHTTP2::updateSetting(const char* ptr, uint32_t len) { U_TRACE(0, "UHTTP2::updateSetting(%#.*S,%u)", len, ptr, len) - setConnection(); - U_INTERNAL_ASSERT_POINTER(pConnection) for (; len >= 6; len -= 6, ptr += 6) @@ -546,78 +496,28 @@ bool UHTTP2::updateSetting(const char* ptr, uint32_t len) pConnection->peer_settings.header_table_size, pConnection->peer_settings.enable_push, pConnection->peer_settings.max_concurrent_streams, pConnection->peer_settings.initial_window_size, pConnection->peer_settings.max_frame_size, pConnection->peer_settings.max_header_list_size) - if (len != 0) U_RETURN(false); + if (len == 0) U_RETURN(true); - U_RETURN(true); + U_RETURN(false); } -void UHTTP2::decodeFrame() +unsigned char* UHTTP2::hpackEncodeInt(unsigned char* dst, uint32_t value, uint8_t prefix_max) { - U_TRACE(0, "UHTTP2::decodeFrame()") + U_TRACE(0, "UHTTP2::hpackEncodeInt(%p,%u,%u)", dst, value, prefix_max) - const char* ptr = UClientImage_Base::rbuffer->c_pointer(UClientImage_Base::rstart); - - U_INTERNAL_DUMP("ptr = %#.4S", ptr) // "\000\000\f\004" (big endian: 0x11223344) - - if ((frame.type = ptr[3]) > CONTINUATION) + if (value <= prefix_max) *dst++ |= value; + else { - nerror = PROTOCOL_ERROR; + value -= prefix_max; - return; + U_INTERNAL_ASSERT(value <= 0x0fffffff) + + for (*dst++ |= value; value >= 256; value >>= 8) *dst++ = 0x80 | value; + + *dst++ = value; } - frame.length = ntohl(*(uint32_t*)ptr & 0x00ffffff) >> 8; - - U_INTERNAL_DUMP("frame.length = %#.4S", &frame.length) - - frame.flags = ptr[4]; - frame.stream_id = ntohl(*(uint32_t*)(ptr+5) & 0x7fffffff); - - U_DUMP("frame { length = %d stream_id = %d type = (%d, %s) flags = %d } = %#.*S", frame.length, - frame.stream_id, frame.type, getFrameTypeDescription(), frame.flags, frame.length, ptr + HTTP2_FRAME_HEADER_SIZE) - - if (frame.length > (int32_t)SETTINGS_HOST.max_frame_size) - { - nerror = FRAME_SIZE_ERROR; - - return; - } - - nerror = NO_ERROR; - - frame.payload = ptr + HTTP2_FRAME_HEADER_SIZE; -} - -void UHTTP2::readFrame() -{ - U_TRACE(0, "UHTTP2::readFrame()") - - uint32_t sz = UClientImage_Base::rbuffer->size() - UClientImage_Base::rstart; - - if (sz >= HTTP2_FRAME_HEADER_SIZE || - USocketExt::read(UServer_Base::csocket, *UClientImage_Base::rbuffer, U_SINGLE_READ, UServer_Base::timeoutMS, UHTTP::request_read_timeout)) - { - decodeFrame(); - - U_INTERNAL_DUMP("nerror = %u", nerror) - - if (nerror == NO_ERROR) - { - uint32_t len = HTTP2_FRAME_HEADER_SIZE + (uint32_t)frame.length; - - sz = UClientImage_Base::rbuffer->size() - UClientImage_Base::rstart; - - U_INTERNAL_DUMP("sz = %u len = %u", sz, len) - - if (sz >= len || - USocketExt::read(UServer_Base::csocket, *UClientImage_Base::rbuffer, len-sz, UServer_Base::timeoutMS, UHTTP::request_read_timeout)) - { - return; - } - } - } - - nerror = ERROR_INCOMPLETE; + return dst; } uint32_t UHTTP2::hpackDecodeInt(const unsigned char* src, const unsigned char* src_end, int32_t* pvalue, uint8_t prefix_max) @@ -648,6 +548,66 @@ end: U_RETURN(1 + 4-(src_end-src)); } +uint32_t UHTTP2::hpackEncodeString(unsigned char* dst, const char* src, uint32_t len) +{ + U_TRACE(0+256, "UHTTP2::hpackEncodeString(%p,%.*S,%u)", dst, len, src, len) + + U_INTERNAL_ASSERT_MAJOR(len, 0) + + uint64_t bits = 0; + int bits_left = 40; + unsigned char* ptr; + const char* src_end = src + len; + + UString buffer(len + 1024); + + unsigned char* _dst = (unsigned char*)buffer.data(); + unsigned char* _dst_end = _dst + len; + unsigned char* _dst_start = _dst; + + do { + const HuffSym* sym = huff_sym_table + *src++; + + bits |= (uint64_t)sym->code << (bits_left - sym->nbits); + + bits_left -= sym->nbits; + + while (bits_left <= 32) + { + *_dst++ = bits >> 32; + + bits <<= 8; + bits_left += 8; + } + } + while (src < src_end); + + if (bits_left != 40) + { + bits |= (1UL << bits_left) - 1; + + *_dst++ = bits >> 32; + } + + if (_dst >= _dst_end) // encode as-is + { + *dst = '\0'; + ptr = hpackEncodeInt(dst, len, (1<<7)-1); + + u__memcpy(ptr, src, len, __PRETTY_FUNCTION__); + + U_RETURN(ptr - dst + len); + } + + len = _dst - _dst_start; + *dst = '\x80'; + ptr = hpackEncodeInt(dst, len, (1<<7)-1); + + u__memcpy(ptr, _dst, len, __PRETTY_FUNCTION__); + + U_RETURN(ptr - dst + len); +} + uint32_t UHTTP2::hpackDecodeString(const unsigned char* src, const unsigned char* src_end, UString* pvalue) { U_TRACE(0+256, "UHTTP2::hpackDecodeString(%p,%p,%p)", src, src_end, pvalue) @@ -658,8 +618,7 @@ uint32_t UHTTP2::hpackDecodeString(const unsigned char* src, const unsigned char if (len <= 0) { -error: - pvalue->clear(); +err: pvalue->clear(); U_RETURN(nmove); } @@ -670,7 +629,7 @@ error: if (is_huffman == false) { - if ((src + len) > src_end) goto error; + if ((src + len) > src_end) goto err; (void) pvalue->replace((const char*)src, len); } @@ -686,12 +645,12 @@ error: { entry = huff_decode_table[state] + (*src >> 4); - if ((entry->flags & HUFF_FAIL) != 0) goto error; + if ((entry->flags & HUFF_FAIL) != 0) goto err; if ((entry->flags & HUFF_SYM) != 0) *dst++ = entry->sym; entry = huff_decode_table[entry->state] + (*src & 0x0f); - if ((entry->flags & HUFF_FAIL) != 0) goto error; + if ((entry->flags & HUFF_FAIL) != 0) goto err; if ((entry->flags & HUFF_SYM) != 0) *dst++ = entry->sym; state = entry->state; @@ -717,9 +676,9 @@ void UHTTP2::decodeHeaders(const char* ptr, const char* endptr) unsigned char c; const char* ptr1; UString name, value; - bool value_is_indexed; UHTTP2::HpackHeaderTableEntry* entry; - UHashMap* ptable = pConnection->itable; + bool value_is_indexed, continue100 = false; + UHashMap& ptable = pConnection->itable; while (ptr < endptr) { @@ -766,7 +725,7 @@ void UHTTP2::decodeHeaders(const char* ptr, const char* endptr) { // add the decoded header to the header table - ptable->hash = name.hash(); + ptable.hash = name.hash(); goto insert; } @@ -818,7 +777,7 @@ error: nerror = COMPRESSION_ERROR; (int)((char*)&&case_32-(char*)&&cdefault), /* 32 cookie */ 0,/* 33 date */ 0,/* 34 etag */ - 0,/* 35 expect */ + (int)((char*)&&case_35-(char*)&&cdefault), /* 35 expect */ 0,/* 36 expires */ 0,/* 37 from */ (int)((char*)&&case_38-(char*)&&cdefault), /* 38 host */ @@ -871,7 +830,7 @@ host: U_INTERNAL_ASSERT_EQUALS(value_is_indexed, false) UHTTP::setHostname(value.data(), sz); - ptable->hash = hash_static_table[37]; // host + ptable.hash = hash_static_table[37]; // host goto insert; @@ -931,7 +890,7 @@ case_4_5: // / - /index.html name = *str_path; - ptable->hash = hash_static_table[3]; // path + ptable.hash = hash_static_table[3]; // path // determine the value (if necessary) @@ -986,7 +945,7 @@ case_16: // accept-encoding: gzip, deflate U_INTERNAL_DUMP("U_http_is_accept_gzip = %C", U_http_is_accept_gzip) - ptable->hash = hash_static_table[15]; // accept_encoding + ptable.hash = hash_static_table[15]; // accept_encoding goto insert; @@ -1006,7 +965,7 @@ case_17: // accept-language U_INTERNAL_DUMP("Accept-Language: = %.*S", U_HTTP_ACCEPT_LANGUAGE_TO_TRACE) - ptable->hash = hash_static_table[16]; // accept_language + ptable.hash = hash_static_table[16]; // accept_language goto insert; @@ -1026,7 +985,7 @@ case_19: // accept U_INTERNAL_DUMP("Accept: = %.*S", U_HTTP_ACCEPT_TO_TRACE) - ptable->hash = hash_static_table[18]; // accept + ptable.hash = hash_static_table[18]; // accept goto insert; @@ -1044,7 +1003,7 @@ case_28: // content_length U_INTERNAL_DUMP("Content-Length: = %.*S U_http_info.clength = %u", U_STRING_TO_TRACE(value), U_http_info.clength) - ptable->hash = hash_static_table[27]; // content_length + ptable.hash = hash_static_table[27]; // content_length goto insert; @@ -1064,7 +1023,7 @@ case_31: // content_type U_INTERNAL_DUMP("Content-Type(%u): = %.*S", U_http_content_type_len, U_HTTP_CTYPE_TO_TRACE) - ptable->hash = hash_static_table[30]; // content_type + ptable.hash = hash_static_table[30]; // content_type goto insert; @@ -1084,10 +1043,33 @@ case_32: // cookie U_INTERNAL_DUMP("Cookie(%u): = %.*S", U_http_info.cookie_len, U_HTTP_COOKIE_TO_TRACE) - ptable->hash = hash_static_table[31]; // cookie + ptable.hash = hash_static_table[31]; // cookie goto insert; +case_35: // expect + + U_INTERNAL_ASSERT_EQUALS(value_is_indexed, false) + + ptr += hpackDecodeString((const unsigned char*)ptr, (const unsigned char*)endptr, &value); + + if (value.empty()) goto error; + + // NB: check for 'Expect: 100-continue' (as curl does)... + + continue100 = value.equal(U_CONSTANT_TO_PARAM("100-continue")); + + if (continue100 == false) + { + name = *str_expect; + + ptable.hash = hash_static_table[34]; // expect + + goto insert; + } + + continue; + case_40: // if-modified-since name = *str_if_modified_since; @@ -1102,7 +1084,7 @@ case_40: // if-modified-since U_INTERNAL_DUMP("If-Modified-Since = %u", U_http_info.if_modified_since) - ptable->hash = hash_static_table[39]; // if_modified_since + ptable.hash = hash_static_table[39]; // if_modified_since goto insert; @@ -1122,7 +1104,7 @@ case_50: // range U_INTERNAL_DUMP("Range = %.*S", U_HTTP_RANGE_TO_TRACE) - ptable->hash = hash_static_table[49]; // range + ptable.hash = hash_static_table[49]; // range goto insert; @@ -1142,7 +1124,7 @@ case_51: // referer U_INTERNAL_DUMP("Referer(%u): = %.*S", U_http_info.referer_len, U_HTTP_REFERER_TO_TRACE) - ptable->hash = hash_static_table[50]; // referer + ptable.hash = hash_static_table[50]; // referer goto insert; @@ -1168,14 +1150,14 @@ case_58: // user-agent U_INTERNAL_DUMP("User-Agent: = %.*S", U_HTTP_USER_AGENT_TO_TRACE) - ptable->hash = hash_static_table[57]; // user_agent + ptable.hash = hash_static_table[57]; // user_agent goto insert; cdefault: entry = hpack_static_table + --index; - ptable->hash = hash_static_table[index]; + ptable.hash = hash_static_table[index]; name = *(entry->name); if (value_is_indexed) value = *(entry->value); // determine the value (if necessary) @@ -1187,21 +1169,256 @@ cdefault: } insert: - ptable->insert(name, value); // add the decoded header to the header table + ptable.insert(name, value); // add the decoded header to the header table U_INTERNAL_DUMP("name = %V value = %V", name.rep, value.rep) } U_INTERNAL_DUMP("U_http_method_type = %B U_http_method_num = %d", U_http_method_type, U_http_method_num) + + if (U_http_info.clength) + { + U_INTERNAL_DUMP("U_http_info.clength = %u UHTTP::limit_request_body = %u", U_http_info.clength, UHTTP::limit_request_body) + + if (U_http_info.clength > UHTTP::limit_request_body) + { + U_http_info.nResponseCode = HTTP_ENTITY_TOO_LARGE; + + UClientImage_Base::setCloseConnection(); + + UHTTP::setResponse(0, 0); + + return; + } + + char buffer[HTTP2_FRAME_HEADER_SIZE+5] = { 0, 0, 5, // frame size + 1, // header frame + 4, // end header flags + 0, 0, 0, 0, // stream id + 8, 3, '1', '0', '0' }; // use literal header field without indexing - indexed name + + *(uint32_t*)(buffer+5) = htonl(frame.stream_id); + + if (USocketExt::write(UServer_Base::csocket, buffer, sizeof(buffer), UServer_Base::timeoutMS) != sizeof(buffer)) + { + nerror = FLOW_CONTROL_ERROR; + + return; + } + + (void) UClientImage_Base::body->reserve(U_http_info.clength); + } } -bool UHTTP2::manageHeaders(const char** p, const char** e) +void UHTTP2::readFrame() { - U_TRACE(0, "UHTTP2::manageHeaders(%p,%p)", p, e) + U_TRACE(0, "UHTTP2::readFrame()") + + U_INTERNAL_ASSERT_POINTER(pStream) + + uint32_t sz; + int32_t len; + const char* ptr; + +loop: + sz = UClientImage_Base::rbuffer->size(); + + U_INTERNAL_DUMP("UClientImage_Base::rbuffer->size() = %u UClientImage_Base::rstart = %u", sz, UClientImage_Base::rstart) + + if (sz == UClientImage_Base::rstart) + { + UClientImage_Base::rstart = 0; + + UClientImage_Base::rbuffer->setEmpty(); + + if (USocketExt::read(UServer_Base::csocket, *UClientImage_Base::rbuffer, U_SINGLE_READ, UServer_Base::timeoutMS, UHTTP::request_read_timeout) == false) + { + nerror = PROTOCOL_ERROR; + + return; + } + + sz = UClientImage_Base::rbuffer->size(); + } +#ifdef DEBUG + else + { + U_INTERNAL_ASSERT_MAJOR(sz-UClientImage_Base::rstart, HTTP2_FRAME_HEADER_SIZE) + } +#endif + + ptr = UClientImage_Base::rbuffer->c_pointer(UClientImage_Base::rstart); + + U_INTERNAL_DUMP("ptr = %#.4S", ptr) // "\000\000\f\004" (big endian: 0x11223344) + + if ((frame.type = ptr[3]) > CONTINUATION) + { + nerror = PROTOCOL_ERROR; + + return; + } + + frame.length = ntohl(*(uint32_t*)ptr & 0x00ffffff) >> 8; + + U_INTERNAL_DUMP("frame.length = %#.4S", &frame.length) + + frame.flags = ptr[4]; + frame.stream_id = ntohl(*(uint32_t*)(ptr+5) & 0x7fffffff); + + U_DUMP("frame { length = %d stream_id = %d type = (%d, %s) flags = %d } = %#.*S", frame.length, + frame.stream_id, frame.type, getFrameTypeDescription(), frame.flags, frame.length, ptr + HTTP2_FRAME_HEADER_SIZE) + + U_INTERNAL_ASSERT_MINOR(frame.length, (int32_t)settings.max_frame_size) + + len = UClientImage_Base::rbuffer->size() - (UClientImage_Base::rstart += HTTP2_FRAME_HEADER_SIZE) - frame.length; + + U_INTERNAL_DUMP("UClientImage_Base::rbuffer->size() = %u UClientImage_Base::rstart = %u frame.length = %u len = %d", sz, UClientImage_Base::rstart, frame.length, len) + + if (len >= 0 || + USocketExt::read(UServer_Base::csocket, *UClientImage_Base::rbuffer, -len, UServer_Base::timeoutMS, UHTTP::request_read_timeout)) + { + frame.payload = UClientImage_Base::rbuffer->c_pointer(UClientImage_Base::rstart); + UClientImage_Base::rstart += (uint32_t)frame.length; + + if (frame.type == WINDOW_UPDATE) + { + uint32_t window_size_increment = ntohl(*(uint32_t*)frame.payload) & 0x7fffffff; + + U_INTERNAL_DUMP("window_size_increment = %u", window_size_increment) + + if (frame.length != 4 || + window_size_increment == 0) + { + nerror = PROTOCOL_ERROR; + + goto err; + } + + if (frame.stream_id) pStream->output_window += window_size_increment; + else pConnection->output_window += window_size_increment; + + goto loop; + } + + if (frame.stream_id == 0) + { + if (frame.type == SETTINGS) + { + if ((frame.flags & FLAG_ACK) != 0) + { + if (frame.length) + { + nerror = FRAME_SIZE_ERROR; + + goto err; + } + + settings_ack = true; + } + else + { + if (updateSetting(frame.payload, frame.length) == false || + USocketExt::write(UServer_Base::csocket, U_CONSTANT_TO_PARAM(HTTP2_SETTINGS_ACK), UServer_Base::timeoutMS) != U_CONSTANT_SIZE(HTTP2_SETTINGS_ACK)) + { + nerror = PROTOCOL_ERROR; + + goto err; + } + } + + goto loop; + } + } + else + { + if (frame.type == PRIORITY) + { + // TODO + + goto loop; + } + + if (frame.type == HEADERS) + { + // open the stream + + U_INTERNAL_ASSERT_POINTER(pStream) + U_INTERNAL_ASSERT(pConnection->max_open_stream_id <= frame.stream_id) + + pStream->input_window = + pConnection->input_window = settings.initial_window_size; + pStream->output_window = + pConnection->output_window = pConnection->peer_settings.initial_window_size; + + pStream->id = + pConnection->max_open_stream_id = frame.stream_id; + pConnection->hpack_max_capacity = settings.header_table_size; + + pStream->state = ((frame.flags & FLAG_END_STREAM) != 0 ? STREAM_STATE_HALF_CLOSED : STREAM_STATE_OPEN); + + manageHeaders(); + + goto end; + } + + if (pStream->id != frame.stream_id) + { + if (frame.stream_id <= pConnection->max_open_stream_id) + { + for (pStream = pConnection->streams; pStream < pConnectionEnd; ++pStream) + { + if (pStream->id == frame.stream_id) goto next; + } + } + + nerror = FLOW_CONTROL_ERROR; + + goto err; + } + +next: if ((frame.flags & FLAG_END_STREAM) != 0) pStream->state = STREAM_STATE_HALF_CLOSED; + + if (frame.type == DATA) + { + manageData(); + + if (pStream->state != STREAM_STATE_HALF_CLOSED) goto loop; // we must wait for other DATA frames for the same stream... + + goto end; + } + + if (frame.type == RST_STREAM) + { + U_INTERNAL_ASSERT_EQUALS(pStream->state, STREAM_STATE_HALF_CLOSED) + + pStream->state = STREAM_STATE_CLOSED; + + uint32_t error = ntohl(*(uint32_t*)frame.payload); + + U_INTERNAL_DUMP("error = %u", error) + } + } + +end: nerror = NO_ERROR; + + return; + } + + nerror = ERROR_INCOMPLETE; + +err: + UClientImage_Base::rstart = 0; + + UClientImage_Base::rbuffer->setEmpty(); +} + +void UHTTP2::manageHeaders() +{ + U_TRACE(0, "UHTTP2::manageHeaders()") int32_t padlen; - const char* ptr = *p; - const char* endptr = *e; + const char* ptr; + const char* endptr = (ptr = frame.payload) + frame.length; if ((frame.flags & FLAG_PADDED) == 0) padlen = 0; else @@ -1212,17 +1429,12 @@ bool UHTTP2::manageHeaders(const char** p, const char** e) { nerror = PROTOCOL_ERROR; - U_RETURN(false); + return; } endptr -= padlen; } - // init the stream - - U_INTERNAL_ASSERT_POINTER(pStream) - U_INTERNAL_ASSERT(pConnection->max_open_stream_id <= frame.stream_id) - if ((frame.flags & FLAG_PRIORITY) == 0) { pStream->priority_exclusive = false; @@ -1235,7 +1447,7 @@ bool UHTTP2::manageHeaders(const char** p, const char** e) { nerror = PROTOCOL_ERROR; - U_RETURN(false); + return; } uint32_t u4 = ntohl(*(uint32_t*)ptr); @@ -1246,65 +1458,69 @@ bool UHTTP2::manageHeaders(const char** p, const char** e) pStream->priority_weight = (uint16_t)*ptr++ + 1; } - *p = ptr; - *e = endptr; + if ((frame.flags & FLAG_END_HEADERS) != 0) decodeHeaders(ptr, endptr); // parse header block fragment + else + { + // we must wait for CONTINUATION frames for the same stream... - pStream->id = - pConnection->max_open_stream_id = frame.stream_id; + U_INTERNAL_ASSERT_EQUALS(frame.flags & FLAG_END_HEADERS, 0) - pStream->input_window = - pConnection->input_window = SETTINGS_HOST.initial_window_size; - pStream->output_window = - pConnection->output_window = pConnection->peer_settings.initial_window_size; + uint32_t sz = (endptr - ptr); - pConnection->itable = U_NEW(UHashMap(53, setIndexStaticTable)); + UString bufferHeaders(ptr, sz, sz * 2); - pConnection->hpack_max_capacity = SETTINGS_DEFAULT.header_table_size; +wait_CONTINUATION: + readFrame(); - pStream->state = STREAM_STATE_RECV_PSUEDO_HEADERS; - if ((frame.flags & FLAG_END_STREAM) != 0) pStream->state |= STREAM_STATE_HALF_CLOSED; + if (nerror != NO_ERROR || + frame.type != CONTINUATION || + frame.stream_id != pStream->id) + { + nerror = PROTOCOL_ERROR; - if ((frame.flags & FLAG_END_HEADERS) != 0) U_RETURN(true); + return; + } - U_RETURN(false); + (void) bufferHeaders.append(frame.payload, frame.length); + + if ((frame.flags & FLAG_END_HEADERS) == 0) goto wait_CONTINUATION; + + ptr = bufferHeaders.data(); + + decodeHeaders(ptr, ptr + bufferHeaders.size()); // parse header block fragment + } } void UHTTP2::manageData() { U_TRACE(0, "UHTTP2::manageData()") -} -void UHTTP2::managePriority() -{ - U_TRACE(0, "UHTTP2::managePriority()") -} + if ((frame.flags & FLAG_PADDED) == 0) + { + U_INTERNAL_ASSERT((uint32_t)frame.length <= U_http_info.clength) -void UHTTP2::manageWindowUpdate() -{ - U_TRACE(0, "UHTTP2::manageWindowUpdate()") + (void) UClientImage_Base::body->append(frame.payload, frame.length); - uint32_t window_size_increment = ntohl(*(uint32_t*)frame.payload) & 0x7fffffff; + return; + } - U_INTERNAL_DUMP("window_size_increment = %u", window_size_increment) + uint32_t sz; + int32_t padlen; + const char* ptr; + const char* endptr = (ptr = frame.payload) + frame.length; - if (frame.length != 4 || - window_size_increment == 0) + if (frame.length < (padlen = *ptr++)) { nerror = PROTOCOL_ERROR; return; } - if (frame.stream_id == 0) - { - pConnection->output_window += window_size_increment; + sz = (endptr - padlen) - ptr; - return; - } + U_INTERNAL_ASSERT(sz <= U_http_info.clength) - setStream(); - - if (nerror == NO_ERROR) pStream->output_window += window_size_increment; + (void) UClientImage_Base::body->append(ptr, sz); } bool UHTTP2::manageSetting() @@ -1316,15 +1532,21 @@ bool UHTTP2::manageSetting() U_INTERNAL_DUMP("HTTP2-Settings: = %.*S U_http_method_type = %B", U_http2_settings_len, UHTTP2::upgrade_settings, U_http_method_type) if (U_http2_settings_len && - USocketExt::write(UServer_Base::csocket, U_CONSTANT_TO_PARAM(HTTP2_CONNECTION_UPGRADE), UServer_Base::timeoutMS) != - U_CONSTANT_SIZE(HTTP2_CONNECTION_UPGRADE)) + USocketExt::write(UServer_Base::csocket, U_CONSTANT_TO_PARAM(HTTP2_CONNECTION_UPGRADE_AND_SETTING_BIN), UServer_Base::timeoutMS) != + U_CONSTANT_SIZE(HTTP2_CONNECTION_UPGRADE_AND_SETTING_BIN)) { U_RETURN(false); } + U_INTERNAL_ASSERT(UClientImage_Base::request->same(*UClientImage_Base::rbuffer)) + + UClientImage_Base::request->clear(); + // maybe we have read more data than necessary... - uint32_t sz = UClientImage_Base::request->size(); + uint32_t sz = UClientImage_Base::rbuffer->size(); + + U_INTERNAL_ASSERT_MAJOR(sz, 0) if (sz > U_http_info.endHeader) UClientImage_Base::rstart = U_http_info.endHeader; else @@ -1340,156 +1562,67 @@ bool UHTTP2::manageSetting() } UClientImage_Base::rstart = 0; + + sz = UClientImage_Base::rbuffer->size(); } const char* ptr = UClientImage_Base::rbuffer->c_pointer(UClientImage_Base::rstart); - if (u_get_unalignedp64(ptr) == U_MULTICHAR_CONSTANT64( 'P', 'R','I',' ', '*', ' ', 'H', 'T') && - u_get_unalignedp64(ptr+8) == U_MULTICHAR_CONSTANT64( 'T', 'P','/','2', '.', '0','\r','\n') && - u_get_unalignedp64(ptr+16) == U_MULTICHAR_CONSTANT64('\r','\n','S','M','\r','\n','\r','\n')) - { - if (U_http2_settings_len) - { - UString buffer(U_CAPACITY); - - UBase64::decodeUrl(upgrade_settings, U_http2_settings_len, buffer); - - if (buffer.empty() || - updateSetting(U_STRING_TO_PARAM(buffer)) == false) - { - U_RETURN(false); - } - } - - U_ClientImage_data_missing = true; - - resetReadBuffer(UClientImage_Base::rstart + U_CONSTANT_SIZE(HTTP2_CONNECTION_PREFACE)); - } - - readFrame(); - - if ( frame.stream_id != 0 || - frame.type != SETTINGS || - (frame.flags & FLAG_ACK) != 0) - { - nerror = PROTOCOL_ERROR; - } - - if (nerror != NO_ERROR) goto error; - - if (USocketExt::write(UServer_Base::csocket, U_CONSTANT_TO_PARAM(HTTP2_SETTINGS_HOST_BIN), UServer_Base::timeoutMS) != - U_CONSTANT_SIZE(HTTP2_SETTINGS_HOST_BIN)) + if (u_get_unalignedp64(ptr) != U_MULTICHAR_CONSTANT64( 'P', 'R','I',' ', '*', ' ', 'H', 'T') || + u_get_unalignedp64(ptr+8) != U_MULTICHAR_CONSTANT64( 'T', 'P','/','2', '.', '0','\r','\n') || + u_get_unalignedp64(ptr+16) != U_MULTICHAR_CONSTANT64('\r','\n','S','M','\r','\n','\r','\n')) { U_RETURN(false); } - if (updateSetting(UClientImage_Base::rbuffer->c_pointer(HTTP2_FRAME_HEADER_SIZE), frame.length) == false) + pConnection = (Connection*)UServer_Base::pClientImage->connection; + pConnectionEnd = (char*)pConnection + sizeof(Connection); + + pConnection->state = CONN_STATE_OPEN; + pConnection->peer_settings = settings; + + pConnection->max_open_stream_id = + pConnection->num_responding_streams = + pConnection->max_processed_stream_id = 0; + + pStream = pConnection->streams; + + pStream->state = STREAM_STATE_IDLE; + + if (U_http2_settings_len == 0) { - nerror = PROTOCOL_ERROR; - - goto error; - } - -loop: - sz = HTTP2_FRAME_HEADER_SIZE + (uint32_t)frame.length; - - U_INTERNAL_DUMP("sz = %u", sz) - - if (UClientImage_Base::rbuffer->size() > sz) UClientImage_Base::rstart += sz; - else UClientImage_Base::rbuffer->setEmpty(); - - readFrame(); - - if (nerror != NO_ERROR) goto error; - - if (frame.stream_id) - { - switch (frame.type) - { - case DATA: manageData(); break; - case PRIORITY: managePriority(); break; - case HEADERS: - { - const char* endptr = (ptr = frame.payload) + frame.length; - - if (manageHeaders(&ptr, &endptr)) decodeHeaders(ptr, endptr); // parse header block fragment - else - { - if (nerror != NO_ERROR) goto error; - - // we must wait for CONTINUATION frames for the same stream... - - U_INTERNAL_ASSERT_EQUALS(frame.flags & FLAG_END_HEADERS, 0) - - sz = (endptr - ptr); - - UString bufferHeaders(ptr, sz, sz * 2); - -wait_for_CONTINUATION: - resetReadBuffer(UClientImage_Base::rstart + HTTP2_FRAME_HEADER_SIZE + (uint32_t)frame.length); - - readFrame(); - - if (nerror != NO_ERROR) goto error; - - if (frame.type != CONTINUATION || - frame.stream_id != pConnection->max_open_stream_id) - { - nerror = PROTOCOL_ERROR; - - goto error; - } - - (void) bufferHeaders.append(frame.payload, frame.length); - - if ((frame.flags & FLAG_END_HEADERS) == 0) goto wait_for_CONTINUATION; - - ptr = bufferHeaders.data(); - - decodeHeaders(ptr, ptr + bufferHeaders.size()); // parse header block fragment - } - } - break; - - case CONTINUATION: - { - nerror = PROTOCOL_ERROR; - - goto error; - } - - default: goto loop; // we wait for SETTINGS ack... - } + if (USocketExt::write(UServer_Base::csocket, U_CONSTANT_TO_PARAM(HTTP2_SETTINGS_BIN), UServer_Base::timeoutMS) != U_CONSTANT_SIZE(HTTP2_SETTINGS_BIN)) U_RETURN(false); } else { - if (frame.type == WINDOW_UPDATE) + UString buffer(U_CAPACITY); + + UBase64::decodeUrl(upgrade_settings, U_http2_settings_len, buffer); + + if (buffer.empty() || + updateSetting(U_STRING_TO_PARAM(buffer)) == false) { - manageWindowUpdate(); - - if (nerror != NO_ERROR) goto error; - - goto loop; - } - - // must be SETTINGS ack... - - if ( frame.type != SETTINGS || - (frame.flags & FLAG_ACK) == 0) - { - nerror = PROTOCOL_ERROR; + U_RETURN(false); } } + settings_ack = false; + + UClientImage_Base::rstart += U_CONSTANT_SIZE(HTTP2_CONNECTION_PREFACE); + +loop: + readFrame(); + if (nerror == NO_ERROR) { - resetReadBuffer(UClientImage_Base::rstart + HTTP2_FRAME_HEADER_SIZE + (uint32_t)frame.length); + U_INTERNAL_DUMP("settings_ack = %b", settings_ack) + + if (settings_ack == false) goto loop; // we wait for SETTINGS ack... U_RETURN(true); } -error: - sendError(nerror); + sendError(); U_RETURN(false); } diff --git a/src/ulib/utility/semaphore.cpp b/src/ulib/utility/semaphore.cpp index 528b733d..7ea1d532 100644 --- a/src/ulib/utility/semaphore.cpp +++ b/src/ulib/utility/semaphore.cpp @@ -55,22 +55,22 @@ void USemaphore::init(sem_t* ptr, int resource) U_INTERNAL_ASSERT_DIFFERS(first, next) } -# ifdef DEBUG +# ifdef DEBUG int _value = getValue(); if (_value != resource) U_ERROR("USemaphore::init(%p,%u) failed - value = %d", ptr, resource, _value); -# endif +# endif #else -# ifdef _MSWINDOWS_ +# ifdef _MSWINDOWS_ psem = (sem_t*) ::CreateSemaphore((LPSECURITY_ATTRIBUTES)NULL, (LONG)resource, 1000000, (LPCTSTR)NULL); -# else +# else if (flock == 0) { flock = U_NEW(UFile); if (flock->mkTemp(0) == false) U_ERROR("USemaphore::init(%p,%u) failed", ptr, resource); } -# endif +# endif #endif } @@ -88,11 +88,11 @@ USemaphore::~USemaphore() (void) sem_destroy(psem); // Free resources associated with semaphore object sem #else -# ifdef _MSWINDOWS_ +# ifdef _MSWINDOWS_ ::CloseHandle((HANDLE)psem); -# else +# else (void) flock->close(); -# endif +# endif #endif } @@ -116,11 +116,11 @@ void USemaphore::post() U_INTERNAL_DUMP("value = %d", getValue()) #else -# ifdef _MSWINDOWS_ +# ifdef _MSWINDOWS_ ::ReleaseSemaphore((HANDLE)psem, 1, (LPLONG)NULL); -# else +# else (void) flock->unlock(); -# endif +# endif #endif } @@ -190,11 +190,11 @@ bool USemaphore::wait(time_t timeoutMS) if (rc == 0) U_RETURN(true); #else -# ifdef _MSWINDOWS_ +# ifdef _MSWINDOWS_ if (::WaitForSingleObject((HANDLE)psem, timeoutMS) == WAIT_OBJECT_0) U_RETURN(true); -# else +# else if (flock->unlock()) U_RETURN(true); -# endif +# endif #endif U_RETURN(false); @@ -234,11 +234,11 @@ wait: U_INTERNAL_ASSERT_EQUALS(rc, 0) #else -# ifdef _MSWINDOWS_ +# ifdef _MSWINDOWS_ (void) ::WaitForSingleObject((HANDLE)psem, INFINITE); -# else +# else (void) flock->unlock(); -# endif +# endif #endif } diff --git a/src/ulib/utility/services.cpp b/src/ulib/utility/services.cpp index d64eadf8..53d947db 100644 --- a/src/ulib/utility/services.cpp +++ b/src/ulib/utility/services.cpp @@ -19,6 +19,10 @@ #include #include +#ifdef USE_LIBUUID +# include +#endif + unsigned char UServices::key[16]; /* coverity[+alloc] */ @@ -222,13 +226,15 @@ int UServices::askToLDAP(UString* pinput, UHashMap* ptable, const char* U_RETURN(0); } +// creat a new unique UUID value - 8 bytes (64 bits) long + uint64_t UServices::getUniqUID() { U_TRACE(0, "UServices::getUniqUID()") static uint64_t unique_num; - if (unique_num == 0) unique_num = (uint64_t)u_now->tv_usec; + if (unique_num == 0) unique_num = (uint64_t)u_seed_hash; uint64_t _uid = (((uint64_t)u_pid) << 56) | ((((uint64_t)u_now->tv_sec) & (0xfffffULL << 20)) << 16) | @@ -237,27 +243,75 @@ uint64_t UServices::getUniqUID() U_RETURN(_uid); } -#ifdef USE_LIBUUID // creat a new unique UUID value - 16 bytes (128 bits) long // return from the binary representation a 36-byte string (plus tailing '\0') of the form 1b4e28ba-2fa1-11d2-883f-0016d3cca427 -uuid_t UServices::uuid; // typedef unsigned char uuid_t[16]; - UString UServices::getUUID() { U_TRACE(1, "UServices::getUUID()") - UString id(37U); + UString buffer(36U); + char* id = buffer.data(); - U_SYSCALL_VOID(uuid_generate, "%p", uuid); - U_SYSCALL_VOID(uuid_unparse, "%p", uuid, id.data()); +#ifdef USE_LIBUUID + uuid_t uuid; // typedef unsigned char uuid_t[16]; - id.size_adjust(36U); + U_SYSCALL_VOID(uuid_generate, "%p", uuid); + U_SYSCALL_VOID(uuid_unparse, "%p,%p", uuid, id); +#else + static unsigned short clock_seq; - U_RETURN_STRING(id); -} + unsigned short clock_seq_low = ++clock_seq & 0xff; + unsigned short clock_seq_hi_variant = (clock_seq >> 8) & 0x3f; + + uint64_t node = getUniqUID(), + ossp_time = (((uint64_t)u_now->tv_sec + (141427ULL * 24ULL * 60ULL * 60ULL)) * 10000000ULL) + (u_now->tv_usec > 0 ? u_now->tv_usec * 10 : 0); + + uint32_t time_low = htonl( ossp_time & 0xffffffff), + time_mid = htons((ossp_time >> 32) & 0x0000ffff), + time_hi_and_version = htons((ossp_time >> 48) & 0x00000fff); + +#define U_APPEND_HEX(value, offset) \ + *id++ = u_hex_upper[(((char*)&value)[offset] >> 4) & 0x0F]; \ + *id++ = u_hex_upper[(((char*)&value)[offset] ) & 0x0F]; + + U_APPEND_HEX(time_low, 0); + U_APPEND_HEX(time_low, 1); + U_APPEND_HEX(time_low, 2); + U_APPEND_HEX(time_low, 3); + + *id++ = '-'; + + U_APPEND_HEX(time_mid, 0); + U_APPEND_HEX(time_mid, 1); + + *id++ = '-'; + + U_APPEND_HEX(time_hi_and_version, 0); + U_APPEND_HEX(time_hi_and_version, 1); + + *id++ = '-'; + + U_APPEND_HEX(clock_seq_hi_variant, 0); + U_APPEND_HEX(clock_seq_low, 0); + + *id++ = '-'; + + U_APPEND_HEX(node, 0); + U_APPEND_HEX(node, 1); + U_APPEND_HEX(node, 2); + U_APPEND_HEX(node, 3); + U_APPEND_HEX(node, 4); + U_APPEND_HEX(node, 5); + +#undef U_APPEND_HEX(value, offset) #endif + buffer.size_adjust(36U); + + U_RETURN_STRING(buffer); +} + #ifdef USE_LIBSSL # include # include diff --git a/src/ulib/utility/uhttp.cpp b/src/ulib/utility/uhttp.cpp index 7bd20d07..e5767cc9 100644 --- a/src/ulib/utility/uhttp.cpp +++ b/src/ulib/utility/uhttp.cpp @@ -956,7 +956,7 @@ void UHTTP::ctor() /** * Set up static environment variables * ------------------------------------------------------------------------------------------------------------------------------------------- - * server static variable Description + * server static variable Description * ------------------------------------------------------------------------------------------------------------------------------------------- * SERVER_PORT * SERVER_ADDR @@ -966,14 +966,14 @@ void UHTTP::ctor() * GATEWAY_INTERFACE CGI specification revision with which this server complies. Format: CGI/revision * ------------------------------------------------------------------------------------------------------------------------------------------- * Example: - * ---------------------------------------------------------------------------------------------------------------------------- + * ------------------------------------------------------------------------------------------------------------------------------------------- * SERVER_PORT=80 * SERVER_ADDR=127.0.0.1 * SERVER_NAME=localhost * DOCUMENT_ROOT="/var/www/localhost/htdocs" * SERVER_SOFTWARE=Apache * GATEWAY_INTERFACE=CGI/1.1 - * ---------------------------------------------------------------------------------------------------------------------------- + * ------------------------------------------------------------------------------------------------------------------------------------------- */ U_INTERNAL_ASSERT_POINTER(UServer_Base::cenvironment) @@ -1047,14 +1047,14 @@ next: cache_file = U_NEW(UHashMap); #ifdef U_STATIC_ONLY -# if defined(U_ALIAS) && !defined(U_STATIC_SERVLET_WI_AUTH) +# if defined(U_ALIAS) && !defined(U_STATIC_SERVLET_WI_AUTH) U_INTERNAL_ASSERT_EQUALS(virtual_host, false) -# endif +# endif /** * I do know that to include code in the middle of a function is hacky and dirty, but this is the best solution that I could figure out. * If you have some idea to clean it up, please, don't hesitate and let me know */ -# include "../net/server/plugin/usp/loader.autoconf.cpp" +# include "../net/server/plugin/usp/loader.autoconf.cpp" #endif U_INTERNAL_ASSERT_EQUALS(file_not_in_cache_data, 0) @@ -1101,7 +1101,7 @@ next: # ifdef U_STDCPP_ENABLE if (content_cache) { - n += (content_cache.size() / (1024 + 512)); // NB: we assume as medium file size ~1.5k... + n += (content_cache.size() / (1024 + 512)); // NB: we assume as medium file size something like ~1.5k... UString2Object(U_STRING_TO_PARAM(content_cache), *cache_file); @@ -1492,7 +1492,15 @@ __pure bool UHTTP::isMobile() } /** + * --------------------------------------------------------------------------------------------------------------------------- * HTTP message + * --------------------------------------------------------------------------------------------------------------------------- + * There are four parts to an HTTP request: + * --------------------------------------------------------------------------------------------------------------------------- + * 1) the request line [REQUIRED]: the method, the URL, the version of the protocol + * 2) the request headers [OPTIONAL]: a series of lines (one per) in the format of name, colon(:), and the value of the header + * 3) a blank line [REQUIRED]: worth mentioning by itself + * 4) the request Body [OPTIONAL]: used in POST/PUT/PATCH requests to send content to the server * ====================================================================================== * Read the request line and attached headers. A typical http request will take the form: * ====================================================================================== @@ -1641,14 +1649,18 @@ int UHTTP::handlerDataPending() U_RETURN(-1); } - // TODO: HTTP/2 implementation + U_ClientImage_data_missing = false; + + UClientImage_Base::setRequestNeedProcessing(); + + (void) manageRequest(); /* return 1 // child of parallelization return -1 // parent of parallelization */ - U_RETURN(-1); + U_RETURN(0); } else #endif @@ -1661,22 +1673,26 @@ bool UHTTP::scanfHeaderRequest(const char* ptr, uint32_t size) U_TRACE(0, "UHTTP::scanfHeaderRequest(%.*S,%u)", size, ptr, size) /** - * ------------------------------------------------------------------ - * Check HTTP request. + * ------------------------------------------------------------------- + * Check HTTP request + * ------------------------------------------------------------------- * The default is GET for input requests and POST for output requests. * Other possible alternatives are: - * ------------------------------------------------------------------ + * ------------------------------------------------------------------- * - PUT * - HEAD * - COPY * - PATCH * - DELETE * - OPTIONS - * ---------------------- NOT implemented --------------------------- + * ---------------------- NOT implemented ---------------------------- * - CONNECT * - TRACE (because can send client cookie information, dangerous...) - * ------------------------------------------------------------------ - * See http://ietf.org/rfc/rfc2616.txt for further information about HTTP request methods + * ------------------------------------------------------------------- + * for further information about HTTP request methods see: + * + * http://ietf.org/rfc/rfc2616.txt + * ------------------------------------------------------------------- */ unsigned char c; @@ -3169,17 +3185,6 @@ bool UHTTP::callService(const UString& path) // NB: it is used also by server_pl U_RETURN(true); } -/** - * --------------------------------------------------------------------------------------------------------------------------- - * There are four parts to an HTTP request: - * --------------------------------------------------------------------------------------------------------------------------- - * 1) the request line [REQUIRED]: the method, the URL, the version of the protocol - * 2) the request headers [OPTIONAL]: a series of lines (one per) in the format of name, colon(:), and the value of the header - * 3) a blank line [REQUIRED]: worth mentioning by itself - * 4) the request Body [OPTIONAL]: used in POST/PUT/PATCH requests to send content to the server - * --------------------------------------------------------------------------------------------------------------------------- - */ - bool UHTTP::handlerCache() { U_TRACE(0, "UHTTP::handlerCache()") @@ -3338,7 +3343,6 @@ int UHTTP::handlerREAD() U_INTERNAL_ASSERT(*UClientImage_Base::request) - const char* ptr; bool result_read_body; // ------------------------------ @@ -3452,8 +3456,7 @@ dmiss: UClientImage_Base::setRequestProcessed(); U_INTERNAL_ASSERT_EQUALS(U_ClientImage_data_missing, false) - if (result_read_body) UClientImage_Base::size_request += U_http_info.clength; - else + if (result_read_body == false) { U_INTERNAL_DUMP("UServer_Base::csocket->isClosed() = %b UClientImage_Base::wbuffer(%u) = %V", UServer_Base::csocket->isClosed(), UClientImage_Base::wbuffer->size(), UClientImage_Base::wbuffer->rep) @@ -3464,11 +3467,22 @@ dmiss: UClientImage_Base::setRequestProcessed(); U_RETURN(U_PLUGIN_HANDLER_FINISHED); } + + UClientImage_Base::size_request += U_http_info.clength; } #endif + return manageRequest(); +} + +int UHTTP::manageRequest() +{ + U_TRACE(0, "UHTTP::manageRequest()") + // check the HTTP message + U_INTERNAL_DUMP("U_ClientImage_request = %d %B", U_ClientImage_request, U_ClientImage_request) + U_ASSERT(UClientImage_Base::isRequestNotFound()) // manage alias uri @@ -3501,6 +3515,7 @@ dmiss: UClientImage_Base::setRequestProcessed(); if (valias) { UString str; + const char* ptr; int i, n = valias->size(); // Ex: /admin /admin.html @@ -3512,7 +3527,6 @@ dmiss: UClientImage_Base::setRequestProcessed(); int flag = 0; str = (*valias)[i]; - ptr = str.data(); int len = str.size(); @@ -3624,7 +3638,7 @@ set_uri: U_http_info.uri = alias->data(); // we check if it is present as shared file (without the virtual host prefix) // ------------------------------------------------------------------------------ # ifndef U_SERVER_CAPTIVE_PORTAL - ptr = pathname->c_pointer(u_cwd_len); + const char* ptr = pathname->c_pointer(u_cwd_len); # ifdef U_ALIAS U_INTERNAL_DUMP("virtual_host = %b U_http_host_vlen = %u U_http_is_request_nostat = %b", virtual_host, U_http_host_vlen, U_http_is_request_nostat) @@ -4224,9 +4238,9 @@ void UHTTP::setEndRequestProcessing() } # endif - U_INTERNAL_ASSERT_EQUALS(U_HTTP_DATE2, iov_vec[2].iov_base) + U_INTERNAL_ASSERT_EQUALS(iov_vec[2].iov_base, ULog::date.date2) - ULog::updateStaticDate(U_HTTP_DATE2, 2); + ULog::updateDate2(); UServer_Base::apache_like_log->write(iov_vec, 10); @@ -5199,11 +5213,11 @@ uint32_t UHTTP::processForm() { U_ASSERT(isPOST()) - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // POST - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Content-Type: application/x-www-form-urlencoded OR multipart/form-data... - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- if (U_HTTP_CTYPE_MEMEQ("application/x-www-form-urlencoded")) tmp = *UClientImage_Base::body; else @@ -5438,6 +5452,13 @@ UString UHTTP::getHeaderForResponse() UClientImage_Base::setRequestProcessed(); +#ifndef U_HTTP2_DISABLE + if (U_http_version == '2') + { + return UString::getStringNull(); + } +#endif + UClientImage_Base::setHeaderForResponse(6+29+2+12+2); // Date: Wed, 20 Jun 2012 11:43:17 GMT\r\nServer: ULib\r\n if (U_http_info.nResponseCode == HTTP_NOT_IMPLEMENTED || @@ -5665,7 +5686,8 @@ void UHTTP::setResponse(const UString* content_type, UString* pbody) "
ULib Server
\r\n" \ "\r\n" -/*------------------------------------------------------------------------------------------------------------------ +/** + * ------------------------------------------------------------------------------------------------------------------ * http://sebastians-pamphlets.com/the-anatomy-of-http-redirects-301-302-307/ * ------------------------------------------------------------------------------------------------------------------ * HTTP/1.0 @@ -5695,6 +5717,7 @@ void UHTTP::setResponse(const UString* content_type, UString* pbody) * the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new * URI(s), since many pre-HTTP/1.1 user agents do not understand the 307 status. Therefore, the note SHOULD contain the * information necessary for a user to repeat the original request on the new URI. + * ------------------------------------------------------------------------------------------------------------------ */ void UHTTP::setRedirectResponse(int mode, const char* ptr_location, uint32_t len_location) @@ -9598,12 +9621,12 @@ void UHTTP::initApacheLikeLog() iov_vec[1].iov_base = (caddr_t) " - - ["; iov_vec[1].iov_len = U_CONSTANT_SIZE(" - - ["); - iov_vec[2].iov_base = (caddr_t) U_HTTP_DATE2; // %d/%b/%Y:%T %z - 21/May/2012:16:29:41 +0200 + iov_vec[2].iov_base = (caddr_t)ULog::date.date2; // %d/%b/%Y:%T %z - 21/May/2012:16:29:41 +0200 iov_vec[2].iov_len = 26; iov_vec[3].iov_base = (caddr_t) "] \""; iov_vec[3].iov_len = U_CONSTANT_SIZE("] \""); // request - iov_vec[5].iov_base = (caddr_t) iov_buffer; // response_code, body_len + iov_vec[5].iov_base = (caddr_t)iov_buffer; // response_code, body_len // referer iov_vec[7].iov_base = (caddr_t) "\" \""; iov_vec[7].iov_len = U_CONSTANT_SIZE("\" \""); diff --git a/tests/examples/FrameworkBenchmarks.sh b/tests/examples/FrameworkBenchmarks.sh index 644d8395..18d72496 100755 --- a/tests/examples/FrameworkBenchmarks.sh +++ b/tests/examples/FrameworkBenchmarks.sh @@ -22,9 +22,9 @@ export ORM_DRIVER ORM_OPTION UMEMPOOL # ---------------------------------------------------------------------------------------------------------------------------------------------------------- # PLAINTEXT # ---------------------------------------------------------------------------------------------------------------------------------------------------------- - UMEMPOOL="982,0,0,36,9846,-24,-23,1727,1151" - sed -i "s|TCP_LINGER_SET .*|TCP_LINGER_SET 0|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg - sed -i "s|LISTEN_BACKLOG .*|LISTEN_BACKLOG 16384|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg +#UMEMPOOL="982,0,0,36,9846,-24,-23,1727,1151" +#sed -i "s|TCP_LINGER_SET .*|TCP_LINGER_SET 0|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg +#sed -i "s|LISTEN_BACKLOG .*|LISTEN_BACKLOG 16384|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg #sed -i "s|CLIENT_THRESHOLD .*|CLIENT_THRESHOLD 4000|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg #sed -i "s|CLIENT_FOR_PARALLELIZATION .*|CLIENT_FOR_PARALLELIZATION 8000|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg # ---------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -58,9 +58,9 @@ export ORM_DRIVER ORM_OPTION UMEMPOOL # ---------------------------------------------------------------------------------------------------------------------------------------------------------- # JSON # ---------------------------------------------------------------------------------------------------------------------------------------------------------- -#UMEMPOOL="56,0,0,40,150,-24,-13,-20,0" -#sed -i "s|TCP_LINGER_SET .*|TCP_LINGER_SET 0|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg -#sed -i "s|LISTEN_BACKLOG .*|LISTEN_BACKLOG 256|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg + UMEMPOOL="56,0,0,40,150,-24,-13,-20,0" + sed -i "s|TCP_LINGER_SET .*|TCP_LINGER_SET 0|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg + sed -i "s|LISTEN_BACKLOG .*|LISTEN_BACKLOG 256|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg #sed -i "s|CLIENT_THRESHOLD .*|CLIENT_THRESHOLD 50|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg #sed -i "s|CLIENT_FOR_PARALLELIZATION .*|CLIENT_FOR_PARALLELIZATION 100|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg # ---------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg b/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg index a39d11df..bd9328d6 100644 --- a/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg +++ b/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg @@ -3,7 +3,7 @@ userver { PORT 8080 PREFORK_CHILD 4 TCP_LINGER_SET 0 - LISTEN_BACKLOG 16384 + LISTEN_BACKLOG 256 DOCUMENT_ROOT benchmark/FrameworkBenchmarks/ULib/www PID_FILE benchmark/FrameworkBenchmarks/ULib/userver_tcp.pid diff --git a/tests/examples/web_server_multiclient.test b/tests/examples/web_server_multiclient.test index 64e14fea..415c1442 100755 --- a/tests/examples/web_server_multiclient.test +++ b/tests/examples/web_server_multiclient.test @@ -16,10 +16,11 @@ rm -f $DOC_ROOT/web_server_multiclient.log* \ trace.*userver_*.[0-9]* object.*userver_*.[0-9]* stack.*userver_*.[0-9]* mempool.*userver_*.[0-9]* \ $DOC_ROOT/trace.*userver_*.[0-9]* $DOC_ROOT/object.*userver_*.[0-9]* $DOC_ROOT/stack.*userver_*.[0-9]* $DOC_ROOT/mempool.*userver_*.[0-9]* -#UTRACE="0 100M 0" +#UTRACE="5 100M 0" +#UTRACE_SIGNAL="0 100M -1" #UOBJDUMP="0 10M 100" #USIMERR="error.sim" - export UTRACE UOBJDUMP USIMERR +export UTRACE UOBJDUMP USIMERR UTRACE_SIGNAL if [ "$TERM" = "msys" ]; then export TMPDIR="c:/tmp" diff --git a/tests/ulib/ok/services.ok b/tests/ulib/ok/services.ok index 75a29467..81c25d18 100644 --- a/tests/ulib/ok/services.ok +++ b/tests/ulib/ok/services.ok @@ -39,11 +39,8 @@ U_EXPORT main (int argc, char* argv[]) // U_ASSERT( result1 == U_STRING_FROM_CONSTANT("test_services.cpp\n") ) -#ifdef USE_LIBUUID buffer = UServices::getUUID(); U_INTERNAL_DUMP("buffer = %#.*S", U_STRING_TO_TRACE(buffer)) - U_INTERNAL_DUMP("UServices::uuid = %#.*S", 16, UServices::uuid) -#endif cmd = U_STRING_FROM_CONSTANT("cat test_services.cpp"); result2 = UCommand::outputCommand(cmd, 0, -1, fd_stderr); diff --git a/tests/ulib/test_date.cpp b/tests/ulib/test_date.cpp index 202ec062..15a41f2b 100644 --- a/tests/ulib/test_date.cpp +++ b/tests/ulib/test_date.cpp @@ -53,39 +53,35 @@ U_EXPORT main (int argc, char* argv[]) U_ASSERT( UTimeDate::getSecondFromTime("19030314104248Z", true, "%4u%2u%2u%2u%2u%2uZ") < u_now->tv_sec ) /* - typedef struct static_date { - struct timeval _timeval; // => u_now - char lock1[1]; + typedef struct log_date { char date1[17+1]; // 18/06/12 18:45:56 - char lock2[1]; char date2[26+1]; // 04/Jun/2012:18:18:37 +0200 - char lock3[1]; char date3[6+29+2+12+2+19+1]; // Date: Wed, 20 Jun 2012 11:43:17 GMT\r\nServer: ULib\r\nConnection: close\r\n - } static_date; + } log_date; */ - ULog::static_date log_data; + ULog::log_date log_date; - (void) u_strftime2(log_data.date1, 17, "%d/%m/%y %T", u_now->tv_sec + u_now_adjust); - (void) u_strftime2(log_data.date2, 26, "%d/%b/%Y:%T %z", u_now->tv_sec + u_now_adjust); - (void) u_strftime2(log_data.date3, 6+29+2+12+2+17+2, "Date: %a, %d %b %Y %T GMT\r\nServer: ULib\r\nConnection: close\r\n", u_now->tv_sec); + (void) u_strftime2(log_date.date1, 17, "%d/%m/%y %T", u_now->tv_sec + u_now_adjust); + (void) u_strftime2(log_date.date2, 26, "%d/%b/%Y:%T %z", u_now->tv_sec + u_now_adjust); + (void) u_strftime2(log_date.date3, 6+29+2+12+2+17+2, "Date: %a, %d %b %Y %T GMT\r\nServer: ULib\r\nConnection: close\r\n", u_now->tv_sec); - U_INTERNAL_DUMP("date1 = %.17S date2 = %.26S date3+6 = %.29S", log_data.date1, log_data.date2, log_data.date3+6) + U_INTERNAL_DUMP("date1 = %.17S date2 = %.26S date3+6 = %.29S", log_date.date1, log_date.date2, log_date.date3+6) /* for (int i = 0; i < 360; ++i) { u_now->tv_sec++; - UTimeDate::updateTime(log_data.date1 + 12); - UTimeDate::updateTime(log_data.date2 + 15); - UTimeDate::updateTime(log_data.date3+6 + 20); + UTimeDate::updateTime(log_date.date1 + 12); + UTimeDate::updateTime(log_date.date2 + 15); + UTimeDate::updateTime(log_date.date3+6 + 20); - cout.write(log_data.date1, 17); + cout.write(log_date.date1, 17); cout.write(" - ", 3); - cout.write(log_data.date2, 26); + cout.write(log_date.date2, 26); cout.write(" - ", 3); - cout.write(log_data.date3+6, 29); + cout.write(log_date.date3+6, 29); cout.put('\n'); } */ diff --git a/tests/ulib/test_services.cpp b/tests/ulib/test_services.cpp index 75a29467..81c25d18 100644 --- a/tests/ulib/test_services.cpp +++ b/tests/ulib/test_services.cpp @@ -39,11 +39,8 @@ U_EXPORT main (int argc, char* argv[]) // U_ASSERT( result1 == U_STRING_FROM_CONSTANT("test_services.cpp\n") ) -#ifdef USE_LIBUUID buffer = UServices::getUUID(); U_INTERNAL_DUMP("buffer = %#.*S", U_STRING_TO_TRACE(buffer)) - U_INTERNAL_DUMP("UServices::uuid = %#.*S", 16, UServices::uuid) -#endif cmd = U_STRING_FROM_CONSTANT("cat test_services.cpp"); result2 = UCommand::outputCommand(cmd, 0, -1, fd_stderr);