mirror of
				https://github.com/Telecominfraproject/wlan-cloud-lib-poco.git
				synced 2025-10-31 02:27:56 +00:00 
			
		
		
		
	Devel (#3586)
* Enable unit test in cmake build * add BLOB SQLite test * accept notifications by name (if they have one) * catch std::exception on parsing * fix a leak, add some table features * few PostgreSQL fixes * GH #2351: WebSocket docs * Rename pcre internal symbols used by Poco to avoid symbol collision https://github.com/pocoproject/poco/issues/2916 This patch was backported from https://github.com/pld-linux/poco/blob/master/pcre.patch * Fix warning in clang * Fix MSVC clang build fail * Zip and SevenZip do not depend on Util, XML, JSON * Added Test and new Pattern 'O' to only log the Filename not the full Path. * Updated Comment * Configuration to receive OCSP stapling response for client connections and callback implementation to verify the response if the server returns any response * removed SDK version from project files * run Application::initialize() in try-catch block * fix Invalid condition [ICMPv4PacketImpl.cpp:234] #2783 * style fixes for #2935; check OpenSSL version * Fixed issue 2945 (#2946) * Fixed #2945 * Added unit tests for #2945 * Dissalow iterator on empty Var (#2945) * Updated unit tests for #2945 * More concise unit tests for #2945 * Removed some more clutter (#2945) * NetSSL_Win: fix potential endless loop due to wrong error handling * fixed GH #2970: Poco::Data::TypeHandler<Poco::Nullable<T>>::prepare() must prepare with underlying type, not Poco::Data::Keywords::null * Fixed linking with Data ODBC error on some platforms * Fix set padding call for new versions of OpenSSL * PatternFormatter priorityNames fix * PKCS12Container: fix memory leaks on exceptions * Fix constness of URI::getPathSegments * Fix typo in the ThreadPool's docs * cmake: use GNUInstallDirs * Changed EventHandlerMap key (#3116) * Changed EventHandlerMap key Changed EventHandlerMap key from Socket to poco_socket_t to avoid errors in removing/access EventHandlerMap when for example we make an SSL handshake * Changed EventHandlerMap key Changed EventHandlerMap key from Socket to poco_socket_t to avoid errors in removing/access EventHandlerMap when for example we make an SSL handshake * avoid too much call to sockfd() and impl() * Fix configuration error while cross compiling (#3127) During the configuration phase in a cross compilation scenario, `include(InstallRequiredSystemLibraries)` fails even if `MSVC_REDIST_DIR` is provided. This should not be an hard error, in case someone wants to compile/use the library, and not package it. As explained on https://reviews.llvm.org/D41220, the most sensible fix is to include `InstallRequiredSystemLibraries` only on a Windows host. * crash when remove key from JSON::Object(JSON_PRESERVE_KEY_ORDER). (#3151) * #3153: Poco::Data::ODBC [N]VARCHAR(MAX) wrong maxDataSize() result * [SharedPtr] Poco::makeSharedArray #3200 * #3202: JWT: ESxxx signature must include padding for ECDSA R and S values * feat(HashRange): port HashRange from boost * chore(cmake): spelling typo fix * fix(hashRange): change function names casing * merge changes from 1.10.2 * formatting * merge JSON formatting changes from 1.10.2 * added Application::windowSize() * RemoteSyslogChannel/RemoteSyslogListener: make UDP buffer size configurable * merge fix from 1.10.2 * merge Postgres fixes from 1.10.2 * #2993: The Sec-WebSocket-Key of WebSocket is always the same one * formatting * #2927 * remove HowToGetHelp page due to outdated information * formatting * #3044: Upgrade PCRE to 8.44 * #3086: Use POCO_IOS_INIT_HACK for Linux in combination with libc++ * #3095: Digest proxy authentication does not work in 1.10.1 * #3136: Fixed null character issue when parsing a JSON * #3114: Added JSON Array::empty() method * #3230: ECDSADigestEngine: include missing header * fix include order * include order * fix(PollSet): #3248 #3249 * chore(UDPServer): fix spelling * feat(SocketReactor): extract and expose poll() as a member function * feat(Endpoint): add Endpoint (socket address directly wrapping native structures) * fix(Endpoint): osx build, align family enum with patform, some other adjustments * fix(EndpointTest): add missing include * feat(Endpoint): add some low-level accessors * feat(IPAddress): add functions returning addres as raw bytes * feat(DatagramSocket): DatagramSocket does not allow IPV6_V6ONLY #3283 * feat(SocketReactor): Add completion handling to SocketReactor #3290 * feat(SocketReactor): Add completion handling to SocketReactor #3290 (add scheduled handlers and runOne()) * chore(Net-testsuite): fix some tests warnings * feat: move semantics for sockets and addresses * fix(NetworkInterface): Unterminated string possible in NetworkInterfaceImpl::setPhyParams() #3301 * feat(Net): Add move semantics to Net (sockets and addresses) #3296 * fix(HostEntry): DNS HostEntry returns multiple entries #3303 * fix(SocketReactor): completion handling fixes and tests, separation of i/o and completion mutexes * feat(SocketReactor): execute permanent completion handlers on when there are I/O handlers and the expired ones whenever they expire * feat(Socket): expose lastError() * fix(SocketReactor): windows compile * windows fixes, remove Endnpoint * feat(Socket): expose error() * feat(PollSet): Use select() on windows for PollSet #3339 * add ci.yml * fix compile errors * revert(SocketReactor): back to devel branch * feat(SocketProactor): initial version w/ completion handler and executor * chore(SocketProactor): Sockets package * chore(ci): add dir and run script * feat(SocketProactor): add socket error handling #3357 * modify(SocketProactor): wait for completion handlers availability #3357 * feat(PollSet): Make PollSet::poll() interruptible #3359 * modify(SocketProactor): make addSend() public #3357 * modify(SocketProactor): platform non-interrupt sleep without Poco thread #3357 * modify(SocketProactor): allow restart #3357 * fix(SocketProactor): windows fixes and VS build * fix(SocketProactor): race when stop() is called before run() * fix(Socket): Windows SO_REUSEADDR is neither reliable nor safe #3380 * fix(SocketProactor): rvalue refs should not be const * fix(DNS): DNS::hostByAddress not thread-safe #3381 * chore(SocketProactor): remove unnecessary this capture * fix(IPAddress): IPAddress::tryParse does not work for :: #3385 * fix(SoccketProactor): add some try/catch safety nets; broaden the work list mutex coverage to protect all function access * fix(SocketProactor): use Poco::Mutex only * fix(SocketProactor): scheduled work skipped in the absence of socket events * fix(SocketProactor): test * chore (SocketProactor): add some state members * Fix clang linker problem by defining POCO_NO_AUTOMATIC_LIBS (#3177) * Dev/devel 1.12.0 (#3585) * fix(PollSet): #3248 #3249 * bump version to 1.11.0 * updated changelog| * #3299: NetSSL: Allow per-Context InvalidCertificateHandler * #3022: Process::isRunning(PID pid) causes handle leak on Windows * #3022: fix for WinCE * upgrade bundled pdjson to latest master * update build configs - add support for Apple Silicon * #2906, #2904: Support environments without hardware floating point * #3130: fix error handling: report original error before close() * #3107: remove unused variable * #3219: SMTPClientSession: invalid SMTP command if empty recipients list in MailMessage * Poco::trim*() code cleanup - use ptrdiff_t instead of int; additional test cases * #3182 Poco::Process:launch on MacOS BigSur: limit maximum number of file descriptors to close before exec() to 100000 * #3278: Fixing no hardware floating point support - Part II * #3090: Do not initialize value with undefined behavior * #3163: Correct Var::parse null value * #3196: std::forward for Poco::Optional ctor with rvalue * #3068: Documented ENABLE_JWT option * #3041: PostgreSQL and TEXT column type * #3099: Fixed Postgres extraction into Dynamic::Var * #3138: Add support of arch riscv32 * #2825: riscv: Enable double operations when using double float abi * #3166: Fix PostgresSQL BLOB extractor * #3237: An error in the documentation for Poco/JSON/Parser.h * #3193: ServerApplication::registerService() unquoted path security vulnerability * #3266: Order of Util::Application::uninitialize() is not in reverse as documented * #3215: XML parser returns item from different element in a array * #3282: Update constant in setContentType documentation * #3089: HTTPSessionFactory does not support HTTPClientSession::ProxyConfig * #2418: SecureServerSocket doesn't work with IpV6 * fix warnings * #3019: ObjectPool wait on borrow condition fix * #3224: Remove SSL23 support from Poco/Crypto * #3191: Fixing a bug in the NetSSL_Win module (Host name verification failed error) * disallow SSLv3 * #3269: Poco::Net::Context initialization with empty certificateFile * #3307: Poco::Crypto::X509Certificate: obtain certificate fingerprint * #3260: Memory leak in EVPPKey::loadKey used with files & wrong password * #3157: fix(openssl): add missing dependency to OpenSSL components * #3066: CMake warning about MYSQL casing * #3135: Poco::Data::SQLite::Utility::fileToMemory unsuccessful if journal exists * #3217: CMake: warning message with -DPOCO_STATIC confusing * #3274: Fix localtime_r for VxWorks 6.9 and later * #2746, #3169: Fix race condition on TCPServerDispatcher stop * #3092: add more detailed error description when LoadLibrary fails| * #3074: Fix sessions may not return back to the pool * #3309: optimize parsing from stream (no copying of entire JSON to memory); limit maximum depth to avoid stack overflow with malicious documents (fuzzing - #3285); code cleanup * JSON Parser performance improvements * #3310: Upgrade bundled SQLite to 3.35.5 * fix UB/bad cast in TCPServerTest.cpp * add comment regarding potential UB in AnyTest::testCastToReference() * support sanitizers in build configs * bump version * fix 'catching polymorphic type by value' warnings * fix 'catching polymorphic type by value' warnings * fix 'catching polymorphic type by value' warnings * remove failing Android build; add sanitizer builds * update postgres version * fix warning * fix warning * add GitHub workflow * fix ci.yml * fix ci.yml * additional ci builds * fix ci.yml for macos and windows * fix(double-conversion): Upgrade bundled double-conversion #3313 * ci fixes * #3314: NetSSL_OpenSSL: any.pem certificate error: ca md too weak * testReuseSession: remove bad checks for session reuse * investigate failing test * investigate failing test * investigate failing test * investigate failing test * ci * remove travis and appveyor * ci, readme * ci fixes * fix ci * fix ci * fix ci * fix memory leak when ignoring test error/failure * fix ci * don't define UNREACHABLE as poco_bugcheck as it triggers 'control reaches end of non-void function' warning * add Linux cross build, build Data libs on macos * fix ci * add MySQL include/lib search paths for Homebrew * ci fixes * ci fixes * ci fixes * ci fixes * fix indluce paths for brew mysql * #3317: Data::MySQL MySQL headers and library search paths * fix ARM-Linux build config * fix MySQL.make * update FindMySQL.cmake * fix(SocketReactor): fix dataCollection test * chore: remove troubleshooting help leftovers * #3302: MSVC: Poco hides warnings (C4996) for the C++14 attribute [[deprecated]] * fix potential crash in testAsyncNotify: don't delete event object while async notification is still in progress * fix(PollSetTest): change connect to blocking * added ActiveRecord library and compiler * added dependencies file * update copyright dates * ActiveRecord: project files and fixes for MSVC * ci: enable ActiveRecord on Windows * fix(PollSetTest): remove poll timing check (fails on msvc ci) * fix ActiveRecord CMake build and configuration * feat(build): add gen directory (for generated sources) and macchina lib link dirs (if needed) * #3318: Data: Support Poco::UUID for data binding * ODBC tests for UUID, updated ActiveRecord projects * ActiveRecord user guide * update ActiveRecord documentation * documentation fixes * #3321: manually merge ODBC text encoding support * CppParser: merge changes from internal repository * updated Makefile * AbstractObserver::accepts() - add optional name parameter * fix SharedPtr::makeSharedArray() [merge from devel] * remove blank line * #2895, #2935: support OCSP stapling * style * clang support (merge from devel) * #3322: remove useless struct * link libmariadb instead of libmysql if headers indicate MariaDB * fix nullptr passed to memcmp/memcpy reported by ubsan * fix nullptr passed to memcmp/memcpy reported by ubsan * fix PageCompiler cross-compile; fix Content-Security-Policy header * remove Data release notes page * style, remove unused var * update docs * improve BLOB handling, clean-up code * fix(ICMPv4Packet): [asan] Undefined behavior in ICMPv4PacketImpl.cpp #3326 * fix(NumericString): Bug in NumericString with decSep != '.' #3159 * fix(HostEntry): DNS HostEntry returns multiple entries #3303 * fix(PollSet): #3248 #3249 * fix(NetworkInterface): Unterminated string possible in NetworkInterfaceImpl::setPhyParams() #3301 * style/whitespace * fix warnings * add version resources to executables * style * whitespace * update changelog * cpproj: also copy testsuite/include if it's there * branch off 1.11.1 * #3335: XML error when build 1.11.0 * #3353: add POCO_NO_FORK_EXEC CMake option * #3381: DNS::hostByAddress not thread-safe * #3400: fix std::localtime not thread safe * #3221: Crash reported on Windows in X509Certificate verification * #3344: [bug] MacOS bundle destination path is not set * #3360: Add POCO_PGSQL_{INCLUDE,LIB} variables * #3363: Fixed compilation error with MongoDB::Connection and Util::Application * #3377: Correct Poco::Path::configHome() and dataHome() documentation for Windows * #2823: error: implicit conversion from 'int' to 'float' changes value from 2147483647 to 2147483648 * #3425: Fixed suspend/resumeEvents pair in DirectoryWatcher * #2966: SocketReactor loads one core of CPU up to 100% * #3330: Poco::Data::ODBC::ODBCStatementImpl causes crash * use OpenSSL 1.1.1 on macOS * add missing include search path * upgrade bundled PCRE to 8.45 * upgrade bundled SQLite to 3.36.0 * updated changelog * fix brew OpenSSL version * branch off poco-1.11.2 * #3506: Upgrade bundled expat to 2.4.4 * manually merge #3448, part 1 (Crypto) * manually merge #3448, part 1 (NetSSL) * #3515: NetSSL_OpenSSL Testsuite: testInterop() and testProxy() fail due to changed certificate * #3448: fix version check * #3465: NetSSL_Win: bad error handling when decodeMessage() fails * #3458: encryptString() crash on redhat/centos 8 with FIPS enabled using md5 default digest * #3505: JSON::PrintHandler.value(bool) prints incorrect value * #3527: Upgrade bundled expat to 2.4.5 * #3470: bug in JSON ParseHandler.cpp (RFC 7159 should be valid) * #3507: Reference counting for bound configuration in Util::Option is broken * #3518: Expat version check in #defines incorrect * #3338: NamedMutex does not work on Linux distributions where fs.protected_regular=1 * CI: don't build PageCompiler in ARM cross build * detect ARM64 on Windows * updated README.md * ProGen: support generation of VS 2022 project files * ci: add windows 2022 * fix library name * remove unused CppUnit headers * added VS2022 project files * #3530: Upgrade bundled expat to 2.4.6 * #3538: Upgrade bundled expat to 2.4.7 * Add back NIOS2 double conversion detection to fix compile errors The commit558324f672removed the nios2 support, which was originally added ine7b91e8125This commit add it back. Signed-off-by: Julien Olivain <ju.o@free.fr> * #3466: DefinePlatformSpecific.cmake: handle RelWithDebInfo and MinSizeRel configurations * #3524: remove XML and Util dependencies in Zip/SevenZip * #3483: Adds Windows 11 and Server 2022 to Environment::osDisplayName() * #3495: Array::operator[] should not throw * #3268: Poco redis command set have a bug when you want to set nx ex or expireTime * #3509: fix dst and utcOffset handling for Dublin time zone * #2882: another attempt at fixing it that should also work on other platforms * remove unused method in Timezone_WIN32.cpp * use tm_gmtoff on Linux * Basic support for OpenSSL 3.0.0 (#3448) * updated README.md * Create close-inactive-issues.yml * check return codes of EVP_CIPHER_CTX_new and EVP_CipherInit Especially with OpenSSL 3, it is possible that EVP_CipherInit may fail even when passed a non-null cipher[1]. Without the checking, it will finally get to a segfault. [1] https://github.com/openssl/openssl/issues/16864 * Automatically load default and legacy providers with OpenSSL 3 Without the legacy provider [1], some ciphers are not available. For example, the 'des-ecb' one used by test sutie is missed and the test will fail. [1] OSSL_PROVIDER-LEGACY(7ossl) * Make p12 ca order the same as pem OpenSSL < 3 returns p12 ca order in reversed order. This is fixed in OpenSSL 3. We work around it with old OpenSSL. See: https://github.com/openssl/openssl/issues/16421 https://github.com/openssl/openssl/pull/12641f5eb85eb0f* Implement SSL abort handling on OpenSSL 3 On an unexpected EOF, versions before OpenSSL 3.0 returned SSL_ERROR_SYSCALL, nothing was added to the error stack, and errno was 0. Since OpenSSL 3.0 the returned error is SSL_ERROR_SSL with a meaningful error on the error stack.[1] [1] SSL_GET_ERROR(3ossl) Co-authored-by: Günter Obiltschnig <guenter.obiltschnig@appinf.com> Co-authored-by: Robin Lee <cheeselee@fedoraproject.org> Co-authored-by: Aleksandar Fabijanic <aleks-f@users.noreply.github.com> * fix(Socket): shutdown fixes from pull #3448 * #3500: Sandbox all iFrames in PocoDoc * #3549; replace assert with assertTrue * #3553: Upgrade bundled zlib to 1.2.12 * #3525: Bad management of file in case of OpenSSLException in X509Certificate::readPEM and X509Certificate::writePEM * disable OpenSSL deprecation warnings * chore: cleanup * fix(X509Certificate): add missing string format * #3559: Poco::Data::PostgreSQL - DateTime extraction truncates fractional seconds * feat(EVP): 3.0 support - add EVPCipher - additional EVPPKey constructors - tests - fix and improve openssl-related exceptions Transition towards 3.0 support; deprecating direct EC and RSA interface portions. * fix(openssl): pre 3.0 compile * feat(Envelope): Add envelope to crypto #3561 * fix(Envelope): mac/clang compile * fix(Any): #3297 #3514 * #3562: fixed OpenSSL setup/shutdown * fix exception text * #3563: Remove support for OpenSSL < 1.0 * ci jobs for OpenSSL 1.1 and 3 * updated CHANGELOG * updated .vscode * Refactor/any soo (#3564) * refactor(Any): SOO - encapsulate data holders - add missing gets and ops - eliminate g++ warnings with enable_if's - default enable SOO * refactor(Placeholder): encapsulate SOO memory management and fix leaks; cf. #3297 #3514 * fix(Placeholder): asan errors and add tests cf. #3297 #3514 * fix(SSLManager): Race condition in SSLManager #3558 * remove unused include * updated copyright date * PocoDoc: fix iframe sandboxing * fix(SHA2Engine): cannot use HMACEngine with SHA2Engine #3421 * refactor(Placeholder): ifdef POCO_NO_SOO only in Placeholder and remove it anywhere else (#3566) * refactor(Placeholder): more SOO consolidation and optimization * fix(FPEnvironment): Visual Studio Warning C4244 #3543 * fix(Extractor): move extraction decoding to AbstractExtractor #3396 * Netssl/openssl3 (#3575) * feat(Context): DH init openssl3 port (1/2 hardcoded params) * create poco-1.11.3 branch, bump version * update copyright date * #3567: check legacy provider existence for legacy exception #3567 * fix(Placeholder): comparison for zero value * feat(Context): DH init openssl3 port (2/2 params from file) * test(HTTPSClientSession): try/catch to understand CI failure * chore(cmake): copy the DH parameters file * fix(OpenSSLInitializer): unload provider on uninitialize * chore(HTTPSClientSessionTest): remove try/catch * fix(OpenSSLInitializer): fix provider unloading * feat(CppUnit): make tests exceptions more descriptive * chore(CppUnit): a more descriptive name for callback Co-authored-by: Günter Obiltschnig <guenter.obiltschnig@appinf.com> * fix(Foundation): update VS 2019 platform version * chore(Data): update VS project files (add Transcoder #3396) * fix(Data): Poco::Data::ODBC-dbEncoding property not used for insert/update #3396 * fix(Data): add transcoder to Makefile #3396 * fix(JWT): remove duplicate test functions after merge Co-authored-by: Günter Obiltschnig <guenter.obiltschnig@appinf.com> Co-authored-by: Julien Olivain <ju.o@free.fr> Co-authored-by: Robin Lee <robinlee.sysu@gmail.com> Co-authored-by: Robin Lee <cheeselee@fedoraproject.org> * #2755: Fix MySQL's LONGBLOB/LONGTEXT not allocating enough space (#3474) * Unit test for bug #2755. * Removed condition to set buffer length to 0. * Fixes to unit tests for LONGBLOB/TEXT data type. * Adjusted buffer sizes to accommodate LONGBLOBs. Co-authored-by: Hector Toledo Soto <hsoto@transperfect.com> * fix(Data): MySQL UUID binding temporary string #3587 * feat(CI): add MySQL tests to CI #3588 * fix(CI): remove mysql client dev (using mariadb) #3588 * fix(CI): another shot at mysql * fix(Net/testsuite): add missing include * fix(DatagramSocket): Socket::available does not always return correct value for UDP #3589 * fix(SocketProactor): few improvements (#3357) * fix(ICMPsocketTest): change appinf (doesn't respond to ping) to github * fix(PollSet): windows fixes * fix(PollSet): windows implementation fixes (multi-fd_set select); minor reactor fixes * Extract JSON type as string (#3491) * Declared JSON as string data # Conflicts: # Data/include/Poco/Data/MetaColumn.h # Data/src/RecordSet.cpp # Data/src/StatementImpl.cpp * Added JSON extractor as string * Added unit test * Update comment Co-authored-by: Joerg-Christian Boehme <joerg@chaosdorf.de> Co-authored-by: Günter Obiltschnig <guenter.obiltschnig@appinf.com> Co-authored-by: tbarbier <thomas.barbier@amadeus.com> Co-authored-by: Linquize <linquize@yahoo.com.hk> Co-authored-by: Jan Kevin Dick <fixed-term.jan.dick@de.bosch.com> Co-authored-by: Neelima Patil <neelima.patil@honeywell.com> Co-authored-by: akete <akete@users.noreply.github.com> Co-authored-by: YuriAzathoth <iamkiller@mail.com> Co-authored-by: Jonathan Horvath <byteme@bytedreamer.com> Co-authored-by: Maksim Kita <kitaetoya@gmail.com> Co-authored-by: Alexander Galanin <al@galanin.nnov.ru> Co-authored-by: Thomas Sablik <thomas.sablik@wombytes.de> Co-authored-by: Nikita Migunov <nmigunov@iponweb.net> Co-authored-by: Ben Wolsieffer <benwolsieffer@gmail.com> Co-authored-by: micheleselea <michele.pradella@selea.com> Co-authored-by: Federico Kircheis <federico.kircheis@gmail.com> Co-authored-by: fenghao119 <fenghao119@gmail.com> Co-authored-by: Alex Fabijanic <alex@pocoprojecct.org> Co-authored-by: linquize <linquize2@yahoo.com> Co-authored-by: Julien Olivain <ju.o@free.fr> Co-authored-by: Robin Lee <robinlee.sysu@gmail.com> Co-authored-by: Robin Lee <cheeselee@fedoraproject.org> Co-authored-by: hectots <monkey.instinct@gmail.com> Co-authored-by: Hector Toledo Soto <hsoto@transperfect.com> Co-authored-by: Hernan Martinez <hernan.c.martinez@gmail.com>
This commit is contained in:
		 Aleksandar Fabijanic
					Aleksandar Fabijanic
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							6de1e18eb9
						
					
				
				
					commit
					7852153db5
				
			
							
								
								
									
										14
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -3,13 +3,23 @@ on: [push] | |||||||
| jobs: | jobs: | ||||||
|   linux-gcc-make: |   linux-gcc-make: | ||||||
|     runs-on: ubuntu-20.04 |     runs-on: ubuntu-20.04 | ||||||
|  |     services: | ||||||
|  |       mysql: | ||||||
|  |         image: mysql:latest | ||||||
|  |         env: | ||||||
|  |           MYSQL_ALLOW_EMPTY_PASSWORD: yes | ||||||
|  |           MYSQL_USER: pocotest | ||||||
|  |           MYSQL_PASSWORD: pocotest | ||||||
|  |           MYSQL_DATABASE: pocotest | ||||||
|  |         ports: | ||||||
|  |           - 3306:3306 | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v2 |       - uses: actions/checkout@v2 | ||||||
|       - run: sudo apt update && sudo apt install libssl-dev unixodbc-dev libmysqlclient-dev redis-server |       - run: sudo apt update && sudo apt install libssl-dev unixodbc-dev redis-server libmysqlclient-dev | ||||||
|       - run: ./configure --everything --omit=PDF && make all -s -j4 && sudo make install |       - run: ./configure --everything --omit=PDF && make all -s -j4 && sudo make install | ||||||
|       - run: >- |       - run: >- | ||||||
|           sudo -s |           sudo -s | ||||||
|           EXCLUDE_TESTS="Data/MySQL Data/ODBC Data/PostgreSQL MongoDB" |           EXCLUDE_TESTS="Data/ODBC Data/PostgreSQL MongoDB" | ||||||
|           ./ci/runtests.sh |           ./ci/runtests.sh | ||||||
|  |  | ||||||
|   linux-gcc-make-asan: |   linux-gcc-make-asan: | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ set_target_properties(mod_poco | |||||||
| target_include_directories(mod_poco | target_include_directories(mod_poco | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE | 	PRIVATE | ||||||
| 		${APACHE2_INCLUDE_DIRS} | 		${APACHE2_INCLUDE_DIRS} | ||||||
| 		${CMAKE_CURRENT_SOURCE_DIR}/src | 		${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
|   | |||||||
| @@ -50,6 +50,9 @@ if(NOT CMAKE_BUILD_TYPE) | |||||||
| 	set(CMAKE_BUILD_TYPE "RelWithDebInfo") | 	set(CMAKE_BUILD_TYPE "RelWithDebInfo") | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | # Enable standard installation directories | ||||||
|  | include(GNUInstallDirs) | ||||||
|  |  | ||||||
| # Include some common macros to simpilfy the Poco CMake files | # Include some common macros to simpilfy the Poco CMake files | ||||||
| include(PocoMacros) | include(PocoMacros) | ||||||
|  |  | ||||||
| @@ -436,7 +439,9 @@ add_custom_target(uninstall | |||||||
| ############################################################# | ############################################################# | ||||||
| # Enable packaging | # Enable packaging | ||||||
|  |  | ||||||
| include(InstallRequiredSystemLibraries) | if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") | ||||||
|  | 	include(InstallRequiredSystemLibraries) | ||||||
|  | endif() | ||||||
|  |  | ||||||
| set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Poco Libraries") | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Poco Libraries") | ||||||
| set(CPACK_PACKAGE_VENDOR "Applied Informatics Software Engineering GmbH") | set(CPACK_PACKAGE_VENDOR "Applied Informatics Software Engineering GmbH") | ||||||
| @@ -462,7 +467,7 @@ write_basic_package_version_file( | |||||||
| if(WIN32) | if(WIN32) | ||||||
| 	set(PocoConfigPackageLocation "cmake") | 	set(PocoConfigPackageLocation "cmake") | ||||||
| else() | else() | ||||||
| 	set(PocoConfigPackageLocation "lib${LIB_SUFFIX}/cmake/${PROJECT_NAME}") | 	set(PocoConfigPackageLocation "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| configure_file(cmake/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}Config.cmake" @ONLY) | configure_file(cmake/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}Config.cmake" @ONLY) | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ target_link_libraries(CppParser PUBLIC Poco::Foundation) | |||||||
| target_include_directories(CppParser | target_include_directories(CppParser | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,10 +18,15 @@ target_link_libraries(CppUnit PUBLIC Poco::Foundation) | |||||||
| target_include_directories(CppUnit | target_include_directories(CppUnit | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE | 	PRIVATE | ||||||
| 		${CMAKE_CURRENT_SOURCE_DIR}/src | 		${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|  | if(WIN32) | ||||||
|  | 	if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") | ||||||
|  | 		target_compile_definitions(CppUnit PUBLIC POCO_NO_AUTOMATIC_LIBS) | ||||||
|  | 	endif() | ||||||
|  | endif() | ||||||
|  |  | ||||||
| if(NOT BUILD_SHARED_LIBS) | if(NOT BUILD_SHARED_LIBS) | ||||||
| 	target_compile_definitions(CppUnit | 	target_compile_definitions(CppUnit | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ | |||||||
|     <ProjectGuid>{138BB448-808A-4FE5-A66D-78D1F8770F59}</ProjectGuid> |     <ProjectGuid>{138BB448-808A-4FE5-A66D-78D1F8770F59}</ProjectGuid> | ||||||
|     <RootNamespace>CppUnit</RootNamespace> |     <RootNamespace>CppUnit</RootNamespace> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|     <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ | |||||||
|     <ProjectGuid>{138BB448-808A-4FE5-A66D-78D1F8770F59}</ProjectGuid> |     <ProjectGuid>{138BB448-808A-4FE5-A66D-78D1F8770F59}</ProjectGuid> | ||||||
|     <RootNamespace>CppUnit</RootNamespace> |     <RootNamespace>CppUnit</RootNamespace> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|     <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ | |||||||
|     <ProjectGuid>{138BB448-808A-4FE5-A66D-78D1F8770F59}</ProjectGuid> |     <ProjectGuid>{138BB448-808A-4FE5-A66D-78D1F8770F59}</ProjectGuid> | ||||||
|     <RootNamespace>CppUnit</RootNamespace> |     <RootNamespace>CppUnit</RootNamespace> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|     <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ target_link_libraries(Crypto PUBLIC Poco::Foundation OpenSSL::SSL OpenSSL::Crypt | |||||||
| target_include_directories(Crypto | target_include_directories(Crypto | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE | 	PRIVATE | ||||||
| 		${CMAKE_CURRENT_SOURCE_DIR}/src | 		${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ target_link_libraries(Data PUBLIC Poco::Foundation) | |||||||
| target_include_directories(Data | target_include_directories(Data | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ target_link_libraries(DataMySQL PUBLIC Poco::Data MySQL::client) | |||||||
| target_include_directories(DataMySQL | target_include_directories(DataMySQL | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
| target_compile_definitions(DataMySQL PUBLIC THREADSAFE NO_TCL) | target_compile_definitions(DataMySQL PUBLIC THREADSAFE NO_TCL) | ||||||
|   | |||||||
| @@ -323,6 +323,10 @@ public: | |||||||
| private: | private: | ||||||
| 	bool realExtractFixed(std::size_t pos, enum_field_types type, void* buffer, bool isUnsigned = false); | 	bool realExtractFixed(std::size_t pos, enum_field_types type, void* buffer, bool isUnsigned = false); | ||||||
|  |  | ||||||
|  | 	bool extractLongLOB(std::size_t pos); | ||||||
|  |  | ||||||
|  | 	bool extractJSON(std::size_t pos); | ||||||
|  |  | ||||||
| 	// Prevent VC8 warning "operator= could not be generated" | 	// Prevent VC8 warning "operator= could not be generated" | ||||||
| 	Extractor& operator=(const Extractor&); | 	Extractor& operator=(const Extractor&); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -40,6 +40,9 @@ class ResultMetadata | |||||||
| 	/// MySQL result metadata | 	/// MySQL result metadata | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  | 	~ResultMetadata(); | ||||||
|  | 		/// Destroys the ResultMetadata. | ||||||
|  |  | ||||||
| 	void reset(); | 	void reset(); | ||||||
| 		/// Resets the metadata. | 		/// Resets the metadata. | ||||||
|  |  | ||||||
| @@ -64,10 +67,13 @@ public: | |||||||
| 	bool isNull(std::size_t pos) const; | 	bool isNull(std::size_t pos) const; | ||||||
| 		/// Returns true if value at pos is null. | 		/// Returns true if value at pos is null. | ||||||
|  |  | ||||||
|  | 	void adjustColumnSizeToFit(std::size_t pos); | ||||||
|  | 		/// Expands the size allocated for column to fit the length of the data. | ||||||
|  |  | ||||||
| private: | private: | ||||||
| 	std::vector<MetaColumn>    _columns; | 	std::vector<MetaColumn>    _columns; | ||||||
| 	std::vector<MYSQL_BIND>    _row; | 	std::vector<MYSQL_BIND>    _row; | ||||||
| 	std::vector<char>          _buffer; | 	std::vector<char*>         _buffer; | ||||||
| 	std::vector<unsigned long> _lengths; | 	std::vector<unsigned long> _lengths; | ||||||
| 	std::vector<my_boolv>      _isNull; // using char instead of bool to avoid std::vector<bool> disaster | 	std::vector<my_boolv>      _isNull; // using char instead of bool to avoid std::vector<bool> disaster | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -213,8 +213,7 @@ void Binder::bind(std::size_t pos, const Time& val, Direction dir) | |||||||
|  |  | ||||||
| void Binder::bind(std::size_t pos, const UUID& val, Direction dir) | void Binder::bind(std::size_t pos, const UUID& val, Direction dir) | ||||||
| { | { | ||||||
| 	std::string str = val.toString(); | 	bind(pos, toString(val), dir); | ||||||
| 	bind(pos, str, dir); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -128,9 +128,12 @@ bool Extractor::extract(std::size_t pos, std::string& val) | |||||||
|  |  | ||||||
| 	//mysql reports TEXT types as FDT_BLOB when being extracted | 	//mysql reports TEXT types as FDT_BLOB when being extracted | ||||||
| 	MetaColumn::ColumnDataType columnType = _metadata.metaColumn(static_cast<Poco::UInt32>(pos)).type(); | 	MetaColumn::ColumnDataType columnType = _metadata.metaColumn(static_cast<Poco::UInt32>(pos)).type(); | ||||||
| 	if (columnType != Poco::Data::MetaColumn::FDT_STRING && columnType != Poco::Data::MetaColumn::FDT_BLOB) | 	if (columnType != Poco::Data::MetaColumn::FDT_STRING && columnType != Poco::Data::MetaColumn::FDT_BLOB && columnType != Poco::Data::MetaColumn::FDT_JSON) | ||||||
| 		throw MySQLException("Extractor: not a string"); | 		throw MySQLException("Extractor: not a string"); | ||||||
|  |  | ||||||
|  | 	if (columnType == Poco::Data::MetaColumn::FDT_JSON && !extractJSON(pos)) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
| 	val.assign(reinterpret_cast<const char*>(_metadata.rawData(pos)), _metadata.length(pos)); | 	val.assign(reinterpret_cast<const char*>(_metadata.rawData(pos)), _metadata.length(pos)); | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| @@ -147,6 +150,9 @@ bool Extractor::extract(std::size_t pos, Poco::Data::BLOB& val) | |||||||
| 	if (_metadata.metaColumn(static_cast<Poco::UInt32>(pos)).type() != Poco::Data::MetaColumn::FDT_BLOB) | 	if (_metadata.metaColumn(static_cast<Poco::UInt32>(pos)).type() != Poco::Data::MetaColumn::FDT_BLOB) | ||||||
| 		throw MySQLException("Extractor: not a blob"); | 		throw MySQLException("Extractor: not a blob"); | ||||||
|  |  | ||||||
|  | 	if (_metadata.metaColumn(static_cast<Poco::UInt32>(pos)).length() == 0 && !extractLongLOB(pos)) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
| 	val.assignRaw(_metadata.rawData(pos), _metadata.length(pos)); | 	val.assignRaw(_metadata.rawData(pos), _metadata.length(pos)); | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| @@ -163,6 +169,9 @@ bool Extractor::extract(std::size_t pos, Poco::Data::CLOB& val) | |||||||
| 	if (_metadata.metaColumn(static_cast<Poco::UInt32>(pos)).type() != Poco::Data::MetaColumn::FDT_BLOB) | 	if (_metadata.metaColumn(static_cast<Poco::UInt32>(pos)).type() != Poco::Data::MetaColumn::FDT_BLOB) | ||||||
| 		throw MySQLException("Extractor: not a blob"); | 		throw MySQLException("Extractor: not a blob"); | ||||||
|  |  | ||||||
|  | 	if (_metadata.metaColumn(static_cast<Poco::UInt32>(pos)).length() == 0 && !extractLongLOB(pos)) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
| 	val.assignRaw(reinterpret_cast<const char*>(_metadata.rawData(pos)), _metadata.length(pos)); | 	val.assignRaw(reinterpret_cast<const char*>(_metadata.rawData(pos)), _metadata.length(pos)); | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| @@ -263,6 +272,37 @@ bool Extractor::realExtractFixed(std::size_t pos, enum_field_types type, void* b | |||||||
| 	return isNull == 0; | 	return isNull == 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool Extractor::extractLongLOB(std::size_t pos) | ||||||
|  | { | ||||||
|  | 	// Large LOBs (LONGBLOB and LONGTEXT) are fetched | ||||||
|  | 	// with a zero-length buffer to avoid allocating | ||||||
|  | 	// huge amounts of memory. Therefore, when extracting | ||||||
|  | 	// the buffers need to be adjusted. | ||||||
|  | 	 | ||||||
|  | 	_metadata.adjustColumnSizeToFit(pos); | ||||||
|  | 	 | ||||||
|  | 	MYSQL_BIND* row = _metadata.row(); | ||||||
|  | 	if (!_stmt.fetchColumn(pos, &row[pos])) | ||||||
|  | 		return false; | ||||||
|  | 	 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool Extractor::extractJSON(std::size_t pos) | ||||||
|  | { | ||||||
|  | 	// JSON columns are fetched with a zero-length | ||||||
|  | 	// buffer to avoid allocating huge amounts of memory. | ||||||
|  | 	// Therefore, when extracting the buffers need to be adjusted. | ||||||
|  |  | ||||||
|  | 	_metadata.adjustColumnSizeToFit(pos); | ||||||
|  |  | ||||||
|  | 	MYSQL_BIND* row = _metadata.row(); | ||||||
|  | 	row->buffer_type = MYSQL_TYPE_JSON; | ||||||
|  | 	if (!_stmt.fetchColumn(pos, &row[pos])) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
| ////////////// | ////////////// | ||||||
| // Not implemented | // Not implemented | ||||||
|   | |||||||
| @@ -71,6 +71,7 @@ namespace | |||||||
| 		case MYSQL_TYPE_MEDIUM_BLOB: | 		case MYSQL_TYPE_MEDIUM_BLOB: | ||||||
| 		case MYSQL_TYPE_LONG_BLOB: | 		case MYSQL_TYPE_LONG_BLOB: | ||||||
| 		case MYSQL_TYPE_BLOB: | 		case MYSQL_TYPE_BLOB: | ||||||
|  | 		case MYSQL_TYPE_JSON: | ||||||
| 			return field.length; | 			return field.length; | ||||||
|  |  | ||||||
| 		default: | 		default: | ||||||
| @@ -128,6 +129,8 @@ namespace | |||||||
| 		case MYSQL_TYPE_LONG_BLOB: | 		case MYSQL_TYPE_LONG_BLOB: | ||||||
| 		case MYSQL_TYPE_BLOB: | 		case MYSQL_TYPE_BLOB: | ||||||
| 			return Poco::Data::MetaColumn::FDT_BLOB; | 			return Poco::Data::MetaColumn::FDT_BLOB; | ||||||
|  | 		case MYSQL_TYPE_JSON: | ||||||
|  | 			return Poco::Data::MetaColumn::FDT_JSON; | ||||||
| 		default: | 		default: | ||||||
| 			return Poco::Data::MetaColumn::FDT_UNKNOWN; | 			return Poco::Data::MetaColumn::FDT_UNKNOWN; | ||||||
| 		} | 		} | ||||||
| @@ -140,6 +143,13 @@ namespace Data { | |||||||
| namespace MySQL { | namespace MySQL { | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ResultMetadata::~ResultMetadata() | ||||||
|  | { | ||||||
|  | 	for (std::vector<char*>::iterator it = _buffer.begin(); it != _buffer.end(); ++it) | ||||||
|  | 		std::free(*it); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void ResultMetadata::reset() | void ResultMetadata::reset() | ||||||
| { | { | ||||||
| 	_columns.resize(0); | 	_columns.resize(0); | ||||||
| @@ -165,7 +175,6 @@ void ResultMetadata::init(MYSQL_STMT* stmt) | |||||||
| 	std::size_t count = mysql_num_fields(h); | 	std::size_t count = mysql_num_fields(h); | ||||||
| 	MYSQL_FIELD* fields = mysql_fetch_fields(h); | 	MYSQL_FIELD* fields = mysql_fetch_fields(h); | ||||||
|  |  | ||||||
| 	std::size_t commonSize = 0; |  | ||||||
| 	_columns.reserve(count); | 	_columns.reserve(count); | ||||||
|  |  | ||||||
| 	for (std::size_t i = 0; i < count; i++) | 	for (std::size_t i = 0; i < count; i++) | ||||||
| @@ -181,29 +190,24 @@ void ResultMetadata::init(MYSQL_STMT* stmt) | |||||||
| 			0,                               // TODO: precision | 			0,                               // TODO: precision | ||||||
| 			!IS_NOT_NULL(fields[i].flags)    // nullable | 			!IS_NOT_NULL(fields[i].flags)    // nullable | ||||||
| 			)); | 			)); | ||||||
|  |  | ||||||
| 		commonSize += _columns[i].length(); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	_buffer.resize(commonSize); | 	_buffer.resize(count); | ||||||
| 	_row.resize(count); | 	_row.resize(count); | ||||||
| 	_lengths.resize(count); | 	_lengths.resize(count); | ||||||
| 	_isNull.resize(count); | 	_isNull.resize(count); | ||||||
|  |  | ||||||
| 	std::size_t offset = 0; |  | ||||||
|  |  | ||||||
| 	for (std::size_t i = 0; i < count; i++) | 	for (std::size_t i = 0; i < count; i++) | ||||||
| 	{ | 	{ | ||||||
| 		std::memset(&_row[i], 0, sizeof(MYSQL_BIND)); | 		std::memset(&_row[i], 0, sizeof(MYSQL_BIND)); | ||||||
| 		unsigned int len = static_cast<unsigned int>(_columns[i].length()); | 		unsigned int len = static_cast<unsigned int>(_columns[i].length()); | ||||||
|  | 		_buffer[i] = (char*) std::calloc(len, sizeof(char)); | ||||||
| 		_row[i].buffer_type   = fields[i].type; | 		_row[i].buffer_type   = fields[i].type; | ||||||
| 		_row[i].buffer_length = len; | 		_row[i].buffer_length = len; | ||||||
| 		_row[i].buffer        = (len > 0) ? (&_buffer[0] + offset) : 0; | 		_row[i].buffer        = _buffer[i]; | ||||||
| 		_row[i].length        = &_lengths[i]; | 		_row[i].length        = &_lengths[i]; | ||||||
| 		_row[i].is_null       = reinterpret_cast<my_bool*>(&_isNull[i]); // workaround to make it work with both MySQL 8 and earlier | 		_row[i].is_null       = reinterpret_cast<my_bool*>(&_isNull[i]); // workaround to make it work with both MySQL 8 and earlier | ||||||
| 		_row[i].is_unsigned   = (fields[i].flags & UNSIGNED_FLAG) > 0; | 		_row[i].is_unsigned   = (fields[i].flags & UNSIGNED_FLAG) > 0; | ||||||
| 		 |  | ||||||
| 		offset += _row[i].buffer_length; |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -244,4 +248,13 @@ bool ResultMetadata::isNull(std::size_t pos) const | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ResultMetadata::adjustColumnSizeToFit(std::size_t pos) | ||||||
|  | { | ||||||
|  | 	std::free(_buffer[pos]); | ||||||
|  | 	_buffer[pos] = (char*) std::calloc(_lengths[pos], sizeof(char)); | ||||||
|  | 	_row[pos].buffer = _buffer[pos]; | ||||||
|  | 	_row[pos].buffer_length = _lengths[pos]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| } } } // namespace Poco::Data::MySQL | } } } // namespace Poco::Data::MySQL | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								Data/MySQL/testsuite/run-db-setup.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										15
									
								
								Data/MySQL/testsuite/run-db-setup.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | #apt-get install mariadb-server | ||||||
|  | USER=pocotest | ||||||
|  | PASS=pocotest | ||||||
|  |  | ||||||
|  | mysql -uroot <<MYSQL_SCRIPT | ||||||
|  | CREATE DATABASE pocotest; | ||||||
|  | CREATE USER '$USER'@'localhost' IDENTIFIED BY '$PASS'; | ||||||
|  | GRANT ALL PRIVILEGES ON pocotest.* TO '$USER'@'localhost'; | ||||||
|  | FLUSH PRIVILEGES; | ||||||
|  | MYSQL_SCRIPT | ||||||
|  |  | ||||||
|  | echo "MySQL user created." | ||||||
|  | echo "Username:   $USER" | ||||||
|  | echo "Password:   $PASS" | ||||||
| @@ -469,6 +469,23 @@ void MySQLTest::testBLOBStmt() | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void MySQLTest::testLongBLOB() | ||||||
|  | { | ||||||
|  | 	if (!_pSession) fail ("Test not available."); | ||||||
|  |  | ||||||
|  | 	recreatePersonLongBLOBTable(); | ||||||
|  | 	_pExecutor->longBlob(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MySQLTest::testJSON() | ||||||
|  | { | ||||||
|  | 	if (!_pSession) fail("Test not available."); | ||||||
|  |  | ||||||
|  | 	recreatePersonJSONTable(); | ||||||
|  | 	_pExecutor->json(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void MySQLTest::testUnsignedInts() | void MySQLTest::testUnsignedInts() | ||||||
| { | { | ||||||
| 	if (!_pSession) fail ("Test not available."); | 	if (!_pSession) fail ("Test not available."); | ||||||
| @@ -752,6 +769,24 @@ void MySQLTest::recreatePersonTimeTable() | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void MySQLTest::recreatePersonLongBLOBTable() | ||||||
|  | { | ||||||
|  | 	dropTable("Person"); | ||||||
|  | 	try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Biography LONGTEXT)", now; } | ||||||
|  | 	catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreatePersonLongBLOBTable()"); } | ||||||
|  | 	catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreatePersonLongBLOBTable()"); } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void MySQLTest::recreatePersonJSONTable() | ||||||
|  | { | ||||||
|  | 	dropTable("Person"); | ||||||
|  | 	try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Biography JSON)", now; } | ||||||
|  | 	catch (ConnectionException& ce) { std::cout << ce.displayText() << std::endl; fail("recreatePersonLongBLOBTable()"); } | ||||||
|  | 	catch (StatementException& se) { std::cout << se.displayText() << std::endl; fail("recreatePersonLongBLOBTable()"); } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void MySQLTest::recreateIntsTable() | void MySQLTest::recreateIntsTable() | ||||||
| { | { | ||||||
| 	dropTable("Strings"); | 	dropTable("Strings"); | ||||||
| @@ -919,6 +954,8 @@ CppUnit::Test* MySQLTest::suite() | |||||||
| 	CppUnit_addTest(pSuite, MySQLTest, testDateTime); | 	CppUnit_addTest(pSuite, MySQLTest, testDateTime); | ||||||
| 	//CppUnit_addTest(pSuite, MySQLTest, testBLOB); | 	//CppUnit_addTest(pSuite, MySQLTest, testBLOB); | ||||||
| 	CppUnit_addTest(pSuite, MySQLTest, testBLOBStmt); | 	CppUnit_addTest(pSuite, MySQLTest, testBLOBStmt); | ||||||
|  | 	CppUnit_addTest(pSuite, MySQLTest, testLongBLOB); | ||||||
|  | 	CppUnit_addTest(pSuite, MySQLTest, testJSON); | ||||||
| 	CppUnit_addTest(pSuite, MySQLTest, testUnsignedInts); | 	CppUnit_addTest(pSuite, MySQLTest, testUnsignedInts); | ||||||
| 	CppUnit_addTest(pSuite, MySQLTest, testFloat); | 	CppUnit_addTest(pSuite, MySQLTest, testFloat); | ||||||
| 	CppUnit_addTest(pSuite, MySQLTest, testDouble); | 	CppUnit_addTest(pSuite, MySQLTest, testDouble); | ||||||
|   | |||||||
| @@ -79,6 +79,8 @@ public: | |||||||
| 	void testDateTime(); | 	void testDateTime(); | ||||||
| 	void testBLOB(); | 	void testBLOB(); | ||||||
| 	void testBLOBStmt(); | 	void testBLOBStmt(); | ||||||
|  | 	void testLongBLOB(); | ||||||
|  | 	void testJSON(); | ||||||
|  |  | ||||||
| 	void testUnsignedInts(); | 	void testUnsignedInts(); | ||||||
| 	void testFloat(); | 	void testFloat(); | ||||||
| @@ -117,6 +119,8 @@ private: | |||||||
| 	void recreatePersonDateTimeTable(); | 	void recreatePersonDateTimeTable(); | ||||||
| 	void recreatePersonDateTable(); | 	void recreatePersonDateTable(); | ||||||
| 	void recreatePersonTimeTable(); | 	void recreatePersonTimeTable(); | ||||||
|  | 	void recreatePersonLongBLOBTable(); | ||||||
|  | 	void recreatePersonJSONTable(); | ||||||
| 	void recreateStringsTable(); | 	void recreateStringsTable(); | ||||||
| 	void recreateIntsTable(); | 	void recreateIntsTable(); | ||||||
| 	void recreateUnsignedIntsTable(); | 	void recreateUnsignedIntsTable(); | ||||||
|   | |||||||
| @@ -1435,6 +1435,57 @@ void SQLExecutor::blobStmt() | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SQLExecutor::longBlob() | ||||||
|  | { | ||||||
|  | 	std::string funct = "longBlob()"; | ||||||
|  | 	std::string lastName("lastname"); | ||||||
|  | 	std::string firstName("firstname"); | ||||||
|  | 	std::string address("Address"); | ||||||
|  | 	Poco::Data::CLOB biography("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", 123); | ||||||
|  |  | ||||||
|  | 	int count = 0; | ||||||
|  | 	Statement ins = (*_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(biography)); | ||||||
|  | 	ins.execute(); | ||||||
|  | 	try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } | ||||||
|  | 	catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } | ||||||
|  | 	catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } | ||||||
|  | 	assertTrue (count == 1); | ||||||
|  |  | ||||||
|  | 	Poco::Data::CLOB res; | ||||||
|  | 	poco_assert (res.size() == 0); | ||||||
|  | 	Statement stmt = (*_pSession << "SELECT Biography FROM Person", into(res)); | ||||||
|  | 	try { stmt.execute(); } | ||||||
|  | 	catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } | ||||||
|  | 	catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } | ||||||
|  | 	poco_assert (res == biography); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SQLExecutor::json() | ||||||
|  | { | ||||||
|  | 	std::string funct = "json()"; | ||||||
|  | 	std::string lastName("lastname"); | ||||||
|  | 	std::string firstName("firstname"); | ||||||
|  | 	std::string address("Address"); | ||||||
|  | 	std::string biography(R"({"biography": {"count": 42, "title": "Lorem Ipsum", "released": true}})"); | ||||||
|  |  | ||||||
|  | 	int count = 0; | ||||||
|  | 	Statement ins = (*_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(biography)); | ||||||
|  | 	ins.execute(); | ||||||
|  | 	try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } | ||||||
|  | 	catch (ConnectionException& ce) { std::cout << ce.displayText() << std::endl; fail(funct); } | ||||||
|  | 	catch (StatementException& se) { std::cout << se.displayText() << std::endl; fail(funct); } | ||||||
|  | 	assertTrue(count == 1); | ||||||
|  |  | ||||||
|  | 	Poco::Data::JSON res; | ||||||
|  | 	poco_assert(res.size() == 0); | ||||||
|  | 	Statement stmt = (*_pSession << "SELECT Biography FROM Person", into(res)); | ||||||
|  | 	try { stmt.execute(); } | ||||||
|  | 	catch (ConnectionException& ce) { std::cout << ce.displayText() << std::endl; fail(funct); } | ||||||
|  | 	catch (StatementException& se) { std::cout << se.displayText() << std::endl; fail(funct); } | ||||||
|  | 	poco_assert(res == biography); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void SQLExecutor::tuples() | void SQLExecutor::tuples() | ||||||
| { | { | ||||||
| 	typedef Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> TupleType; | 	typedef Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> TupleType; | ||||||
|   | |||||||
| @@ -83,6 +83,8 @@ public: | |||||||
| 	void dateTime(); | 	void dateTime(); | ||||||
| 	void date(); | 	void date(); | ||||||
| 	void time(); | 	void time(); | ||||||
|  | 	void longBlob(); | ||||||
|  | 	void json(); | ||||||
| 	void unsignedInts(); | 	void unsignedInts(); | ||||||
| 	void floats(); | 	void floats(); | ||||||
| 	void doubles(); | 	void doubles(); | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ target_link_libraries(DataODBC PUBLIC Poco::Data ODBC::ODBC) | |||||||
| target_include_directories(DataODBC | target_include_directories(DataODBC | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
| target_compile_definitions(DataODBC PUBLIC THREADSAFE) | target_compile_definitions(DataODBC PUBLIC THREADSAFE) | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ target_link_libraries(DataPostgreSQL PUBLIC Poco::Data PostgreSQL::client) | |||||||
| target_include_directories(DataPostgreSQL | target_include_directories(DataPostgreSQL | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE | 	PRIVATE | ||||||
| 		${CMAKE_CURRENT_SOURCE_DIR}/src | 		${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ target_link_libraries(DataSQLite PUBLIC Poco::Data) | |||||||
| target_include_directories(DataSQLite | target_include_directories(DataSQLite | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										43
									
								
								Data/SQLite/testsuite/src/SQLiteTest.cpp
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										43
									
								
								Data/SQLite/testsuite/src/SQLiteTest.cpp
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -55,6 +55,7 @@ using Poco::Data::SQLChannel; | |||||||
| using Poco::Data::LimitException; | using Poco::Data::LimitException; | ||||||
| using Poco::Data::ConnectionFailedException; | using Poco::Data::ConnectionFailedException; | ||||||
| using Poco::Data::CLOB; | using Poco::Data::CLOB; | ||||||
|  | using Poco::Data::BLOB; | ||||||
| using Poco::Data::Date; | using Poco::Data::Date; | ||||||
| using Poco::Data::Time; | using Poco::Data::Time; | ||||||
| using Poco::Data::Transaction; | using Poco::Data::Transaction; | ||||||
| @@ -1419,6 +1420,47 @@ void SQLiteTest::testCLOB() | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SQLiteTest::testBLOB() | ||||||
|  | { | ||||||
|  | 	std::string lastName("lastname"); | ||||||
|  | 	std::string firstName("firstname"); | ||||||
|  | 	std::string address("Address"); | ||||||
|  | 	Session tmp(Poco::Data::SQLite::Connector::KEY, "dummy.db"); | ||||||
|  | 	tmp << "DROP TABLE IF EXISTS Person", now; | ||||||
|  | 	tmp << "CREATE TABLE IF NOT EXISTS Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Image BLOB)", now; | ||||||
|  | 	typedef struct | ||||||
|  | 	{ | ||||||
|  | 		int i = 0; | ||||||
|  | 		Poco::Int64 i64 = 1; | ||||||
|  | 		float f = 2.5; | ||||||
|  | 		double d = 3.5; | ||||||
|  | 		char c[16] = {0}; | ||||||
|  | 	} DataStruct; | ||||||
|  | 	DataStruct ds; | ||||||
|  | 	strcpy(ds.c, "123456789ABCDEF"); | ||||||
|  | 	BLOB img(reinterpret_cast<unsigned char*>(&ds), sizeof(ds)); | ||||||
|  | 	assertTrue(img.size() == sizeof(ds)); | ||||||
|  | 	int count = 0; | ||||||
|  | 	tmp << "INSERT INTO PERSON VALUES(:ln, :fn, :ad, :img)", use(lastName), use(firstName), use(address), use(img), now; | ||||||
|  | 	tmp << "SELECT COUNT(*) FROM PERSON", into(count), now; | ||||||
|  | 	assertTrue(count == 1); | ||||||
|  | 	BLOB res; | ||||||
|  | 	assertTrue(res.size() == 0); | ||||||
|  |  | ||||||
|  | 	tmp << "SELECT Image FROM Person WHERE LastName == :ln", bind("lastname"), into(res), now; | ||||||
|  | 	assertTrue(res.size() == img.size()); | ||||||
|  | 	assertTrue(0 == std::memcmp(res.rawContent(), img.rawContent(), sizeof(img))); | ||||||
|  | 	assertTrue(0 == std::memcmp(res.rawContent(), &ds, sizeof(ds))); | ||||||
|  | 	DataStruct dsCopy; | ||||||
|  | 	std::memcpy(&dsCopy, res.rawContent(), sizeof(dsCopy)); | ||||||
|  | 	assertTrue(ds.i == dsCopy.i); | ||||||
|  | 	assertTrue(ds.i64 == dsCopy.i64); | ||||||
|  | 	assertTrue(ds.f == dsCopy.f); | ||||||
|  | 	assertTrue(ds.d == dsCopy.d); | ||||||
|  | 	assertTrue(std::string(ds.c) == std::string(dsCopy.c)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void SQLiteTest::testTuple10() | void SQLiteTest::testTuple10() | ||||||
| { | { | ||||||
| 	Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db"); | 	Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db"); | ||||||
| @@ -3448,6 +3490,7 @@ CppUnit::Test* SQLiteTest::suite() | |||||||
| 	CppUnit_addTest(pSuite, SQLiteTest, testSingleSelect); | 	CppUnit_addTest(pSuite, SQLiteTest, testSingleSelect); | ||||||
| 	CppUnit_addTest(pSuite, SQLiteTest, testEmptyDB); | 	CppUnit_addTest(pSuite, SQLiteTest, testEmptyDB); | ||||||
| 	CppUnit_addTest(pSuite, SQLiteTest, testCLOB); | 	CppUnit_addTest(pSuite, SQLiteTest, testCLOB); | ||||||
|  | 	CppUnit_addTest(pSuite, SQLiteTest, testBLOB); | ||||||
| 	CppUnit_addTest(pSuite, SQLiteTest, testTuple10); | 	CppUnit_addTest(pSuite, SQLiteTest, testTuple10); | ||||||
| 	CppUnit_addTest(pSuite, SQLiteTest, testTupleVector10); | 	CppUnit_addTest(pSuite, SQLiteTest, testTupleVector10); | ||||||
| 	CppUnit_addTest(pSuite, SQLiteTest, testTuple9); | 	CppUnit_addTest(pSuite, SQLiteTest, testTuple9); | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								Data/SQLite/testsuite/src/SQLiteTest.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										1
									
								
								Data/SQLite/testsuite/src/SQLiteTest.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -76,6 +76,7 @@ public: | |||||||
| 	void testEmptyDB(); | 	void testEmptyDB(); | ||||||
|  |  | ||||||
| 	void testCLOB(); | 	void testCLOB(); | ||||||
|  | 	void testBLOB(); | ||||||
|  |  | ||||||
| 	void testTuple1(); | 	void testTuple1(); | ||||||
| 	void testTupleVector1(); | 	void testTupleVector1(); | ||||||
|   | |||||||
| @@ -363,9 +363,12 @@ protected: | |||||||
| 	bool transcodeRequired() const; | 	bool transcodeRequired() const; | ||||||
| 	void transcode(const std::string& from, std::string& to); | 	void transcode(const std::string& from, std::string& to); | ||||||
| 	void reverseTranscode(const std::string& from, std::string& to); | 	void reverseTranscode(const std::string& from, std::string& to); | ||||||
|  | 	const std::string& toString(const UUID& uuid); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|  | 	using StringList = std::vector<std::string*>; | ||||||
| 	std::unique_ptr<Transcoder> _pTranscoder; | 	std::unique_ptr<Transcoder> _pTranscoder; | ||||||
|  | 	std::unique_ptr<StringList> _pStrings; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -221,7 +221,7 @@ private: | |||||||
|  |  | ||||||
| using BLOB = LOB<unsigned char>; | using BLOB = LOB<unsigned char>; | ||||||
| using CLOB = LOB<char>; | using CLOB = LOB<char>; | ||||||
|  | using JSON = std::string; | ||||||
|  |  | ||||||
| // | // | ||||||
| // inlines | // inlines | ||||||
|   | |||||||
| @@ -51,6 +51,7 @@ public: | |||||||
| 		FDT_TIME, | 		FDT_TIME, | ||||||
| 		FDT_TIMESTAMP, | 		FDT_TIMESTAMP, | ||||||
| 		FDT_UUID, | 		FDT_UUID, | ||||||
|  | 		FDT_JSON, | ||||||
| 		FDT_UNKNOWN | 		FDT_UNKNOWN | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -36,6 +36,11 @@ AbstractBinder::AbstractBinder(Poco::TextEncoding::Ptr pFromEncoding, | |||||||
|  |  | ||||||
| AbstractBinder::~AbstractBinder() | AbstractBinder::~AbstractBinder() | ||||||
| { | { | ||||||
|  | 	if (_pStrings) | ||||||
|  | 	{ | ||||||
|  | 		for (auto& s : *_pStrings) | ||||||
|  | 			delete s; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -53,6 +58,14 @@ void AbstractBinder::reverseTranscode(const std::string& from, std::string& to) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | const std::string& AbstractBinder::toString(const UUID& uuid) | ||||||
|  | { | ||||||
|  | 	if (!_pStrings) _pStrings.reset(new StringList); | ||||||
|  | 	_pStrings->push_back(new std::string(uuid.toString())); | ||||||
|  | 	return *_pStrings->back(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void AbstractBinder::bind(std::size_t pos, const std::vector<Poco::Int8>& val, Direction dir) | void AbstractBinder::bind(std::size_t pos, const std::vector<Poco::Int8>& val, Direction dir) | ||||||
| { | { | ||||||
| 	throw NotImplementedException("std::vector binder must be implemented."); | 	throw NotImplementedException("std::vector binder must be implemented."); | ||||||
|   | |||||||
| @@ -160,6 +160,7 @@ Poco::Dynamic::Var RecordSet::value(std::size_t col, std::size_t row, bool useFi | |||||||
| 	case MetaColumn::FDT_TIME:      return value<Time>(col, row, useFilter); | 	case MetaColumn::FDT_TIME:      return value<Time>(col, row, useFilter); | ||||||
| 	case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(col, row); | 	case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(col, row); | ||||||
| 	case MetaColumn::FDT_UUID:      return value<UUID>(col, row); | 	case MetaColumn::FDT_UUID:      return value<UUID>(col, row); | ||||||
|  | 	case MetaColumn::FDT_JSON:      return value<std::string>(col, row, useFilter); | ||||||
| 	default: | 	default: | ||||||
| 		throw UnknownTypeException("Data type not supported."); | 		throw UnknownTypeException("Data type not supported."); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -353,6 +353,8 @@ void StatementImpl::makeExtractors(std::size_t count) | |||||||
| 				addInternalExtract<DateTime>(mc); break; | 				addInternalExtract<DateTime>(mc); break; | ||||||
| 			case MetaColumn::FDT_UUID: | 			case MetaColumn::FDT_UUID: | ||||||
| 				addInternalExtract<UUID>(mc); break; | 				addInternalExtract<UUID>(mc); break; | ||||||
|  | 			case MetaColumn::FDT_JSON: | ||||||
|  | 				addInternalExtract<std::string>(mc); break; | ||||||
| 			default: | 			default: | ||||||
| 				throw Poco::InvalidArgumentException("Data type not supported."); | 				throw Poco::InvalidArgumentException("Data type not supported."); | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ target_link_libraries(Encodings PUBLIC Poco::Foundation) | |||||||
| target_include_directories(Encodings | target_include_directories(Encodings | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -108,7 +108,7 @@ endif(POCO_UNBUNDLED) | |||||||
| target_include_directories(Foundation | target_include_directories(Foundation | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -137,6 +137,9 @@ endif() | |||||||
|  |  | ||||||
| if(WIN32) | if(WIN32) | ||||||
| 	target_compile_definitions(Foundation PUBLIC POCO_OS_FAMILY_WINDOWS UNICODE _UNICODE) | 	target_compile_definitions(Foundation PUBLIC POCO_OS_FAMILY_WINDOWS UNICODE _UNICODE) | ||||||
|  | 	if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") | ||||||
|  | 		target_compile_definitions(Foundation PUBLIC POCO_NO_AUTOMATIC_LIBS) | ||||||
|  | 	endif() | ||||||
| 	target_link_libraries(Foundation PUBLIC iphlpapi) | 	target_link_libraries(Foundation PUBLIC iphlpapi) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ | |||||||
|     <ProjectGuid>{B01196CC-B693-4548-8464-2FF60499E73F}</ProjectGuid> |     <ProjectGuid>{B01196CC-B693-4548-8464-2FF60499E73F}</ProjectGuid> | ||||||
|     <RootNamespace>Foundation</RootNamespace> |     <RootNamespace>Foundation</RootNamespace> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|     <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ | |||||||
|     <ProjectGuid>{B01196CC-B693-4548-8464-2FF60499E73F}</ProjectGuid> |     <ProjectGuid>{B01196CC-B693-4548-8464-2FF60499E73F}</ProjectGuid> | ||||||
|     <RootNamespace>Foundation</RootNamespace> |     <RootNamespace>Foundation</RootNamespace> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|     <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> | ||||||
|   | |||||||
							
								
								
									
										0
									
								
								Foundation/include/Poco/AbstractObserver.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								Foundation/include/Poco/AbstractObserver.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -142,6 +142,21 @@ | |||||||
| // #define POCO_NET_NO_IPv6 | // #define POCO_NET_NO_IPv6 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // No UNIX socket support | ||||||
|  | // Define to disable unix sockets | ||||||
|  | // #define POCO_NET_NO_UNIX_SOCKET | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Define to nonzero to enable move | ||||||
|  | // semantics on classes where it | ||||||
|  | // introduces a new state. | ||||||
|  | // For explanation, see | ||||||
|  | // https://github.com/pocoproject/poco/wiki/Move-Semantics-in-POCO | ||||||
|  | #ifndef POCO_NEW_STATE_ON_MOVE | ||||||
|  | #define POCO_NEW_STATE_ON_MOVE 1 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| // Windows CE has no locale support | // Windows CE has no locale support | ||||||
| #if defined(_WIN32_WCE) | #if defined(_WIN32_WCE) | ||||||
| 	#define POCO_NO_LOCALE | 	#define POCO_NO_LOCALE | ||||||
|   | |||||||
| @@ -10,6 +10,9 @@ | |||||||
| // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. | // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. | ||||||
| // and Contributors. | // and Contributors. | ||||||
| // | // | ||||||
|  | // hashRange Copyright 2005-2014 Daniel James. | ||||||
|  | // (Extracted from Boost 1.75.0 lib and adapted for poco on 2021-03-31) | ||||||
|  | // | ||||||
| // SPDX-License-Identifier:	BSL-1.0 | // SPDX-License-Identifier:	BSL-1.0 | ||||||
| // | // | ||||||
|  |  | ||||||
| @@ -19,9 +22,17 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
| #include "Poco/Foundation.h" | #include "Poco/Foundation.h" | ||||||
|  | #include "Poco/Types.h" | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #if defined(_MSC_VER) | ||||||
|  | #   define POCO_HASH_ROTL32(x, r) _rotl(x,r) | ||||||
|  | #else | ||||||
|  | #   define POCO_HASH_ROTL32(x, r) (x << r) | (x >> (32 - r)) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| namespace Poco { | namespace Poco { | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -99,6 +110,90 @@ inline std::size_t hash(UInt64 n) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | namespace Impl { | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template <typename SizeT> | ||||||
|  | inline void hashCombine(SizeT& seed, SizeT value) | ||||||
|  | { | ||||||
|  |     seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline void hashCombine(Poco::UInt32& h1, Poco::UInt32 k1) | ||||||
|  | { | ||||||
|  |     const uint32_t c1 = 0xcc9e2d51; | ||||||
|  |     const uint32_t c2 = 0x1b873593; | ||||||
|  |  | ||||||
|  |     k1 *= c1; | ||||||
|  |     k1 = POCO_HASH_ROTL32(k1,15); | ||||||
|  |     k1 *= c2; | ||||||
|  |  | ||||||
|  |     h1 ^= k1; | ||||||
|  |     h1 = POCO_HASH_ROTL32(h1,13); | ||||||
|  |     h1 = h1*5+0xe6546b64; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #if defined(POCO_PTR_IS_64_BIT) && !(defined(__GNUC__) && ULONG_MAX == 0xffffffff) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline void hashCombine(Poco::UInt64& h, Poco::UInt64 k) | ||||||
|  | { | ||||||
|  |     const Poco::UInt64 m = UINT64_C(0xc6a4a7935bd1e995); | ||||||
|  |     const int r = 47; | ||||||
|  |  | ||||||
|  |     k *= m; | ||||||
|  |     k ^= k >> r; | ||||||
|  |     k *= m; | ||||||
|  |  | ||||||
|  |     h ^= k; | ||||||
|  |     h *= m; | ||||||
|  |  | ||||||
|  |     // Completely arbitrary number, to | ||||||
|  |     // prevent zeros from hashing to 0. | ||||||
|  |     h += 0xe6546b64; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif // POCO_PTR_IS_64_BIT | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } // namespace Impl | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template <class T> | ||||||
|  | inline void hashCombine(std::size_t& seed, T const& v) | ||||||
|  | { | ||||||
|  |     Hash<T> hasher; | ||||||
|  |     Impl::hashCombine(seed, hasher(v)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template <class It> | ||||||
|  | inline std::size_t hashRange(It first, It last) | ||||||
|  | { | ||||||
|  |     std::size_t seed = 0; | ||||||
|  |  | ||||||
|  |     for(; first != last; ++first) | ||||||
|  |     { | ||||||
|  |         hashCombine<typename std::iterator_traits<It>::value_type>(seed, *first); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return seed; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template <class It> | ||||||
|  | inline void hashRange(std::size_t& seed, It first, It last) | ||||||
|  | { | ||||||
|  |     for(; first != last; ++first) | ||||||
|  |     { | ||||||
|  |         hashCombine<typename std::iterator_traits<It>::value_type>(seed, *first); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| } // namespace Poco | } // namespace Poco | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										0
									
								
								Foundation/include/Poco/NObserver.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								Foundation/include/Poco/NObserver.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
								
								
									
										0
									
								
								Foundation/include/Poco/Observer.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								Foundation/include/Poco/Observer.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -35,7 +35,7 @@ | |||||||
| 	#error Inconsistent build settings (check for /MD[d]) | 	#error Inconsistent build settings (check for /MD[d]) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | // https://en.wikipedia.org/wiki/Microsoft_Visual_C++ | ||||||
| #if (_MSC_VER >= 1300) && (_MSC_VER < 1400)   // Visual Studio 2003, MSVC++ 7.1 | #if (_MSC_VER >= 1300) && (_MSC_VER < 1400)   // Visual Studio 2003, MSVC++ 7.1 | ||||||
| 	#define POCO_MSVS_VERSION 2003 | 	#define POCO_MSVS_VERSION 2003 | ||||||
| 	#define POCO_MSVC_VERSION 71 | 	#define POCO_MSVC_VERSION 71 | ||||||
| @@ -57,9 +57,15 @@ | |||||||
| #elif (_MSC_VER >= 1900) && (_MSC_VER < 1910) // Visual Studio 2015, MSVC++ 14.0 | #elif (_MSC_VER >= 1900) && (_MSC_VER < 1910) // Visual Studio 2015, MSVC++ 14.0 | ||||||
| 	#define POCO_MSVS_VERSION 2015 | 	#define POCO_MSVS_VERSION 2015 | ||||||
| 	#define POCO_MSVC_VERSION 140 | 	#define POCO_MSVC_VERSION 140 | ||||||
| #elif (_MSC_VER >= 1910) && (_MSC_VER < 2000) // Visual Studio 2017, MSVC++ 14.1 | #elif (_MSC_VER >= 1910) && (_MSC_VER < 1920) // Visual Studio 2017, MSVC++ 14.1 | ||||||
| 	#define POCO_MSVS_VERSION 2017 | 	#define POCO_MSVS_VERSION 2017 | ||||||
| 	#define POCO_MSVC_VERSION 141 | 	#define POCO_MSVC_VERSION 141 | ||||||
|  | #elif (_MSC_VER >= 1920) && (_MSC_VER < 1930) // Visual Studio 2019, MSVC++ 14.2 | ||||||
|  | 	#define POCO_MSVS_VERSION 2019 | ||||||
|  | 	#define POCO_MSVC_VERSION 142 | ||||||
|  | #elif (_MSC_VER >= 1930) // Visual Studio 2022, MSVC++ 14.3 | ||||||
|  | 	#define POCO_MSVS_VERSION 2022 | ||||||
|  | 	#define POCO_MSVC_VERSION 143 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ | |||||||
|     <ProjectGuid>{6C41E55D-C0FC-4E01-AA8D-B7DA40E31D3A}</ProjectGuid> |     <ProjectGuid>{6C41E55D-C0FC-4E01-AA8D-B7DA40E31D3A}</ProjectGuid> | ||||||
|     <RootNamespace>TestApp</RootNamespace> |     <RootNamespace>TestApp</RootNamespace> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|     <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'" Label="Configuration"> | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ | |||||||
|     <ProjectGuid>{6C41E55D-C0FC-4E01-AA8D-B7DA40E31D3A}</ProjectGuid> |     <ProjectGuid>{6C41E55D-C0FC-4E01-AA8D-B7DA40E31D3A}</ProjectGuid> | ||||||
|     <RootNamespace>TestApp</RootNamespace> |     <RootNamespace>TestApp</RootNamespace> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|     <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'" Label="Configuration"> | ||||||
|   | |||||||
| @@ -22,7 +22,6 @@ | |||||||
|     <ProjectName>TestLibrary</ProjectName> |     <ProjectName>TestLibrary</ProjectName> | ||||||
|     <ProjectGuid>{0955EB03-544B-4BD4-9C10-89CF38078F5F}</ProjectGuid> |     <ProjectGuid>{0955EB03-544B-4BD4-9C10-89CF38078F5F}</ProjectGuid> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|     <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|Win32'" Label="Configuration"> | ||||||
|   | |||||||
| @@ -22,7 +22,6 @@ | |||||||
|     <ProjectName>TestLibrary</ProjectName> |     <ProjectName>TestLibrary</ProjectName> | ||||||
|     <ProjectGuid>{0955EB03-544B-4BD4-9C10-89CF38078F5F}</ProjectGuid> |     <ProjectGuid>{0955EB03-544B-4BD4-9C10-89CF38078F5F}</ProjectGuid> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|     <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|Win32'" Label="Configuration"> | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ | |||||||
|     <ProjectGuid>{F1EE93DF-347F-4CB3-B191-C4E63F38E972}</ProjectGuid> |     <ProjectGuid>{F1EE93DF-347F-4CB3-B191-C4E63F38E972}</ProjectGuid> | ||||||
|     <RootNamespace>TestSuite</RootNamespace> |     <RootNamespace>TestSuite</RootNamespace> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|     <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ | |||||||
|     <ProjectGuid>{F1EE93DF-347F-4CB3-B191-C4E63F38E972}</ProjectGuid> |     <ProjectGuid>{F1EE93DF-347F-4CB3-B191-C4E63F38E972}</ProjectGuid> | ||||||
|     <RootNamespace>TestSuite</RootNamespace> |     <RootNamespace>TestSuite</RootNamespace> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|     <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ target_link_libraries(JSON PUBLIC Poco::Foundation) | |||||||
| target_include_directories(JSON | target_include_directories(JSON | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ target_link_libraries(JWT PUBLIC Poco::JSON Poco::Crypto) | |||||||
| target_include_directories(JWT | target_include_directories(JWT | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ target_link_libraries(MongoDB PUBLIC Poco::Net) | |||||||
| target_include_directories(MongoDB | target_include_directories(MongoDB | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -35,7 +35,7 @@ endif(WIN32) | |||||||
| target_include_directories(Net | target_include_directories(Net | ||||||
| 	PUBLIC | 	PUBLIC | ||||||
| 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | 		$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||||||
| 		$<INSTALL_INTERFACE:include> | 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||||
| 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | 	PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ objects = \ | |||||||
| 	HTTPRequestHandlerFactory HTTPStreamFactory ServerSocketImpl TCPServerParams \ | 	HTTPRequestHandlerFactory HTTPStreamFactory ServerSocketImpl TCPServerParams \ | ||||||
| 	QuotedPrintableEncoder QuotedPrintableDecoder StringPartSource \ | 	QuotedPrintableEncoder QuotedPrintableDecoder StringPartSource \ | ||||||
| 	FTPClientSession FTPStreamFactory PartHandler PartSource PartStore NullPartHandler \ | 	FTPClientSession FTPStreamFactory PartHandler PartSource PartStore NullPartHandler \ | ||||||
| 	SocketReactor SocketNotifier SocketNotification AbstractHTTPRequestHandler \ | 	SocketReactor SocketProactor SocketNotifier SocketNotification AbstractHTTPRequestHandler \ | ||||||
| 	MailRecipient MailMessage MailStream SMTPClientSession POP3ClientSession \ | 	MailRecipient MailMessage MailStream SMTPClientSession POP3ClientSession \ | ||||||
| 	RawSocket RawSocketImpl ICMPClient ICMPEventArgs ICMPPacket ICMPPacketImpl \ | 	RawSocket RawSocketImpl ICMPClient ICMPEventArgs ICMPPacket ICMPPacketImpl \ | ||||||
| 	ICMPSocket ICMPSocketImpl ICMPv4PacketImpl \ | 	ICMPSocket ICMPSocketImpl ICMPv4PacketImpl \ | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||||
|   <ItemGroup Label="ProjectConfigurations"> |   <ItemGroup Label="ProjectConfigurations"> | ||||||
|     <ProjectConfiguration Include="debug_shared|Win32"> |     <ProjectConfiguration Include="debug_shared|Win32"> | ||||||
| @@ -56,7 +56,7 @@ | |||||||
|     <RootNamespace>Net</RootNamespace> |     <RootNamespace>Net</RootNamespace> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> | ||||||
|     <ConfigurationType>StaticLibrary</ConfigurationType> |     <ConfigurationType>StaticLibrary</ConfigurationType> | ||||||
|     <CharacterSet>MultiByte</CharacterSet> |     <CharacterSet>MultiByte</CharacterSet> | ||||||
| @@ -117,45 +117,45 @@ | |||||||
|     <CharacterSet>MultiByte</CharacterSet> |     <CharacterSet>MultiByte</CharacterSet> | ||||||
|     <PlatformToolset>v142</PlatformToolset> |     <PlatformToolset>v142</PlatformToolset> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | ||||||
|   <ImportGroup Label="ExtensionSettings"/> |   <ImportGroup Label="ExtensionSettings" /> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <PropertyGroup Label="UserMacros"/> |   <PropertyGroup Label="UserMacros" /> | ||||||
|   <PropertyGroup> |   <PropertyGroup> | ||||||
|     <_ProjectFileVersion>15.0.28307.799</_ProjectFileVersion> |     <_ProjectFileVersion>15.0.28307.799</_ProjectFileVersion> | ||||||
|     <TargetName Condition="'$(Configuration)|$(Platform)'=='debug_shared|Win32'">PocoNetd</TargetName> |     <TargetName Condition="'$(Configuration)|$(Platform)'=='debug_shared|Win32'">PocoNetd</TargetName> | ||||||
| @@ -235,7 +235,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
| @@ -268,9 +268,9 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -299,7 +299,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <ProgramDataBaseFileName>..\lib\PocoNetmtd.pdb</ProgramDataBaseFileName> |       <ProgramDataBaseFileName>..\lib\PocoNetmtd.pdb</ProgramDataBaseFileName> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
| @@ -325,9 +325,9 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -347,7 +347,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <ProgramDataBaseFileName>..\lib\PocoNetmdd.pdb</ProgramDataBaseFileName> |       <ProgramDataBaseFileName>..\lib\PocoNetmdd.pdb</ProgramDataBaseFileName> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
| @@ -373,10 +373,10 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <ProgramDataBaseFileName>..\lib\PocoNetmd.pdb</ProgramDataBaseFileName> |       <ProgramDataBaseFileName>..\lib\PocoNetmd.pdb</ProgramDataBaseFileName> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -397,7 +397,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
| @@ -430,9 +430,9 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -461,7 +461,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <ProgramDataBaseFileName>..\lib64\PocoNetmtd.pdb</ProgramDataBaseFileName> |       <ProgramDataBaseFileName>..\lib64\PocoNetmtd.pdb</ProgramDataBaseFileName> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
| @@ -487,9 +487,9 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -509,7 +509,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <ProgramDataBaseFileName>..\lib64\PocoNetmdd.pdb</ProgramDataBaseFileName> |       <ProgramDataBaseFileName>..\lib64\PocoNetmdd.pdb</ProgramDataBaseFileName> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
| @@ -535,9 +535,9 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -546,122 +546,123 @@ | |||||||
|     </Lib> |     </Lib> | ||||||
|   </ItemDefinitionGroup> |   </ItemDefinitionGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClInclude Include="include\Poco\Net\AbstractHTTPRequestHandler.h"/> |     <ClInclude Include="include\Poco\Net\AbstractHTTPRequestHandler.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\DatagramSocket.h"/> |     <ClInclude Include="include\Poco\Net\DatagramSocket.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\DatagramSocketImpl.h"/> |     <ClInclude Include="include\Poco\Net\DatagramSocketImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\DialogSocket.h"/> |     <ClInclude Include="include\Poco\Net\DialogSocket.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\DNS.h"/> |     <ClInclude Include="include\Poco\Net\DNS.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\FilePartSource.h"/> |     <ClInclude Include="include\Poco\Net\FilePartSource.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\FTPClientSession.h"/> |     <ClInclude Include="include\Poco\Net\FTPClientSession.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\FTPStreamFactory.h"/> |     <ClInclude Include="include\Poco\Net\FTPStreamFactory.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HostEntry.h"/> |     <ClInclude Include="include\Poco\Net\HostEntry.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTMLForm.h"/> |     <ClInclude Include="include\Poco\Net\HTMLForm.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPAuthenticationParams.h"/> |     <ClInclude Include="include\Poco\Net\HTTPAuthenticationParams.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPBasicCredentials.h"/> |     <ClInclude Include="include\Poco\Net\HTTPBasicCredentials.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPBasicStreamBuf.h"/> |     <ClInclude Include="include\Poco\Net\HTTPBasicStreamBuf.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPBufferAllocator.h"/> |     <ClInclude Include="include\Poco\Net\HTTPBufferAllocator.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPChunkedStream.h"/> |     <ClInclude Include="include\Poco\Net\HTTPChunkedStream.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPClientSession.h"/> |     <ClInclude Include="include\Poco\Net\HTTPClientSession.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPCookie.h"/> |     <ClInclude Include="include\Poco\Net\HTTPCookie.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPCredentials.h"/> |     <ClInclude Include="include\Poco\Net\HTTPCredentials.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPDigestCredentials.h"/> |     <ClInclude Include="include\Poco\Net\HTTPDigestCredentials.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPFixedLengthStream.h"/> |     <ClInclude Include="include\Poco\Net\HTTPFixedLengthStream.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPHeaderStream.h"/> |     <ClInclude Include="include\Poco\Net\HTTPHeaderStream.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPIOStream.h"/> |     <ClInclude Include="include\Poco\Net\HTTPIOStream.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPMessage.h"/> |     <ClInclude Include="include\Poco\Net\HTTPMessage.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPNTLMCredentials.h"/> |     <ClInclude Include="include\Poco\Net\HTTPNTLMCredentials.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPRequest.h"/> |     <ClInclude Include="include\Poco\Net\HTTPRequest.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPRequestHandler.h"/> |     <ClInclude Include="include\Poco\Net\HTTPRequestHandler.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPRequestHandlerFactory.h"/> |     <ClInclude Include="include\Poco\Net\HTTPRequestHandlerFactory.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPResponse.h"/> |     <ClInclude Include="include\Poco\Net\HTTPResponse.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPServer.h"/> |     <ClInclude Include="include\Poco\Net\HTTPServer.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPServerConnection.h"/> |     <ClInclude Include="include\Poco\Net\HTTPServerConnection.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPServerConnectionFactory.h"/> |     <ClInclude Include="include\Poco\Net\HTTPServerConnectionFactory.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPServerParams.h"/> |     <ClInclude Include="include\Poco\Net\HTTPServerParams.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPServerRequest.h"/> |     <ClInclude Include="include\Poco\Net\HTTPServerRequest.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPServerRequestImpl.h"/> |     <ClInclude Include="include\Poco\Net\HTTPServerRequestImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPServerResponse.h"/> |     <ClInclude Include="include\Poco\Net\HTTPServerResponse.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPServerResponseImpl.h"/> |     <ClInclude Include="include\Poco\Net\HTTPServerResponseImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPServerSession.h"/> |     <ClInclude Include="include\Poco\Net\HTTPServerSession.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPSession.h"/> |     <ClInclude Include="include\Poco\Net\HTTPSession.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPSessionFactory.h"/> |     <ClInclude Include="include\Poco\Net\HTTPSessionFactory.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPSessionInstantiator.h"/> |     <ClInclude Include="include\Poco\Net\HTTPSessionInstantiator.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPStream.h"/> |     <ClInclude Include="include\Poco\Net\HTTPStream.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\HTTPStreamFactory.h"/> |     <ClInclude Include="include\Poco\Net\HTTPStreamFactory.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\ICMPClient.h"/> |     <ClInclude Include="include\Poco\Net\ICMPClient.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\ICMPEventArgs.h"/> |     <ClInclude Include="include\Poco\Net\ICMPEventArgs.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\ICMPPacket.h"/> |     <ClInclude Include="include\Poco\Net\ICMPPacket.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\ICMPPacketImpl.h"/> |     <ClInclude Include="include\Poco\Net\ICMPPacketImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\ICMPSocket.h"/> |     <ClInclude Include="include\Poco\Net\ICMPSocket.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\ICMPSocketImpl.h"/> |     <ClInclude Include="include\Poco\Net\ICMPSocketImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\ICMPv4PacketImpl.h"/> |     <ClInclude Include="include\Poco\Net\ICMPv4PacketImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\IPAddress.h"/> |     <ClInclude Include="include\Poco\Net\IPAddress.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\IPAddressImpl.h"/> |     <ClInclude Include="include\Poco\Net\IPAddressImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\MailMessage.h"/> |     <ClInclude Include="include\Poco\Net\MailMessage.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\MailRecipient.h"/> |     <ClInclude Include="include\Poco\Net\MailRecipient.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\MailStream.h"/> |     <ClInclude Include="include\Poco\Net\MailStream.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\MediaType.h"/> |     <ClInclude Include="include\Poco\Net\MediaType.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\MessageHeader.h"/> |     <ClInclude Include="include\Poco\Net\MessageHeader.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\MulticastSocket.h"/> |     <ClInclude Include="include\Poco\Net\MulticastSocket.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\MultipartReader.h"/> |     <ClInclude Include="include\Poco\Net\MultipartReader.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\MultipartWriter.h"/> |     <ClInclude Include="include\Poco\Net\MultipartWriter.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\MultiSocketPoller.h"/> |     <ClInclude Include="include\Poco\Net\MultiSocketPoller.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\NameValueCollection.h"/> |     <ClInclude Include="include\Poco\Net\NameValueCollection.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\Net.h"/> |     <ClInclude Include="include\Poco\Net\Net.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\NetException.h"/> |     <ClInclude Include="include\Poco\Net\NetException.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\NetworkInterface.h"/> |     <ClInclude Include="include\Poco\Net\NetworkInterface.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\NTLMCredentials.h"/> |     <ClInclude Include="include\Poco\Net\NTLMCredentials.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\NTPClient.h"/> |     <ClInclude Include="include\Poco\Net\NTPClient.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\NTPEventArgs.h"/> |     <ClInclude Include="include\Poco\Net\NTPEventArgs.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\NTPPacket.h"/> |     <ClInclude Include="include\Poco\Net\NTPPacket.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\NullPartHandler.h"/> |     <ClInclude Include="include\Poco\Net\NullPartHandler.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\OAuth10Credentials.h"/> |     <ClInclude Include="include\Poco\Net\OAuth10Credentials.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\OAuth20Credentials.h"/> |     <ClInclude Include="include\Poco\Net\OAuth20Credentials.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\ParallelSocketAcceptor.h"/> |     <ClInclude Include="include\Poco\Net\ParallelSocketAcceptor.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\ParallelSocketReactor.h"/> |     <ClInclude Include="include\Poco\Net\ParallelSocketReactor.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\PartHandler.h"/> |     <ClInclude Include="include\Poco\Net\PartHandler.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\PartSource.h"/> |     <ClInclude Include="include\Poco\Net\PartSource.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\PartStore.h"/> |     <ClInclude Include="include\Poco\Net\PartStore.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\PollSet.h"/> |     <ClInclude Include="include\Poco\Net\PollSet.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\POP3ClientSession.h"/> |     <ClInclude Include="include\Poco\Net\POP3ClientSession.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\QuotedPrintableDecoder.h"/> |     <ClInclude Include="include\Poco\Net\QuotedPrintableDecoder.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\QuotedPrintableEncoder.h"/> |     <ClInclude Include="include\Poco\Net\QuotedPrintableEncoder.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\RawSocket.h"/> |     <ClInclude Include="include\Poco\Net\RawSocket.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\RawSocketImpl.h"/> |     <ClInclude Include="include\Poco\Net\RawSocketImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\RemoteSyslogChannel.h"/> |     <ClInclude Include="include\Poco\Net\RemoteSyslogChannel.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\RemoteSyslogListener.h"/> |     <ClInclude Include="include\Poco\Net\RemoteSyslogListener.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\ServerSocket.h"/> |     <ClInclude Include="include\Poco\Net\ServerSocket.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\ServerSocketImpl.h"/> |     <ClInclude Include="include\Poco\Net\ServerSocketImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SingleSocketPoller.h"/> |     <ClInclude Include="include\Poco\Net\SingleSocketPoller.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SMTPChannel.h"/> |     <ClInclude Include="include\Poco\Net\SMTPChannel.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SMTPClientSession.h"/> |     <ClInclude Include="include\Poco\Net\SMTPClientSession.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\Socket.h"/> |     <ClInclude Include="include\Poco\Net\Socket.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SocketAcceptor.h"/> |     <ClInclude Include="include\Poco\Net\SocketAcceptor.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SocketAddress.h"/> |     <ClInclude Include="include\Poco\Net\SocketAddress.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SocketAddressImpl.h"/> |     <ClInclude Include="include\Poco\Net\SocketAddressImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SocketConnector.h"/> |     <ClInclude Include="include\Poco\Net\SocketConnector.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SocketDefs.h"/> |     <ClInclude Include="include\Poco\Net\SocketDefs.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SocketImpl.h"/> |     <ClInclude Include="include\Poco\Net\SocketImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SocketNotification.h"/> |     <ClInclude Include="include\Poco\Net\SocketNotification.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SocketNotifier.h"/> |     <ClInclude Include="include\Poco\Net\SocketNotifier.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SocketReactor.h"/> |     <ClInclude Include="include\Poco\Net\SocketProactor.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SocketStream.h"/> |     <ClInclude Include="include\Poco\Net\SocketReactor.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\SSPINTLMCredentials.h"/> |     <ClInclude Include="include\Poco\Net\SocketStream.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\StreamSocket.h"/> |     <ClInclude Include="include\Poco\Net\SSPINTLMCredentials.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\StreamSocketImpl.h"/> |     <ClInclude Include="include\Poco\Net\StreamSocket.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\StringPartSource.h"/> |     <ClInclude Include="include\Poco\Net\StreamSocketImpl.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\TCPServer.h"/> |     <ClInclude Include="include\Poco\Net\StringPartSource.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\TCPServerConnection.h"/> |     <ClInclude Include="include\Poco\Net\TCPServer.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\TCPServerConnectionFactory.h"/> |     <ClInclude Include="include\Poco\Net\TCPServerConnection.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\TCPServerDispatcher.h"/> |     <ClInclude Include="include\Poco\Net\TCPServerConnectionFactory.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\TCPServerParams.h"/> |     <ClInclude Include="include\Poco\Net\TCPServerDispatcher.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\UDPClient.h"/> |     <ClInclude Include="include\Poco\Net\TCPServerParams.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\UDPHandler.h"/> |     <ClInclude Include="include\Poco\Net\UDPClient.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\UDPServer.h"/> |     <ClInclude Include="include\Poco\Net\UDPHandler.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\UDPServerParams.h"/> |     <ClInclude Include="include\Poco\Net\UDPServer.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\UDPSocketReader.h"/> |     <ClInclude Include="include\Poco\Net\UDPServerParams.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\WebSocket.h"/> |     <ClInclude Include="include\Poco\Net\UDPSocketReader.h" /> | ||||||
|     <ClInclude Include="include\Poco\Net\WebSocketImpl.h"/> |     <ClInclude Include="include\Poco\Net\WebSocket.h" /> | ||||||
|  |     <ClInclude Include="include\Poco\Net\WebSocketImpl.h" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="src\AbstractHTTPRequestHandler.cpp"> |     <ClCompile Include="src\AbstractHTTPRequestHandler.cpp"> | ||||||
| @@ -934,6 +935,7 @@ | |||||||
|     <ClCompile Include="src\SocketNotifier.cpp"> |     <ClCompile Include="src\SocketNotifier.cpp"> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="src\SocketProactor.cpp" /> | ||||||
|     <ClCompile Include="src\SocketReactor.cpp"> |     <ClCompile Include="src\SocketReactor.cpp"> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -992,6 +994,6 @@ | |||||||
|       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'">true</ExcludedFromBuild> |       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'">true</ExcludedFromBuild> | ||||||
|     </ResourceCompile> |     </ResourceCompile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | ||||||
|   <ImportGroup Label="ExtensionTargets"/> |   <ImportGroup Label="ExtensionTargets" /> | ||||||
| </Project> | </Project> | ||||||
| @@ -513,6 +513,9 @@ | |||||||
|     <ClInclude Include="include\Poco\Net\SSPINTLMCredentials.h"> |     <ClInclude Include="include\Poco\Net\SSPINTLMCredentials.h"> | ||||||
|       <Filter>NTLM\Header Files</Filter> |       <Filter>NTLM\Header Files</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  |     <ClInclude Include="include\Poco\Net\SocketProactor.h"> | ||||||
|  |       <Filter>Sockets\Header Files</Filter> | ||||||
|  |     </ClInclude> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="src\DNS.cpp"> |     <ClCompile Include="src\DNS.cpp"> | ||||||
| @@ -830,6 +833,9 @@ | |||||||
|     <ClCompile Include="src\SSPINTLMCredentials.cpp"> |     <ClCompile Include="src\SSPINTLMCredentials.cpp"> | ||||||
|       <Filter>NTLM\Source Files</Filter> |       <Filter>NTLM\Source Files</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="src\SocketProactor.cpp"> | ||||||
|  |       <Filter>Sockets\Source Files</Filter> | ||||||
|  |     </ClCompile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ResourceCompile Include="..\DLLVersion.rc" /> |     <ResourceCompile Include="..\DLLVersion.rc" /> | ||||||
|   | |||||||
| @@ -48,19 +48,14 @@ public: | |||||||
| 		/// The socket will be created for the | 		/// The socket will be created for the | ||||||
| 		/// given address family. | 		/// given address family. | ||||||
|  |  | ||||||
| 	DatagramSocket(const SocketAddress& address, bool reuseAddress = false); | 	DatagramSocket(const SocketAddress& address, bool reuseAddress, bool reusePort = false, bool ipV6Only = false); | ||||||
| 		/// Creates a datagram socket and binds it |  | ||||||
| 		/// to the given address. |  | ||||||
| 		/// |  | ||||||
| 		/// Depending on the address family, the socket |  | ||||||
| 		/// will be either an IPv4 or an IPv6 socket. |  | ||||||
|  |  | ||||||
| 	DatagramSocket(const SocketAddress& address, bool reuseAddress, bool reusePort); |  | ||||||
| 		/// Creates a datagram socket and binds it | 		/// Creates a datagram socket and binds it | ||||||
| 		/// to the given address. | 		/// to the given address. | ||||||
| 		/// | 		/// | ||||||
| 		/// Depending on the address family, the socket | 		/// Depending on the address family, the socket | ||||||
| 		/// will be either an IPv4 or an IPv6 socket. | 		/// will be either an IPv4 or an IPv6 socket. | ||||||
|  | 		/// If ipV6Only is true, socket will be bound | ||||||
|  | 		/// to the IPv6 address only. | ||||||
|  |  | ||||||
| 	DatagramSocket(const Socket& socket); | 	DatagramSocket(const Socket& socket); | ||||||
| 		/// Creates the DatagramSocket with the SocketImpl | 		/// Creates the DatagramSocket with the SocketImpl | ||||||
| @@ -68,6 +63,10 @@ public: | |||||||
| 		/// a DatagramSocketImpl, otherwise an InvalidArgumentException | 		/// a DatagramSocketImpl, otherwise an InvalidArgumentException | ||||||
| 		/// will be thrown. | 		/// will be thrown. | ||||||
|  |  | ||||||
|  | 	DatagramSocket(const DatagramSocket& socket); | ||||||
|  | 		/// Creates the DatagramSocket with the SocketImpl | ||||||
|  | 		/// from another socket. | ||||||
|  |  | ||||||
| 	~DatagramSocket(); | 	~DatagramSocket(); | ||||||
| 		/// Destroys the DatagramSocket. | 		/// Destroys the DatagramSocket. | ||||||
|  |  | ||||||
| @@ -78,6 +77,43 @@ public: | |||||||
| 		/// attaches the SocketImpl from the other socket and | 		/// attaches the SocketImpl from the other socket and | ||||||
| 		/// increments the reference count of the SocketImpl. | 		/// increments the reference count of the SocketImpl. | ||||||
|  |  | ||||||
|  | #if POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
|  | 	DatagramSocket(Socket&& socket); | ||||||
|  | 		/// Creates the DatagramSocket with the SocketImpl | ||||||
|  | 		/// from another socket and zeroes the other socket's | ||||||
|  | 		/// SocketImpl.The SocketImpl must be | ||||||
|  | 		/// a DatagramSocketImpl, otherwise an InvalidArgumentException | ||||||
|  | 		/// will be thrown. | ||||||
|  |  | ||||||
|  | 	DatagramSocket(DatagramSocket&& socket); | ||||||
|  | 		/// Creates the DatagramSocket with the SocketImpl | ||||||
|  | 		/// from another socket and zeroes the other socket's | ||||||
|  | 		/// SocketImpl. | ||||||
|  |  | ||||||
|  | 	DatagramSocket& operator = (Socket&& socket); | ||||||
|  | 		/// Assignment move operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl and | ||||||
|  | 		/// attaches the SocketImpl from the other socket and | ||||||
|  | 		/// zeroes the other socket's SocketImpl. | ||||||
|  |  | ||||||
|  | 	DatagramSocket& operator = (DatagramSocket&& socket); | ||||||
|  | 		/// Assignment move operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl and | ||||||
|  | 		/// attaches the SocketImpl from the other socket and | ||||||
|  | 		/// zeroes the other socket's SocketImpl. | ||||||
|  |  | ||||||
|  | #endif // POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
|  | 	DatagramSocket& operator = (const DatagramSocket& socket); | ||||||
|  | 		/// Assignment operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl and | ||||||
|  | 		/// attaches the SocketImpl from the other socket and | ||||||
|  | 		/// increments the reference count of the SocketImpl. | ||||||
|  |  | ||||||
| 	void connect(const SocketAddress& address); | 	void connect(const SocketAddress& address); | ||||||
| 		/// Restricts incoming and outgoing | 		/// Restricts incoming and outgoing | ||||||
| 		/// packets to the specified address. | 		/// packets to the specified address. | ||||||
| @@ -109,6 +145,23 @@ public: | |||||||
| 		/// | 		/// | ||||||
| 		/// Calls to connect cannot() come before calls to bind(). | 		/// Calls to connect cannot() come before calls to bind(). | ||||||
|  |  | ||||||
|  | 	void bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only = false); | ||||||
|  | 		/// Bind a local address to the socket. | ||||||
|  | 		/// | ||||||
|  | 		/// This is usually only done when establishing a server | ||||||
|  | 		/// socket. | ||||||
|  | 		/// | ||||||
|  | 		/// If reuseAddress is true, sets the SO_REUSEADDR | ||||||
|  | 		/// socket option. | ||||||
|  | 		/// | ||||||
|  | 		/// If reusePort is true, sets the SO_REUSEPORT | ||||||
|  | 		/// socket option. | ||||||
|  | 		/// | ||||||
|  | 		/// Sets the IPV6_V6ONLY socket option in accordance with | ||||||
|  | 		/// the supplied ipV6Only value. | ||||||
|  | 		/// | ||||||
|  | 		/// Calls to connect cannot() come before calls to bind(). | ||||||
|  |  | ||||||
| 	int sendBytes(const void* buffer, int length, int flags = 0); | 	int sendBytes(const void* buffer, int length, int flags = 0); | ||||||
| 		/// Sends the contents of the given buffer through | 		/// Sends the contents of the given buffer through | ||||||
| 		/// the socket. | 		/// the socket. | ||||||
| @@ -231,7 +284,7 @@ protected: | |||||||
| 		/// Creates the Socket and attaches the given SocketImpl. | 		/// Creates the Socket and attaches the given SocketImpl. | ||||||
| 		/// The socket takes ownership of the SocketImpl. | 		/// The socket takes ownership of the SocketImpl. | ||||||
| 		/// | 		/// | ||||||
| 		/// The SocketImpl must be a StreamSocketImpl, otherwise | 		/// The SocketImpl must be a DatagramSocketImpl, otherwise | ||||||
| 		/// an InvalidArgumentException will be thrown. | 		/// an InvalidArgumentException will be thrown. | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ | |||||||
| #include "Poco/AutoPtr.h" | #include "Poco/AutoPtr.h" | ||||||
| #include "Poco/Exception.h" | #include "Poco/Exception.h" | ||||||
| #include <vector> | #include <vector> | ||||||
|  | #include <array> | ||||||
| #include <ostream> | #include <ostream> | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -56,6 +57,13 @@ class Net_API IPAddress | |||||||
| public: | public: | ||||||
| 	using List = std::vector<IPAddress>; | 	using List = std::vector<IPAddress>; | ||||||
|  |  | ||||||
|  | 	using RawIP = std::vector<unsigned char>; | ||||||
|  |  | ||||||
|  | 	static const unsigned IPv4Size = sizeof(in_addr); | ||||||
|  | 	static const unsigned IPv6Size = sizeof(in6_addr); | ||||||
|  | 	using RawIPv4 = std::array<unsigned char, IPv4Size>; | ||||||
|  | 	using RawIPv6 = std::array<unsigned char, IPv6Size>; | ||||||
|  |  | ||||||
| 	// The following declarations keep the Family type | 	// The following declarations keep the Family type | ||||||
| 	// backwards compatible with the previously used | 	// backwards compatible with the previously used | ||||||
| 	// enum declaration. | 	// enum declaration. | ||||||
| @@ -71,6 +79,9 @@ public: | |||||||
| 	IPAddress(const IPAddress& addr); | 	IPAddress(const IPAddress& addr); | ||||||
| 		/// Creates an IPAddress by copying another one. | 		/// Creates an IPAddress by copying another one. | ||||||
|  |  | ||||||
|  | 	IPAddress(IPAddress&& addr); | ||||||
|  | 		/// Creates an IPAddress by moving another one. | ||||||
|  |  | ||||||
| 	explicit IPAddress(Family family); | 	explicit IPAddress(Family family); | ||||||
| 		/// Creates a wildcard (zero) IPAddress for the | 		/// Creates a wildcard (zero) IPAddress for the | ||||||
| 		/// given address family. | 		/// given address family. | ||||||
| @@ -122,6 +133,15 @@ public: | |||||||
| 	IPAddress& operator = (const IPAddress& addr); | 	IPAddress& operator = (const IPAddress& addr); | ||||||
| 		/// Assigns an IPAddress. | 		/// Assigns an IPAddress. | ||||||
|  |  | ||||||
|  | 	IPAddress& operator = (IPAddress&& addr); | ||||||
|  | 		/// Move-assigns an IPAddress. | ||||||
|  |  | ||||||
|  | 	bool isV4() const; | ||||||
|  | 	bool isV6() const; | ||||||
|  | 	RawIPv4 toV4Bytes() const; | ||||||
|  | 	RawIPv6 toV6Bytes() const; | ||||||
|  | 	RawIP toBytes() const; | ||||||
|  |  | ||||||
| 	Family family() const; | 	Family family() const; | ||||||
| 		/// Returns the address family (IPv4 or IPv6) of the address. | 		/// Returns the address family (IPv4 or IPv6) of the address. | ||||||
|  |  | ||||||
| @@ -376,6 +396,8 @@ private: | |||||||
| 	void newIPv6(const void* hostAddr); | 	void newIPv6(const void* hostAddr); | ||||||
| 	void newIPv6(const void* hostAddr, Poco::UInt32 scope); | 	void newIPv6(const void* hostAddr, Poco::UInt32 scope); | ||||||
| 	void newIPv6(unsigned prefix); | 	void newIPv6(unsigned prefix); | ||||||
|  | 	static std::string& compressV6(std::string& v6addr); | ||||||
|  | 	static std::string trimIPv6(const std::string v6Addr); | ||||||
| #endif | #endif | ||||||
| 	Ptr _pImpl; | 	Ptr _pImpl; | ||||||
| }; | }; | ||||||
| @@ -384,6 +406,19 @@ private: | |||||||
| // | // | ||||||
| // inlines | // inlines | ||||||
| // | // | ||||||
|  |  | ||||||
|  | inline bool IPAddress::isV4() const | ||||||
|  | { | ||||||
|  | 	return family() == IPv4; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline bool IPAddress::isV6() const | ||||||
|  | { | ||||||
|  | 	return family() == IPv6; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline IPAddress::Ptr IPAddress::pImpl() const | inline IPAddress::Ptr IPAddress::pImpl() const | ||||||
| { | { | ||||||
| 	if (_pImpl) return _pImpl; | 	if (_pImpl) return _pImpl; | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ namespace Net { | |||||||
| template <std::size_t S = POCO_UDP_BUF_SIZE> | template <std::size_t S = POCO_UDP_BUF_SIZE> | ||||||
| class MultiSocketPoller | class MultiSocketPoller | ||||||
| 	/// MultiSocketPoller, as its name indicates, repeatedly polls a set of | 	/// MultiSocketPoller, as its name indicates, repeatedly polls a set of | ||||||
| 	/// sockets for readability and/or eror. If socket is readable or in error | 	/// sockets for readability and/or error. If socket is readable or in error | ||||||
| 	/// state, the reading/error handling actions are delegated to the reader. | 	/// state, the reading/error handling actions are delegated to the reader. | ||||||
| { | { | ||||||
| public: | public: | ||||||
|   | |||||||
| @@ -67,6 +67,14 @@ | |||||||
| #endif // POCO_NET_NO_IPv6, POCO_HAVE_IPv6 | #endif // POCO_NET_NO_IPv6, POCO_HAVE_IPv6 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Default to enabled local socket support if not explicitly disabled | ||||||
|  | #if !defined(POCO_NET_NO_UNIX_SOCKET) && !defined (POCO_HAVE_UNIX_SOCKET) | ||||||
|  | 	#define POCO_HAVE_UNIX_SOCKET | ||||||
|  | #elif defined(POCO_NET_NO_UNIX_SOCKET) && defined (POCO_HAVE_UNIX_SOCKET) | ||||||
|  | 	#undef POCO_HAVE_UNIX_SOCKET | ||||||
|  | #endif // POCO_NET_NO_UNIX_SOCKET, POCO_HAVE_UNIX_SOCKET | ||||||
|  |  | ||||||
|  |  | ||||||
| namespace Poco { | namespace Poco { | ||||||
| namespace Net { | namespace Net { | ||||||
|  |  | ||||||
| @@ -124,4 +132,24 @@ POCO_NET_FORCE_SYMBOL(pocoNetworkInitializer) | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #if defined(POCO_OS_FAMILY_BSD) | ||||||
|  | 	#ifndef POCO_HAVE_FD_POLL | ||||||
|  | 		#define POCO_HAVE_FD_POLL 1 | ||||||
|  | 	#endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #if defined(POCO_OS_FAMILY_WINDOWS) | ||||||
|  | 	#ifndef POCO_HAVE_FD_POLL | ||||||
|  | 		// WSAPoll wants POLLOUT flag in order to return POLERR when there is no | ||||||
|  | 		// server on the other side. Windows default is multi-fd_set select, WSAPoll | ||||||
|  | 		// is disabled and not considered a production-grade code. | ||||||
|  | 		// see https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsapoll | ||||||
|  | 		// This is the version where the WSAPoll was (allegedly) fixed. | ||||||
|  | 		#if defined(WDK_NTDDI_VERSION) && (WDK_NTDDI_VERSION >= NTDDI_WIN10_VB) | ||||||
|  | 			//#define POCO_HAVE_FD_POLL 1 | ||||||
|  | 		#endif | ||||||
|  | 	#endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #endif // Net_Net_INCLUDED | #endif // Net_Net_INCLUDED | ||||||
|   | |||||||
| @@ -78,6 +78,13 @@ public: | |||||||
| 		/// Returns a PollMap containing the sockets that have had | 		/// Returns a PollMap containing the sockets that have had | ||||||
| 		/// their state changed. | 		/// their state changed. | ||||||
|  |  | ||||||
|  | 	int count() const; | ||||||
|  | 		/// Returns the numberof sockets monitored. | ||||||
|  |  | ||||||
|  | 	void wakeUp(); | ||||||
|  | 		/// Wakes up a waiting PollSet. | ||||||
|  | 		/// On platforms/implementations where this functionality | ||||||
|  | 		/// is not available, it does nothing. | ||||||
| private: | private: | ||||||
| 	PollSetImpl* _pImpl; | 	PollSetImpl* _pImpl; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -53,6 +53,10 @@ public: | |||||||
| 		/// a RawSocketImpl, otherwise an InvalidArgumentException | 		/// a RawSocketImpl, otherwise an InvalidArgumentException | ||||||
| 		/// will be thrown. | 		/// will be thrown. | ||||||
|  |  | ||||||
|  | 	RawSocket(const RawSocket& socket); | ||||||
|  | 		/// Creates the RawSocket with the SocketImpl | ||||||
|  | 		/// from another socket. | ||||||
|  |  | ||||||
| 	~RawSocket(); | 	~RawSocket(); | ||||||
| 		/// Destroys the RawSocket. | 		/// Destroys the RawSocket. | ||||||
|  |  | ||||||
| @@ -63,6 +67,43 @@ public: | |||||||
| 		/// attaches the SocketImpl from the other socket and | 		/// attaches the SocketImpl from the other socket and | ||||||
| 		/// increments the reference count of the SocketImpl. | 		/// increments the reference count of the SocketImpl. | ||||||
|  |  | ||||||
|  | 	RawSocket& operator = (const RawSocket& socket); | ||||||
|  | 		/// Assignment operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl and | ||||||
|  | 		/// attaches the SocketImpl from the other socket and | ||||||
|  | 		/// increments the reference count of the SocketImpl. | ||||||
|  |  | ||||||
|  | #if POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
|  | 	RawSocket(Socket&& socket); | ||||||
|  | 		/// Creates the RawSocket with the SocketImpl | ||||||
|  | 		/// from another socket and zeroes the other socket's | ||||||
|  | 		/// SocketImpl.The SocketImpl must be | ||||||
|  | 		/// a RawSocketImpl, otherwise an InvalidArgumentException | ||||||
|  | 		/// will be thrown. | ||||||
|  |  | ||||||
|  | 	RawSocket(RawSocket&& socket); | ||||||
|  | 		/// Creates the RawSocket with the SocketImpl | ||||||
|  | 		/// from another socket and zeroes the other socket's | ||||||
|  | 		/// SocketImpl. | ||||||
|  |  | ||||||
|  | 	RawSocket& operator = (Socket&& socket); | ||||||
|  | 		/// Assignment move operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl and | ||||||
|  | 		/// attaches the SocketImpl from the other socket and | ||||||
|  | 		/// zeroes the other socket's SocketImpl. | ||||||
|  |  | ||||||
|  | 	RawSocket& operator = (RawSocket&& socket); | ||||||
|  | 		/// Assignment move operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl and | ||||||
|  | 		/// attaches the SocketImpl from the other socket and | ||||||
|  | 		/// zeroes the other socket's SocketImpl. | ||||||
|  |  | ||||||
|  | #endif //POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
| 	void connect(const SocketAddress& address); | 	void connect(const SocketAddress& address); | ||||||
| 		/// Restricts incoming and outgoing | 		/// Restricts incoming and outgoing | ||||||
| 		/// packets to the specified address. | 		/// packets to the specified address. | ||||||
| @@ -135,7 +176,7 @@ protected: | |||||||
| 		/// Creates the Socket and attaches the given SocketImpl. | 		/// Creates the Socket and attaches the given SocketImpl. | ||||||
| 		/// The socket takes ownership of the SocketImpl. | 		/// The socket takes ownership of the SocketImpl. | ||||||
| 		/// | 		/// | ||||||
| 		/// The SocketImpl must be a StreamSocketImpl, otherwise | 		/// The SocketImpl must be a RawSocketImpl, otherwise | ||||||
| 		/// an InvalidArgumentException will be thrown. | 		/// an InvalidArgumentException will be thrown. | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ namespace Net { | |||||||
|  |  | ||||||
| template <std::size_t S = POCO_UDP_BUF_SIZE> | template <std::size_t S = POCO_UDP_BUF_SIZE> | ||||||
| class SingleSocketPoller | class SingleSocketPoller | ||||||
| 	/// SinlgeSocketPoller, as its name indicates, repeatedly polls a single | 	/// SingleSocketPoller, as its name indicates, repeatedly polls a single | ||||||
| 	/// socket for readability; if the socket is readable, the reading action | 	/// socket for readability; if the socket is readable, the reading action | ||||||
| 	/// is delegated to the reader. | 	/// is delegated to the reader. | ||||||
| { | { | ||||||
|   | |||||||
| @@ -36,6 +36,8 @@ class Net_API Socket | |||||||
| { | { | ||||||
| public: | public: | ||||||
| 	using BufVec = SocketBufVec; | 	using BufVec = SocketBufVec; | ||||||
|  | 	using Type = SocketImpl::Type; | ||||||
|  | 	using SocketList = std::vector<Socket>; | ||||||
|  |  | ||||||
| 	enum SelectMode | 	enum SelectMode | ||||||
| 		/// The mode argument to poll() and select(). | 		/// The mode argument to poll() and select(). | ||||||
| @@ -45,8 +47,6 @@ public: | |||||||
| 		SELECT_ERROR = 4 | 		SELECT_ERROR = 4 | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	using SocketList = std::vector<Socket>; |  | ||||||
|  |  | ||||||
| 	Socket(); | 	Socket(); | ||||||
| 		/// Creates an uninitialized socket. | 		/// Creates an uninitialized socket. | ||||||
|  |  | ||||||
| @@ -63,6 +63,23 @@ public: | |||||||
| 		/// attaches the SocketImpl from the other socket and | 		/// attaches the SocketImpl from the other socket and | ||||||
| 		/// increments the reference count of the SocketImpl. | 		/// increments the reference count of the SocketImpl. | ||||||
|  |  | ||||||
|  | #if POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
|  | 	Socket(Socket&& socket); | ||||||
|  | 		/// Move constructor. | ||||||
|  | 		/// | ||||||
|  | 		/// Attaches the SocketImpl from the other socket and | ||||||
|  | 		/// zeroes the other socket's SocketImpl. | ||||||
|  |  | ||||||
|  | 	Socket& operator = (Socket&& socket); | ||||||
|  | 		/// Assignment move operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl, | ||||||
|  | 		/// attaches the SocketImpl from the other socket, | ||||||
|  | 		/// and zeroes the other socket's SocketImpl. | ||||||
|  |  | ||||||
|  | #endif // POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
| 	virtual ~Socket(); | 	virtual ~Socket(); | ||||||
| 		/// Destroys the Socket and releases the | 		/// Destroys the Socket and releases the | ||||||
| 		/// SocketImpl. | 		/// SocketImpl. | ||||||
| @@ -87,6 +104,24 @@ public: | |||||||
| 	bool operator >= (const Socket& socket) const; | 	bool operator >= (const Socket& socket) const; | ||||||
| 		/// Compares the SocketImpl pointers. | 		/// Compares the SocketImpl pointers. | ||||||
|  |  | ||||||
|  | 	bool isNull() const; | ||||||
|  | 		/// Returns true if pointer to implementation is null. | ||||||
|  |  | ||||||
|  | 	Type type() const; | ||||||
|  | 		/// Returns the socket type. | ||||||
|  |  | ||||||
|  | 	bool isStream() const; | ||||||
|  | 		/// Returns true if socket is a stream socket, | ||||||
|  | 		/// false otherwise. | ||||||
|  |  | ||||||
|  | 	bool isDatagram() const; | ||||||
|  | 		/// Returns true if socket is a datagram socket, | ||||||
|  | 		/// false otherwise. | ||||||
|  |  | ||||||
|  | 	bool isRaw() const; | ||||||
|  | 		/// Returns true if socket is a raw socket, | ||||||
|  | 		/// false otherwise. | ||||||
|  |  | ||||||
| 	void close(); | 	void close(); | ||||||
| 		/// Closes the socket. | 		/// Closes the socket. | ||||||
|  |  | ||||||
| @@ -134,6 +169,9 @@ public: | |||||||
| 		/// Returns the number of bytes available that can be read | 		/// Returns the number of bytes available that can be read | ||||||
| 		/// without causing the socket to block. | 		/// without causing the socket to block. | ||||||
|  |  | ||||||
|  | 	int getError() const; | ||||||
|  | 		/// Returns the socket error. | ||||||
|  |  | ||||||
| 	void setSendBufferSize(int size); | 	void setSendBufferSize(int size); | ||||||
| 		/// Sets the size of the send buffer. | 		/// Sets the size of the send buffer. | ||||||
| 		 | 		 | ||||||
| @@ -334,6 +372,12 @@ public: | |||||||
| 		/// of buffers used for writing (ie. reading from socket | 		/// of buffers used for writing (ie. reading from socket | ||||||
| 		/// into buffers). | 		/// into buffers). | ||||||
|  |  | ||||||
|  | 	static int lastError(); | ||||||
|  | 		/// Returns the last error code. | ||||||
|  |  | ||||||
|  | 	static void error(); | ||||||
|  | 		/// Throws an appropriate exception for the last error. | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
| 	Socket(SocketImpl* pImpl); | 	Socket(SocketImpl* pImpl); | ||||||
| 		/// Creates the Socket and attaches the given SocketImpl. | 		/// Creates the Socket and attaches the given SocketImpl. | ||||||
| @@ -403,212 +447,318 @@ inline bool Socket::operator >= (const Socket& socket) const | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline Socket::Type Socket::type() const | ||||||
|  | { | ||||||
|  | 	return _pImpl->type(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline bool Socket::isStream() const | ||||||
|  | { | ||||||
|  | 	return type() == Type::SOCKET_TYPE_STREAM; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline bool Socket::isDatagram() const | ||||||
|  | { | ||||||
|  | 	return type() == Type::SOCKET_TYPE_DATAGRAM; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline bool Socket::isRaw() const | ||||||
|  | { | ||||||
|  | 	return type() == Type::SOCKET_TYPE_RAW; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline bool Socket::isNull() const | ||||||
|  | { | ||||||
|  | 	return _pImpl == nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::close() | inline void Socket::close() | ||||||
| { | { | ||||||
| 	_pImpl->close(); | 	if (_pImpl) _pImpl->close(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline bool Socket::poll(const Poco::Timespan& timeout, int mode) const | inline bool Socket::poll(const Poco::Timespan& timeout, int mode) const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->poll(timeout, mode); | 	return _pImpl->poll(timeout, mode); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline int Socket::available() const | inline int Socket::available() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->available(); | 	return _pImpl->available(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline int Socket::getError() const | ||||||
|  | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
|  | 	return _pImpl->getError(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setSendBufferSize(int size) | inline void Socket::setSendBufferSize(int size) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setSendBufferSize(size); | 	_pImpl->setSendBufferSize(size); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	 | 	 | ||||||
| inline int Socket::getSendBufferSize() const | inline int Socket::getSendBufferSize() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->getSendBufferSize(); | 	return _pImpl->getSendBufferSize(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setReceiveBufferSize(int size) | inline void Socket::setReceiveBufferSize(int size) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setReceiveBufferSize(size); | 	_pImpl->setReceiveBufferSize(size); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	 | 	 | ||||||
| inline int Socket::getReceiveBufferSize() const | inline int Socket::getReceiveBufferSize() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->getReceiveBufferSize(); | 	return _pImpl->getReceiveBufferSize(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setSendTimeout(const Poco::Timespan& timeout) | inline void Socket::setSendTimeout(const Poco::Timespan& timeout) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setSendTimeout(timeout); | 	_pImpl->setSendTimeout(timeout); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline Poco::Timespan Socket::getSendTimeout() const | inline Poco::Timespan Socket::getSendTimeout() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->getSendTimeout(); | 	return _pImpl->getSendTimeout(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setReceiveTimeout(const Poco::Timespan& timeout) | inline void Socket::setReceiveTimeout(const Poco::Timespan& timeout) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setReceiveTimeout(timeout); | 	_pImpl->setReceiveTimeout(timeout); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline Poco::Timespan Socket::getReceiveTimeout() const | inline Poco::Timespan Socket::getReceiveTimeout() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->getReceiveTimeout(); | 	return _pImpl->getReceiveTimeout(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setOption(int level, int option, int value) | inline void Socket::setOption(int level, int option, int value) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setOption(level, option, value); | 	_pImpl->setOption(level, option, value); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setOption(int level, int option, unsigned value) | inline void Socket::setOption(int level, int option, unsigned value) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setOption(level, option, value); | 	_pImpl->setOption(level, option, value); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setOption(int level, int option, unsigned char value) | inline void Socket::setOption(int level, int option, unsigned char value) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setOption(level, option, value); | 	_pImpl->setOption(level, option, value); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setOption(int level, int option, const Poco::Timespan& value) | inline void Socket::setOption(int level, int option, const Poco::Timespan& value) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setOption(level, option, value); | 	_pImpl->setOption(level, option, value); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setOption(int level, int option, const IPAddress& value) | inline void Socket::setOption(int level, int option, const IPAddress& value) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setOption(level, option, value); | 	_pImpl->setOption(level, option, value); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::getOption(int level, int option, int& value) const | inline void Socket::getOption(int level, int option, int& value) const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->getOption(level, option, value); | 	_pImpl->getOption(level, option, value); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::getOption(int level, int option, unsigned& value) const | inline void Socket::getOption(int level, int option, unsigned& value) const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->getOption(level, option, value); | 	_pImpl->getOption(level, option, value); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::getOption(int level, int option, unsigned char& value) const | inline void Socket::getOption(int level, int option, unsigned char& value) const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->getOption(level, option, value); | 	_pImpl->getOption(level, option, value); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::getOption(int level, int option, Poco::Timespan& value) const | inline void Socket::getOption(int level, int option, Poco::Timespan& value) const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->getOption(level, option, value); | 	_pImpl->getOption(level, option, value); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::getOption(int level, int option, IPAddress& value) const | inline void Socket::getOption(int level, int option, IPAddress& value) const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->getOption(level, option, value); | 	_pImpl->getOption(level, option, value); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setLinger(bool on, int seconds) | inline void Socket::setLinger(bool on, int seconds) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setLinger(on, seconds); | 	_pImpl->setLinger(on, seconds); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	 | 	 | ||||||
| inline void Socket::getLinger(bool& on, int& seconds) const | inline void Socket::getLinger(bool& on, int& seconds) const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->getLinger(on, seconds); | 	_pImpl->getLinger(on, seconds); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setNoDelay(bool flag) | inline void Socket::setNoDelay(bool flag) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setNoDelay(flag); | 	_pImpl->setNoDelay(flag); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	 | 	 | ||||||
| inline bool Socket::getNoDelay() const | inline bool Socket::getNoDelay() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->getNoDelay(); | 	return _pImpl->getNoDelay(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setKeepAlive(bool flag) | inline void Socket::setKeepAlive(bool flag) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setKeepAlive(flag); | 	_pImpl->setKeepAlive(flag); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	 | 	 | ||||||
| inline bool Socket::getKeepAlive() const | inline bool Socket::getKeepAlive() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->getKeepAlive(); | 	return _pImpl->getKeepAlive(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setReuseAddress(bool flag) | inline void Socket::setReuseAddress(bool flag) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setReuseAddress(flag); | 	_pImpl->setReuseAddress(flag); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline bool Socket::getReuseAddress() const | inline bool Socket::getReuseAddress() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->getReuseAddress(); | 	return _pImpl->getReuseAddress(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setReusePort(bool flag) | inline void Socket::setReusePort(bool flag) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setReusePort(flag); | 	_pImpl->setReusePort(flag); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline bool Socket::getReusePort() const | inline bool Socket::getReusePort() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->getReusePort(); | 	return _pImpl->getReusePort(); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	 | 	 | ||||||
| inline void Socket::setOOBInline(bool flag) | inline void Socket::setOOBInline(bool flag) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setOOBInline(flag); | 	_pImpl->setOOBInline(flag); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline bool Socket::getOOBInline() const | inline bool Socket::getOOBInline() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->getOOBInline(); | 	return _pImpl->getOOBInline(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline void Socket::setBlocking(bool flag) | inline void Socket::setBlocking(bool flag) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->setBlocking(flag); | 	_pImpl->setBlocking(flag); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline bool Socket::getBlocking() const | inline bool Socket::getBlocking() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->getBlocking(); | 	return _pImpl->getBlocking(); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -621,24 +771,32 @@ inline SocketImpl* Socket::impl() const | |||||||
|  |  | ||||||
| inline poco_socket_t Socket::sockfd() const | inline poco_socket_t Socket::sockfd() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->sockfd(); | 	return _pImpl->sockfd(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline SocketAddress Socket::address() const | inline SocketAddress Socket::address() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->address(); | 	return _pImpl->address(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline SocketAddress Socket::peerAddress() const | inline SocketAddress Socket::peerAddress() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->peerAddress(); | 	return _pImpl->peerAddress(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline bool Socket::secure() const | inline bool Socket::secure() const | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	return _pImpl->secure(); | 	return _pImpl->secure(); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -661,6 +819,8 @@ inline bool Socket::supportsIPv6() | |||||||
|  |  | ||||||
| inline void Socket::init(int af) | inline void Socket::init(int af) | ||||||
| { | { | ||||||
|  | 	poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); | ||||||
|  |  | ||||||
| 	_pImpl->init(af); | 	_pImpl->init(af); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -138,6 +138,9 @@ public: | |||||||
| 	SocketAddress(const SocketAddress& addr); | 	SocketAddress(const SocketAddress& addr); | ||||||
| 		/// Creates a SocketAddress by copying another one. | 		/// Creates a SocketAddress by copying another one. | ||||||
|  |  | ||||||
|  | 	SocketAddress(SocketAddress&& addr); | ||||||
|  | 		/// Creates a SocketAddress by moving another one. | ||||||
|  |  | ||||||
| 	SocketAddress(const struct sockaddr* addr, poco_socklen_t length); | 	SocketAddress(const struct sockaddr* addr, poco_socklen_t length); | ||||||
| 		/// Creates a SocketAddress from a native socket address. | 		/// Creates a SocketAddress from a native socket address. | ||||||
|  |  | ||||||
| @@ -147,6 +150,9 @@ public: | |||||||
| 	SocketAddress& operator = (const SocketAddress& socketAddress); | 	SocketAddress& operator = (const SocketAddress& socketAddress); | ||||||
| 		/// Assigns another SocketAddress. | 		/// Assigns another SocketAddress. | ||||||
|  |  | ||||||
|  | 	SocketAddress& operator = (SocketAddress&& socketAddress); | ||||||
|  | 		/// Move-assigns another SocketAddress. | ||||||
|  |  | ||||||
| 	IPAddress host() const; | 	IPAddress host() const; | ||||||
| 		/// Returns the host IP address. | 		/// Returns the host IP address. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -82,7 +82,7 @@ public: | |||||||
|  |  | ||||||
| 	SocketConnector(SocketAddress& address, SocketReactor& reactor, bool doRegister = true) : | 	SocketConnector(SocketAddress& address, SocketReactor& reactor, bool doRegister = true) : | ||||||
| 		_pReactor(0) | 		_pReactor(0) | ||||||
| 		/// Creates an acceptor, using the given ServerSocket. | 		/// Creates an connector, using the given ServerSocket. | ||||||
| 		/// The SocketConnector registers itself with the given SocketReactor. | 		/// The SocketConnector registers itself with the given SocketReactor. | ||||||
| 	{ | 	{ | ||||||
| 		_socket.connectNB(address); | 		_socket.connectNB(address); | ||||||
| @@ -167,6 +167,7 @@ public: | |||||||
| 		unregisterConnector(); | 		unregisterConnector(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
| 	virtual ServiceHandler* createServiceHandler() | 	virtual ServiceHandler* createServiceHandler() | ||||||
| 		/// Create and initialize a new ServiceHandler instance. | 		/// Create and initialize a new ServiceHandler instance. | ||||||
|   | |||||||
| @@ -26,6 +26,7 @@ | |||||||
|  |  | ||||||
| #if defined(POCO_OS_FAMILY_WINDOWS) | #if defined(POCO_OS_FAMILY_WINDOWS) | ||||||
| 	#include "Poco/UnWindows.h" | 	#include "Poco/UnWindows.h" | ||||||
|  | 	#define FD_SETSIZE 1024 // increase as needed | ||||||
| 	#include <winsock2.h> | 	#include <winsock2.h> | ||||||
| 	#include <ws2tcpip.h> | 	#include <ws2tcpip.h> | ||||||
| 	#include <ws2def.h> | 	#include <ws2def.h> | ||||||
| @@ -371,16 +372,18 @@ struct AddressFamily | |||||||
| 	enum Family | 	enum Family | ||||||
| 		/// Possible address families for socket addresses. | 		/// Possible address families for socket addresses. | ||||||
| 	{ | 	{ | ||||||
| 		IPv4, | 		UNKNOWN = AF_UNSPEC, | ||||||
|  | 			/// Unspecified family | ||||||
|  | 	#if defined(POCO_OS_FAMILY_UNIX) | ||||||
|  | 		UNIX_LOCAL = AF_UNIX, | ||||||
|  | 			/// UNIX domain socket address family. Available on UNIX/POSIX platforms only. | ||||||
|  | 	#endif | ||||||
|  | 		IPv4 = AF_INET, | ||||||
| 			/// IPv4 address family. | 			/// IPv4 address family. | ||||||
| 	#if defined(POCO_HAVE_IPv6) | 	#if defined(POCO_HAVE_IPv6) | ||||||
| 		IPv6, | 		IPv6 = AF_INET6 | ||||||
| 			/// IPv6 address family. | 			/// IPv6 address family. | ||||||
| 	#endif | 	#endif | ||||||
| 	#if defined(POCO_OS_FAMILY_UNIX) |  | ||||||
| 		UNIX_LOCAL |  | ||||||
| 			/// UNIX domain socket address family. Available on UNIX/POSIX platforms only. |  | ||||||
| 	#endif |  | ||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -39,6 +39,13 @@ class Net_API SocketImpl: public Poco::RefCountedObject | |||||||
| 	/// You should not create any instances of this class. | 	/// You should not create any instances of this class. | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  | 	enum Type | ||||||
|  | 	{ | ||||||
|  | 		SOCKET_TYPE_STREAM = SOCK_STREAM, | ||||||
|  | 		SOCKET_TYPE_DATAGRAM = SOCK_DGRAM, | ||||||
|  | 		SOCKET_TYPE_RAW = SOCK_RAW | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	enum SelectMode | 	enum SelectMode | ||||||
| 	{ | 	{ | ||||||
| 		SELECT_READ  = 1, | 		SELECT_READ  = 1, | ||||||
| @@ -271,6 +278,12 @@ public: | |||||||
| 		/// Returns true if the next operation corresponding to | 		/// Returns true if the next operation corresponding to | ||||||
| 		/// mode will not block, false otherwise. | 		/// mode will not block, false otherwise. | ||||||
|  |  | ||||||
|  | 	Type type(); | ||||||
|  | 		/// Returns the socket type. | ||||||
|  |  | ||||||
|  | 	virtual int getError(); | ||||||
|  | 		/// Returns the socket error. | ||||||
|  |  | ||||||
| 	virtual void setSendBufferSize(int size); | 	virtual void setSendBufferSize(int size); | ||||||
| 		/// Sets the size of the send buffer. | 		/// Sets the size of the send buffer. | ||||||
|  |  | ||||||
| @@ -526,6 +539,17 @@ private: | |||||||
| // | // | ||||||
| // inlines | // inlines | ||||||
| // | // | ||||||
|  | inline SocketImpl::Type SocketImpl::type() | ||||||
|  | { | ||||||
|  | 	int type; | ||||||
|  | 	getOption(SOL_SOCKET, SO_TYPE, type); | ||||||
|  | 	poco_assert_dbg(type == SOCK_STREAM || | ||||||
|  | 					type == SOCK_DGRAM || | ||||||
|  | 					type == SOCK_RAW); | ||||||
|  | 	return static_cast<Type>(type); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| inline poco_socket_t SocketImpl::sockfd() const | inline poco_socket_t SocketImpl::sockfd() const | ||||||
| { | { | ||||||
| 	return _sockfd; | 	return _sockfd; | ||||||
|   | |||||||
							
								
								
									
										501
									
								
								Net/include/Poco/Net/SocketProactor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										501
									
								
								Net/include/Poco/Net/SocketProactor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,501 @@ | |||||||
|  | // | ||||||
|  | // SocketProactor.h | ||||||
|  | // | ||||||
|  | // Library: Net | ||||||
|  | // Package: Sockets | ||||||
|  | // Module:  SocketProactor | ||||||
|  | // | ||||||
|  | // Definition of the SocketProactor class. | ||||||
|  | // | ||||||
|  | // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. | ||||||
|  | // and Contributors. | ||||||
|  | // | ||||||
|  | // SPDX-License-Identifier:	BSL-1.0 | ||||||
|  | // | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #ifndef Net_SocketProactor_INCLUDED | ||||||
|  | #define Net_SocketProactor_INCLUDED | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include "Poco/Net/Net.h" | ||||||
|  | #include "Poco/Net/Socket.h" | ||||||
|  | #include "Poco/Net/PollSet.h" | ||||||
|  | #include "Poco/Runnable.h" | ||||||
|  | #include "Poco/Timespan.h" | ||||||
|  | #include "Poco/Timestamp.h" | ||||||
|  | #include "Poco/AutoPtr.h" | ||||||
|  | #include "Poco/Mutex.h" | ||||||
|  | #include "Poco/Activity.h" | ||||||
|  | #include "Poco/NotificationQueue.h" | ||||||
|  | #include "Poco/ErrorHandler.h" | ||||||
|  | #include <unordered_map> | ||||||
|  | #include <atomic> | ||||||
|  | #include <functional> | ||||||
|  | #include <deque> | ||||||
|  | #include <utility> | ||||||
|  | #include <memory> | ||||||
|  | #include <iostream> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | namespace Poco { | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Thread; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | namespace Net { | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Socket; | ||||||
|  | class Worker; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Net_API SocketProactor final: public Poco::Runnable | ||||||
|  | 	/// This class implements the proactor pattern. | ||||||
|  | 	/// It may also contain a simple work executor (enabled by default), | ||||||
|  | 	/// which executes submitted workload. | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	using Buffer = std::vector<std::uint8_t>; | ||||||
|  | 	using Work = std::function<void()>; | ||||||
|  | 	using Callback = std::function<void (const std::error_code& failure, int bytesReceived)>; | ||||||
|  |  | ||||||
|  | 	static const int POLL_READ = PollSet::POLL_READ; | ||||||
|  | 	static const int POLL_WRITE = PollSet::POLL_WRITE; | ||||||
|  | 	static const int POLL_ERROR = PollSet::POLL_ERROR; | ||||||
|  |  | ||||||
|  | 	static const Timestamp::TimeDiff PERMANENT_COMPLETION_HANDLER; | ||||||
|  |  | ||||||
|  | 	explicit SocketProactor(bool worker = true); | ||||||
|  | 		/// Creates the SocketProactor. | ||||||
|  |  | ||||||
|  | 	explicit SocketProactor(const Poco::Timespan& timeout, bool worker = true); | ||||||
|  | 		/// Creates the SocketProactor, using the given timeout. | ||||||
|  |  | ||||||
|  | 	SocketProactor(const SocketProactor&) = delete; | ||||||
|  | 	SocketProactor(SocketProactor&&) = delete; | ||||||
|  | 	SocketProactor& operator=(const SocketProactor&) = delete; | ||||||
|  | 	SocketProactor& operator=(SocketProactor&&) = delete; | ||||||
|  |  | ||||||
|  | 	~SocketProactor(); | ||||||
|  | 		/// Destroys the SocketProactor. | ||||||
|  |  | ||||||
|  | 	void addWork(const Work& ch, Timestamp::TimeDiff ms = PERMANENT_COMPLETION_HANDLER); | ||||||
|  | 		/// Adds work to be executed after the next poll() completion. | ||||||
|  | 		/// Function will be called until the specified expiration, | ||||||
|  | 		/// which defaults to immediately, ie. expiration after the | ||||||
|  | 		/// first invocation. | ||||||
|  |  | ||||||
|  | 	void addWork(Work&& ch, Timestamp::TimeDiff ms = PERMANENT_COMPLETION_HANDLER, int pos = -1); | ||||||
|  | 		/// Adds work to be executed after the next poll() completion. | ||||||
|  | 		/// Function will be called until the specified expiration, | ||||||
|  | 		/// which defaults to immediately, ie. expiration after the | ||||||
|  | 		/// first invocation. | ||||||
|  |  | ||||||
|  | 	void removeWork(); | ||||||
|  | 		/// Removes all scheduled work. | ||||||
|  |  | ||||||
|  | 	int scheduledWork(); | ||||||
|  | 		/// Returns the number of scheduled functions. | ||||||
|  |  | ||||||
|  | 	int removeScheduledWork(int count = -1); | ||||||
|  | 		/// Removes the count scheduled functions | ||||||
|  | 		/// from the front of the schedule queue. | ||||||
|  | 		/// Default is removal of all scheduled functions. | ||||||
|  |  | ||||||
|  | 	int permanentWork(); | ||||||
|  | 		/// Returns the number of permanent functions. | ||||||
|  |  | ||||||
|  | 	int removePermanentWork(int count = -1); | ||||||
|  | 		/// Removes the count permanent functions | ||||||
|  | 		/// from the front of the schedule queue. | ||||||
|  | 		/// Default is removal of all functions. | ||||||
|  |  | ||||||
|  | 	int poll(int* pHandled = 0); | ||||||
|  | 		/// Polls all registered sockets and calls their respective handlers. | ||||||
|  | 		/// If pHandled is not null, after the call it contains the total number | ||||||
|  | 		/// of read/write/error socket handlers called. | ||||||
|  | 		/// Returns the number of completion handlers invoked. | ||||||
|  |  | ||||||
|  | 	int runOne(); | ||||||
|  | 		/// Runs one handler, scheduled or permanent. | ||||||
|  | 		/// If there are no available handlers, it blocks | ||||||
|  | 		/// until the first handler is encountered and executed. | ||||||
|  | 		/// Returns 1 on successful handler invocation, 0 on | ||||||
|  | 		/// exception. | ||||||
|  |  | ||||||
|  | 	void run(); | ||||||
|  | 		/// Runs the SocketProactor. The reactor will run | ||||||
|  | 		/// until stop() is called (in a separate thread). | ||||||
|  |  | ||||||
|  | 	void stop(); | ||||||
|  | 		/// Stops the SocketProactor. | ||||||
|  | 		/// | ||||||
|  | 		/// The proactor will be stopped when the next event | ||||||
|  | 		/// (including a timeout event) occurs. | ||||||
|  |  | ||||||
|  | 	void wakeUp(); | ||||||
|  | 		/// Wakes up idle reactor. | ||||||
|  |  | ||||||
|  | 	void wait(); | ||||||
|  | 		/// Blocks and waits for the scheduled I/O completion | ||||||
|  | 		/// handlers loop to end. | ||||||
|  |  | ||||||
|  | 	void setTimeout(const Poco::Timespan& timeout); | ||||||
|  | 		/// Sets the timeout.  | ||||||
|  | 		/// | ||||||
|  | 		/// If no other event occurs for the given timeout  | ||||||
|  | 		/// interval, a timeout event is sent to all event listeners. | ||||||
|  | 		/// | ||||||
|  | 		/// The default timeout is 250 milliseconds; | ||||||
|  | 		/// | ||||||
|  | 		/// The timeout is passed to the Socket::select() | ||||||
|  | 		/// method. | ||||||
|  |  | ||||||
|  | 	Poco::Timespan getTimeout() const; | ||||||
|  | 		/// Returns the timeout. | ||||||
|  |  | ||||||
|  | 	void addSocket(Socket sock, int mode); | ||||||
|  | 		/// Adds the socket to the poll set. | ||||||
|  |  | ||||||
|  | 	void updateSocket(Socket sock, int mode); | ||||||
|  | 		/// Updates the socket mode in the poll set. | ||||||
|  |  | ||||||
|  | 	void removeSocket(Socket sock); | ||||||
|  | 		/// Removes the socket from the poll set. | ||||||
|  |  | ||||||
|  | 	void addReceiveFrom(Socket sock, Buffer& buf, SocketAddress& addr, Callback&& onCompletion); | ||||||
|  | 		/// Adds the datagram socket and the completion handler to the I/O receive queue. | ||||||
|  |  | ||||||
|  | 	void addSendTo(Socket sock, const Buffer& message, const SocketAddress& addr, Callback&& onCompletion); | ||||||
|  | 		/// Adds the datagram socket and the completion handler to the I/O send queue. | ||||||
|  |  | ||||||
|  | 	void addSendTo(Socket sock, Buffer&& message, const SocketAddress&& addr, Callback&& onCompletion); | ||||||
|  | 		/// Adds the datagram socket and the completion handler to the I/O send queue. | ||||||
|  |  | ||||||
|  | 	void addSend(Socket sock, Buffer* pMessage, SocketAddress* pAddr, Callback&& onCompletion, bool own = false); | ||||||
|  | 		/// Adds the socket and the completion handler to the I/O send queue. | ||||||
|  | 		/// For stream socket, pAddr can be nullptr. | ||||||
|  | 		/// If `own` is true, message and address are deleted after the I/O completion. | ||||||
|  |  | ||||||
|  | 	void addReceive(Socket sock, Buffer& buf, Callback&& onCompletion); | ||||||
|  | 		/// Adds the stream socket and the completion handler to the I/O receive queue. | ||||||
|  |  | ||||||
|  | 	void addSend(Socket sock, const Buffer& message, Callback&& onCompletion); | ||||||
|  | 		/// Adds the stream socket and the completion handler to the I/O send queue. | ||||||
|  |  | ||||||
|  | 	void addSend(Socket sock, Buffer&& message, Callback&& onCompletion); | ||||||
|  | 		/// Adds the stream socket and the completion handler to the I/O send queue. | ||||||
|  |  | ||||||
|  | 	bool hasSocketHandlers() const; | ||||||
|  | 		/// Returns true if proactor had at least one I/O completion handler. | ||||||
|  |  | ||||||
|  | 	bool has(const Socket& sock) const; | ||||||
|  | 		/// Returns true if socket is registered with this proactor. | ||||||
|  |  | ||||||
|  | 	bool isRunning() const; | ||||||
|  | 		/// Returns true if this proactor is running | ||||||
|  |  | ||||||
|  | 	bool ioCompletionInProgress() const; | ||||||
|  | 		/// Returns true if there are not executed handlers from last IO.. | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	void onShutdown(); | ||||||
|  | 		/// Called when the SocketProactor is about to terminate. | ||||||
|  |  | ||||||
|  | 	int doWork(bool handleOne = false, bool expiredOnly = false); | ||||||
|  | 		/// Runs the scheduled work. | ||||||
|  | 		/// If handleOne is true, only the next scheduled function | ||||||
|  | 		/// is called. | ||||||
|  | 		/// If expiredOnly is true, only expired temporary functions | ||||||
|  | 		/// are called. | ||||||
|  |  | ||||||
|  | 	typedef Poco::Mutex MutexType; | ||||||
|  | 	typedef MutexType::ScopedLock ScopedLock; | ||||||
|  |  | ||||||
|  | 	static const long DEFAULT_MAX_TIMEOUT_MS = 250; | ||||||
|  |  | ||||||
|  | 	struct Handler | ||||||
|  | 		/// Handler struct holds the scheduled I/O. | ||||||
|  | 		/// At the actual I/O, Buffer and SocketAddress | ||||||
|  | 		/// are used appropriately, and deleted if owned. | ||||||
|  | 		/// Callback is passed to the IOCompletion queue. | ||||||
|  | 	{ | ||||||
|  | 		Buffer* _pBuf = nullptr; | ||||||
|  | 		SocketAddress* _pAddr = nullptr; | ||||||
|  | 		Callback _onCompletion = nullptr; | ||||||
|  | 		bool _owner = false; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	class IONotification: public Notification | ||||||
|  | 		/// IONotification object is used to transfer | ||||||
|  | 		/// the I/O completion handlers into the | ||||||
|  | 		/// completion handlers queue. | ||||||
|  | 	{ | ||||||
|  | 	public: | ||||||
|  | 		IONotification() = delete; | ||||||
|  |  | ||||||
|  | 		IONotification(Callback&& onCompletion, int bytes, const std::error_code& errorCode): | ||||||
|  | 			_onCompletion(std::move(onCompletion)), | ||||||
|  | 			_bytes(bytes), | ||||||
|  | 			_errorCode(errorCode) | ||||||
|  | 			/// Creates the IONotification. | ||||||
|  | 		{ | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		~IONotification() = default; | ||||||
|  |  | ||||||
|  | 		void call() | ||||||
|  | 			/// Calls the completion handler. | ||||||
|  | 		{ | ||||||
|  | 			_onCompletion(_errorCode, _bytes); | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 	private: | ||||||
|  | 		Callback _onCompletion; | ||||||
|  | 		int _bytes; | ||||||
|  | 		std::error_code _errorCode; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	class IOCompletion | ||||||
|  | 		/// IOCompletion utility class accompanies the | ||||||
|  | 		/// SocketProactor and serves to execute I/O | ||||||
|  | 		/// completion handlers in its own thread. | ||||||
|  | 	{ | ||||||
|  | 	public: | ||||||
|  | 		IOCompletion() = delete; | ||||||
|  |  | ||||||
|  | 		explicit IOCompletion(int maxTimeout): | ||||||
|  | 			_activity(this, &IOCompletion::run) | ||||||
|  | 			/// Creates IOCompletion. | ||||||
|  | 		{ | ||||||
|  | 			start(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		~IOCompletion() | ||||||
|  | 		{ | ||||||
|  | 			wakeUp(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void start() | ||||||
|  | 			/// Starts the I/O completion execution. | ||||||
|  | 		{ | ||||||
|  | 			_activity.start(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void stop() | ||||||
|  | 			/// Stops the I/O completion execution. | ||||||
|  | 		{ | ||||||
|  | 			_activity.stop(); | ||||||
|  | 			_nq.wakeUpAll(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void wait() | ||||||
|  | 			/// Blocks until I/O execution completely stops. | ||||||
|  | 		{ | ||||||
|  | 			_activity.wait(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void enqueue(Notification::Ptr pNotification) | ||||||
|  | 			/// Enqueues I/O completion. | ||||||
|  | 		{ | ||||||
|  | 			_nq.enqueueNotification(std::move(pNotification)); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void wakeUp() | ||||||
|  | 			/// Wakes up the I/O completion execution loop. | ||||||
|  | 		{ | ||||||
|  | 			_nq.wakeUpAll(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		int queueSize() const | ||||||
|  | 		{ | ||||||
|  | 			return _nq.size(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	private: | ||||||
|  | 		bool runOne() | ||||||
|  | 			/// Runs the next I/O completion handler in the queue. | ||||||
|  | 		{ | ||||||
|  | 			IONotification* pNf = dynamic_cast<IONotification*>(_nq.waitDequeueNotification()); | ||||||
|  | 			if (pNf) | ||||||
|  | 			{ | ||||||
|  | 				try | ||||||
|  | 				{ | ||||||
|  | 					pNf->call(); | ||||||
|  | 					pNf->release(); | ||||||
|  | 					return true; | ||||||
|  | 				} | ||||||
|  | 				catch (Exception& exc) | ||||||
|  | 				{ | ||||||
|  | 					ErrorHandler::handle(exc); | ||||||
|  | 				} | ||||||
|  | 				catch (std::exception& exc) | ||||||
|  | 				{ | ||||||
|  | 					ErrorHandler::handle(exc); | ||||||
|  | 				} | ||||||
|  | 				catch (...) | ||||||
|  | 				{ | ||||||
|  | 					ErrorHandler::handle(); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void run() | ||||||
|  | 			/// Continuously runs enqueued completion handlers. | ||||||
|  | 		{ | ||||||
|  | 			while(!_activity.isStopped()) runOne(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		Activity<IOCompletion> _activity; | ||||||
|  | 		NotificationQueue _nq; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	using IOHandlerList = std::deque<std::unique_ptr<Handler>>; | ||||||
|  | 	using IOHandlerIt = IOHandlerList::iterator; | ||||||
|  | 	using SubscriberMap = std::unordered_map<poco_socket_t, std::deque<std::unique_ptr<Handler>>>; | ||||||
|  |  | ||||||
|  | 	void sleep(bool isAtWork); | ||||||
|  | 		/// Sleep policy implementation. | ||||||
|  | 		/// If there is currently any work being done, | ||||||
|  | 		/// timeout is kept at zero (ie. no timeout), | ||||||
|  | 		/// otherwise, the timeout is incremented and | ||||||
|  | 		///  - trySleep() is called if proactor runs | ||||||
|  | 		///    in a Poco::Thread, which is necessary | ||||||
|  | 		///    for trySleep call to be interruptable | ||||||
|  | 		/// or | ||||||
|  | 		///  - sleep() is called (not interruptable) | ||||||
|  | 		/// | ||||||
|  | 		/// The value of _timeout can grow up to | ||||||
|  | 		/// _maxTimeout value. | ||||||
|  |  | ||||||
|  | 	int error(Socket& sock); | ||||||
|  | 		/// Enqueues the completion handlers and removes | ||||||
|  | 		/// them from the handlers list after the operation | ||||||
|  | 		/// successfully completes. | ||||||
|  |  | ||||||
|  | 	bool hasHandlers(SubscriberMap& handlers, int sockfd); | ||||||
|  | 	void deleteHandler(IOHandlerList& handlers, IOHandlerList::iterator& it); | ||||||
|  |  | ||||||
|  | 	template <typename T> | ||||||
|  | 	int errorImpl(Socket& sock, T& handlerMap, Poco::Mutex& mutex) | ||||||
|  | 	{ | ||||||
|  | 		Poco::Mutex::ScopedLock l(mutex); | ||||||
|  | 		auto hIt = handlerMap.find(sock.impl()->sockfd()); | ||||||
|  | 		if (hIt == handlerMap.end()) return 0; | ||||||
|  | 		unsigned err = 0; | ||||||
|  | 		sock.getOption(SOL_SOCKET, SO_ERROR, err); | ||||||
|  | 		IOHandlerList& handlers = hIt->second; | ||||||
|  | 		int handled = static_cast<int>(handlers.size()); | ||||||
|  | 		auto it = handlers.begin(); | ||||||
|  | 		auto end = handlers.end(); | ||||||
|  | 		while (it != end) | ||||||
|  | 		{ | ||||||
|  | 			enqueueIONotification(std::move((*it)->_onCompletion), 0, err); | ||||||
|  | 			deleteHandler(handlers, it); | ||||||
|  | 			// end iterator is invalidated when the last member | ||||||
|  | 			// is removed, so make sure we don't check for it | ||||||
|  | 			if (handlers.empty()) break; | ||||||
|  | 		} | ||||||
|  | 		handled -= static_cast<int>(handlers.size()); | ||||||
|  | 		if (handled) _ioCompletion.wakeUp(); | ||||||
|  | 		return handled; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	int send(Socket& sock); | ||||||
|  | 		/// Calls the appropriate output function; enqueues | ||||||
|  | 		/// the accompanying completion handler and removes | ||||||
|  | 		/// it from the handlers list after the operation | ||||||
|  | 		/// successfully completes. | ||||||
|  |  | ||||||
|  | 	int receive(Socket& sock); | ||||||
|  | 		/// Calls the appropriate input function; enqueues | ||||||
|  | 		/// the accompanying completion handler and removes | ||||||
|  | 		/// it from the handlers list after the operation | ||||||
|  | 		/// successfully completes. | ||||||
|  |  | ||||||
|  | 	void sendTo(SocketImpl& sock, IOHandlerIt& it); | ||||||
|  | 		/// Sends data to the datagram socket and enqueues the | ||||||
|  | 		/// accompanying completion handler. | ||||||
|  |  | ||||||
|  | 	void send(SocketImpl& sock, IOHandlerIt& it); | ||||||
|  | 		/// Sends data to the stream socket and enqueues the | ||||||
|  | 		/// accompanying completion handler. | ||||||
|  |  | ||||||
|  | 	void receiveFrom(SocketImpl& sock, IOHandlerIt& it, int available); | ||||||
|  | 		/// Reads data from the datagram socket and enqueues the | ||||||
|  | 		/// accompanying completion handler. | ||||||
|  |  | ||||||
|  | 	void receive(SocketImpl& sock, IOHandlerIt& it, int available); | ||||||
|  | 		/// Reads data from the stream socket and enqueues the | ||||||
|  | 		/// accompanying completion handler. | ||||||
|  |  | ||||||
|  | 	void enqueueIONotification(Callback&& onCompletion, int n, int err); | ||||||
|  | 		/// Enqueues the completion handler into the I/O | ||||||
|  | 		/// completion handler. | ||||||
|  |  | ||||||
|  | 	Worker& worker(); | ||||||
|  |  | ||||||
|  | 	std::atomic<bool> _isRunning; | ||||||
|  | 	std::atomic<bool> _isStopped; | ||||||
|  | 	std::atomic<bool> _stop; | ||||||
|  | 	long              _timeout; | ||||||
|  | 	long              _maxTimeout; | ||||||
|  | 	PollSet           _pollSet; | ||||||
|  | 	Poco::Thread*     _pThread; | ||||||
|  |  | ||||||
|  | 	SubscriberMap _readHandlers; | ||||||
|  | 	SubscriberMap _writeHandlers; | ||||||
|  | 	IOCompletion  _ioCompletion; | ||||||
|  | 	Poco::Mutex   _writeMutex; | ||||||
|  | 	Poco::Mutex   _readMutex; | ||||||
|  |  | ||||||
|  | 	std::unique_ptr<Worker> _pWorker; | ||||||
|  | 	friend class Worker; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // inlines | ||||||
|  | // | ||||||
|  |  | ||||||
|  | inline void SocketProactor::addSocket(Socket sock, int mode) | ||||||
|  | { | ||||||
|  | 	_pollSet.add(sock, mode | PollSet::POLL_ERROR); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline void SocketProactor::updateSocket(Socket sock, int mode) | ||||||
|  | { | ||||||
|  | 	_pollSet.update(sock, mode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline void SocketProactor::removeSocket(Socket sock) | ||||||
|  | { | ||||||
|  | 	_pollSet.remove(sock); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline void SocketProactor::enqueueIONotification(Callback&& onCompletion, int n, int err) | ||||||
|  | { | ||||||
|  | 	if (onCompletion) | ||||||
|  | 	{ | ||||||
|  | 		_ioCompletion.enqueue(new IONotification( | ||||||
|  | 				std::move(onCompletion), n, | ||||||
|  | 				std::error_code(err, std::generic_category()))); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline bool SocketProactor::isRunning() const | ||||||
|  | { | ||||||
|  | 	return _isRunning; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } } // namespace Poco::Net | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif // Net_SocketProactor_INCLUDED | ||||||
| @@ -209,7 +209,7 @@ protected: | |||||||
| private: | private: | ||||||
| 	typedef Poco::AutoPtr<SocketNotifier>     NotifierPtr; | 	typedef Poco::AutoPtr<SocketNotifier>     NotifierPtr; | ||||||
| 	typedef Poco::AutoPtr<SocketNotification> NotificationPtr; | 	typedef Poco::AutoPtr<SocketNotification> NotificationPtr; | ||||||
| 	typedef std::map<Socket, NotifierPtr>     EventHandlerMap; | 	typedef std::map<poco_socket_t, NotifierPtr>     EventHandlerMap; | ||||||
| 	typedef Poco::FastMutex                   MutexType; | 	typedef Poco::FastMutex                   MutexType; | ||||||
| 	typedef MutexType::ScopedLock             ScopedLock; | 	typedef MutexType::ScopedLock             ScopedLock; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -60,6 +60,10 @@ public: | |||||||
| 		/// a StreamSocketImpl, otherwise an InvalidArgumentException | 		/// a StreamSocketImpl, otherwise an InvalidArgumentException | ||||||
| 		/// will be thrown. | 		/// will be thrown. | ||||||
|  |  | ||||||
|  | 	StreamSocket(const StreamSocket& socket); | ||||||
|  | 		/// Creates the StreamSocket with the SocketImpl | ||||||
|  | 		/// from another socket. | ||||||
|  |  | ||||||
| 	virtual ~StreamSocket(); | 	virtual ~StreamSocket(); | ||||||
| 		/// Destroys the StreamSocket. | 		/// Destroys the StreamSocket. | ||||||
|  |  | ||||||
| @@ -70,6 +74,43 @@ public: | |||||||
| 		/// attaches the SocketImpl from the other socket and | 		/// attaches the SocketImpl from the other socket and | ||||||
| 		/// increments the reference count of the SocketImpl. | 		/// increments the reference count of the SocketImpl. | ||||||
|  |  | ||||||
|  | 	StreamSocket& operator = (const StreamSocket& socket); | ||||||
|  | 		/// Assignment operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl and | ||||||
|  | 		/// attaches the SocketImpl from the other socket and | ||||||
|  | 		/// increments the reference count of the SocketImpl. | ||||||
|  |  | ||||||
|  | #if POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
|  | 	StreamSocket(Socket&& socket); | ||||||
|  | 		/// Creates the StreamSocket with the SocketImpl | ||||||
|  | 		/// from another socket and zeroes the other socket's | ||||||
|  | 		/// SocketImpl.The SocketImpl must be | ||||||
|  | 		/// a StreamSocketImpl, otherwise an InvalidArgumentException | ||||||
|  | 		/// will be thrown. | ||||||
|  |  | ||||||
|  | 	StreamSocket(StreamSocket&& socket); | ||||||
|  | 		/// Creates the StreamSocket with the SocketImpl | ||||||
|  | 		/// from another socket and zeroes the other socket's | ||||||
|  | 		/// SocketImpl. | ||||||
|  |  | ||||||
|  | 	StreamSocket& operator = (Socket&& socket); | ||||||
|  | 		/// Assignment move operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl and | ||||||
|  | 		/// attaches the SocketImpl from the other socket and | ||||||
|  | 		/// zeroes the other socket's SocketImpl. | ||||||
|  |  | ||||||
|  | 	StreamSocket& operator = (StreamSocket&& socket); | ||||||
|  | 		/// Assignment move operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl and | ||||||
|  | 		/// attaches the SocketImpl from the other socket and | ||||||
|  | 		/// zeroes the other socket's SocketImpl. | ||||||
|  |  | ||||||
|  | #endif //POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
| 	void connect(const SocketAddress& address); | 	void connect(const SocketAddress& address); | ||||||
| 		/// Initializes the socket and establishes a connection to | 		/// Initializes the socket and establishes a connection to | ||||||
| 		/// the TCP server at the given address. | 		/// the TCP server at the given address. | ||||||
|   | |||||||
| @@ -42,7 +42,7 @@ typedef int UDPMsgSizeT; | |||||||
|  |  | ||||||
| template <std::size_t S = POCO_UDP_BUF_SIZE> | template <std::size_t S = POCO_UDP_BUF_SIZE> | ||||||
| class UDPHandlerImpl: public Runnable, public RefCountedObject | class UDPHandlerImpl: public Runnable, public RefCountedObject | ||||||
| 	/// UDP handler handles the data that arives to the UDP server. | 	/// UDP handler handles the data that arrives to the UDP server. | ||||||
| 	/// The class is thread-safe and runs in its own thread, so many handlers | 	/// The class is thread-safe and runs in its own thread, so many handlers | ||||||
| 	/// can be used in parallel.Handler manages and provides the storage | 	/// can be used in parallel.Handler manages and provides the storage | ||||||
| 	/// (fixed-size memory blocks of S size) to the reader, which signals back | 	/// (fixed-size memory blocks of S size) to the reader, which signals back | ||||||
|   | |||||||
| @@ -176,8 +176,11 @@ public: | |||||||
| 		/// Creates a WebSocket from another Socket, which must be a WebSocket, | 		/// Creates a WebSocket from another Socket, which must be a WebSocket, | ||||||
| 		/// otherwise a Poco::InvalidArgumentException will be thrown. | 		/// otherwise a Poco::InvalidArgumentException will be thrown. | ||||||
|  |  | ||||||
|  | 	WebSocket(const WebSocket& socket); | ||||||
|  | 		/// Creates a WebSocket from another WebSocket. | ||||||
|  |  | ||||||
| 	virtual ~WebSocket(); | 	virtual ~WebSocket(); | ||||||
| 		/// Destroys the StreamSocket. | 		/// Destroys the WebSocket. | ||||||
|  |  | ||||||
| 	WebSocket& operator = (const Socket& socket); | 	WebSocket& operator = (const Socket& socket); | ||||||
| 		/// Assignment operator. | 		/// Assignment operator. | ||||||
| @@ -185,6 +188,39 @@ public: | |||||||
| 		/// The other socket must be a WebSocket, otherwise a Poco::InvalidArgumentException | 		/// The other socket must be a WebSocket, otherwise a Poco::InvalidArgumentException | ||||||
| 		/// will be thrown. | 		/// will be thrown. | ||||||
|  |  | ||||||
|  | 	WebSocket& operator = (const WebSocket& socket); | ||||||
|  | 		/// Assignment operator. | ||||||
|  |  | ||||||
|  | #if POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
|  | 	WebSocket(Socket&& socket); | ||||||
|  | 		/// Creates the WebSocket with the SocketImpl | ||||||
|  | 		/// from another socket and zeroes the other socket's | ||||||
|  | 		/// SocketImpl.The SocketImpl must be | ||||||
|  | 		/// a WebSocketImpl, otherwise an InvalidArgumentException | ||||||
|  | 		/// will be thrown. | ||||||
|  |  | ||||||
|  | 	WebSocket(WebSocket&& socket); | ||||||
|  | 		/// Creates the WebSocket with the SocketImpl | ||||||
|  | 		/// from another socket and zeroes the other socket's | ||||||
|  | 		/// SocketImpl. | ||||||
|  |  | ||||||
|  | 	WebSocket& operator = (Socket&& socket); | ||||||
|  | 		/// Assignment move operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl and | ||||||
|  | 		/// attaches the SocketImpl from the other socket and | ||||||
|  | 		/// zeroes the other socket's SocketImpl. | ||||||
|  |  | ||||||
|  | 	WebSocket& operator = (WebSocket&& socket); | ||||||
|  | 		/// Assignment move operator. | ||||||
|  | 		/// | ||||||
|  | 		/// Releases the socket's SocketImpl and | ||||||
|  | 		/// attaches the SocketImpl from the other socket and | ||||||
|  | 		/// zeroes the other socket's SocketImpl. | ||||||
|  |  | ||||||
|  | #endif //POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
| 	void shutdown(); | 	void shutdown(); | ||||||
| 		/// Sends a Close control frame to the server end of | 		/// Sends a Close control frame to the server end of | ||||||
| 		/// the connection to initiate an orderly shutdown | 		/// the connection to initiate an orderly shutdown | ||||||
|   | |||||||
| @@ -34,15 +34,12 @@ DatagramSocket::DatagramSocket(SocketAddress::Family family): Socket(new Datagra | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| DatagramSocket::DatagramSocket(const SocketAddress& address, bool reuseAddress): Socket(new DatagramSocketImpl(address.family())) | DatagramSocket::DatagramSocket(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only): | ||||||
|  | 	Socket(new DatagramSocketImpl(address.family())) | ||||||
| { | { | ||||||
| 	bind(address, reuseAddress); | 	if (address.family() == SocketAddress::IPv6) | ||||||
| } | 		bind6(address, reuseAddress, reusePort, ipV6Only); | ||||||
|  | 	else bind(address, reuseAddress, reusePort); | ||||||
|  |  | ||||||
| DatagramSocket::DatagramSocket(const SocketAddress& address, bool reuseAddress, bool reusePort): Socket(new DatagramSocketImpl(address.family())) |  | ||||||
| { |  | ||||||
| 	bind(address, reuseAddress, reusePort); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -53,6 +50,11 @@ DatagramSocket::DatagramSocket(const Socket& socket): Socket(socket) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | DatagramSocket::DatagramSocket(const DatagramSocket& socket): Socket(socket) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| DatagramSocket::DatagramSocket(SocketImpl* pImpl): Socket(pImpl) | DatagramSocket::DatagramSocket(SocketImpl* pImpl): Socket(pImpl) | ||||||
| { | { | ||||||
| 	if (!dynamic_cast<DatagramSocketImpl*>(impl())) | 	if (!dynamic_cast<DatagramSocketImpl*>(impl())) | ||||||
| @@ -74,6 +76,44 @@ DatagramSocket& DatagramSocket::operator = (const Socket& socket) | |||||||
| 	return *this; | 	return *this; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #if POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
|  | DatagramSocket::DatagramSocket(DatagramSocket&& socket): Socket(std::move(socket)) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | DatagramSocket::DatagramSocket(Socket&& socket): Socket(std::move(socket)) | ||||||
|  | { | ||||||
|  | 	if (!dynamic_cast<DatagramSocketImpl*>(impl())) | ||||||
|  | 		throw InvalidArgumentException("Cannot assign incompatible socket"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | DatagramSocket& DatagramSocket::operator = (Socket&& socket) | ||||||
|  | { | ||||||
|  | 	if (dynamic_cast<DatagramSocketImpl*>(socket.impl())) | ||||||
|  | 		Socket::operator = (std::move(socket)); | ||||||
|  | 	else | ||||||
|  | 		throw InvalidArgumentException("Cannot assign incompatible socket"); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | DatagramSocket& DatagramSocket::operator = (DatagramSocket&& socket) | ||||||
|  | { | ||||||
|  | 	Socket::operator = (std::move(socket)); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif // POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
|  | DatagramSocket& DatagramSocket::operator = (const DatagramSocket& socket) | ||||||
|  | { | ||||||
|  | 	Socket::operator = (socket); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void DatagramSocket::connect(const SocketAddress& address) | void DatagramSocket::connect(const SocketAddress& address) | ||||||
| { | { | ||||||
| @@ -93,6 +133,12 @@ void DatagramSocket::bind(const SocketAddress& address, bool reuseAddress, bool | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void DatagramSocket::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only) | ||||||
|  | { | ||||||
|  | 	impl()->bind6(address, reuseAddress, reusePort, ipV6Only); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| int DatagramSocket::sendBytes(const void* buffer, int length, int flags) | int DatagramSocket::sendBytes(const void* buffer, int length, int flags) | ||||||
| { | { | ||||||
| 	return impl()->sendBytes(buffer, length, flags); | 	return impl()->sendBytes(buffer, length, flags); | ||||||
|   | |||||||
| @@ -66,7 +66,7 @@ int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags) | |||||||
| { | { | ||||||
| 	int maxPacketSize = _icmpPacket.maxPacketSize(); | 	int maxPacketSize = _icmpPacket.maxPacketSize(); | ||||||
| 	Poco::Buffer<unsigned char> buffer(maxPacketSize); | 	Poco::Buffer<unsigned char> buffer(maxPacketSize); | ||||||
| 	int expected = _icmpPacket.packetSize(); | 	int leftover = _icmpPacket.packetSize(); | ||||||
| 	int type = 0, code = 0; | 	int type = 0, code = 0; | ||||||
|  |  | ||||||
| 	try | 	try | ||||||
| @@ -83,8 +83,8 @@ int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags) | |||||||
| 			if (rc == 0) break; | 			if (rc == 0) break; | ||||||
| 			if (respAddr == address) | 			if (respAddr == address) | ||||||
| 			{ | 			{ | ||||||
| 				expected -= rc; | 				leftover -= rc; | ||||||
| 				if (expected <= 0) | 				if (leftover <= 0) | ||||||
| 				{ | 				{ | ||||||
| 					if (_icmpPacket.validReplyID(buffer.begin(), maxPacketSize)) break; | 					if (_icmpPacket.validReplyID(buffer.begin(), maxPacketSize)) break; | ||||||
| 					std::string err = _icmpPacket.errorDescription(buffer.begin(), maxPacketSize, type, code); | 					std::string err = _icmpPacket.errorDescription(buffer.begin(), maxPacketSize, type, code); | ||||||
| @@ -95,7 +95,7 @@ int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags) | |||||||
| 			} | 			} | ||||||
| 			else continue; | 			else continue; | ||||||
| 		} | 		} | ||||||
| 		while (expected > 0 && !_icmpPacket.validReplyID(buffer.begin(), maxPacketSize)); | 		while (leftover > 0 && !_icmpPacket.validReplyID(buffer.begin(), maxPacketSize)); | ||||||
| 	} | 	} | ||||||
| 	catch (ICMPException&) | 	catch (ICMPException&) | ||||||
| 	{ | 	{ | ||||||
| @@ -113,10 +113,11 @@ int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags) | |||||||
| 		else throw; | 		else throw; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (expected > 0) | 	if (leftover > 0) | ||||||
| 	{ | 	{ | ||||||
| 		throw ICMPException(Poco::format("No response: expected %d, received: %d", _icmpPacket.packetSize(), | 		std::string err = leftover < _icmpPacket.packetSize() ? "Incomplete" : "No"; | ||||||
| 				_icmpPacket.packetSize() - expected)); | 		throw ICMPException(Poco::format("%s response: expected %d, received: %d", err, _icmpPacket.packetSize(), | ||||||
|  | 				_icmpPacket.packetSize() - leftover)); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	struct timeval then = _icmpPacket.time(buffer.begin(), maxPacketSize); | 	struct timeval then = _icmpPacket.time(buffer.begin(), maxPacketSize); | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ | |||||||
| #include "Poco/BinaryReader.h" | #include "Poco/BinaryReader.h" | ||||||
| #include "Poco/BinaryWriter.h" | #include "Poco/BinaryWriter.h" | ||||||
| #include "Poco/String.h" | #include "Poco/String.h" | ||||||
|  | #include "Poco/Format.h" | ||||||
| #include "Poco/Types.h" | #include "Poco/Types.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -69,6 +70,11 @@ IPAddress::IPAddress(const IPAddress& addr) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | IPAddress::IPAddress(IPAddress&& addr): _pImpl(std::move(addr._pImpl)) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| IPAddress::IPAddress(Family family) | IPAddress::IPAddress(Family family) | ||||||
| { | { | ||||||
| 	if (family == IPv4) | 	if (family == IPv4) | ||||||
| @@ -99,7 +105,7 @@ IPAddress::IPAddress(const std::string& addr) | |||||||
|  |  | ||||||
| #if defined(POCO_HAVE_IPv6) | #if defined(POCO_HAVE_IPv6) | ||||||
| 	IPv6AddressImpl empty6 = IPv6AddressImpl(); | 	IPv6AddressImpl empty6 = IPv6AddressImpl(); | ||||||
| 	if (addr.empty() || trim(addr) == "::") | 	if (addr.empty() || trimIPv6(addr) == "::") | ||||||
| 	{ | 	{ | ||||||
| 		newIPv6(empty6.addr()); | 		newIPv6(empty6.addr()); | ||||||
| 		return; | 		return; | ||||||
| @@ -237,6 +243,13 @@ IPAddress& IPAddress::operator = (const IPAddress& addr) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | IPAddress& IPAddress::operator = (IPAddress&& addr) | ||||||
|  | { | ||||||
|  | 	_pImpl = std::move(addr._pImpl); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| IPAddress::Family IPAddress::family() const | IPAddress::Family IPAddress::family() const | ||||||
| { | { | ||||||
| 	return pImpl()->family(); | 	return pImpl()->family(); | ||||||
| @@ -519,6 +532,47 @@ unsigned IPAddress::prefixLength() const | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::string& IPAddress::compressV6(std::string& v6addr) | ||||||
|  | { | ||||||
|  | 	// get rid of leading zeros at the beginning | ||||||
|  | 	while (v6addr.size() && v6addr[0] == '0') v6addr.erase(v6addr.begin()); | ||||||
|  |  | ||||||
|  | 	// get rid of leading zeros in the middle | ||||||
|  | 	while (v6addr.find(":0") != std::string::npos) | ||||||
|  | 		Poco::replaceInPlace(v6addr, ":0", ":"); | ||||||
|  |  | ||||||
|  | 	// get rid of extraneous colons | ||||||
|  | 	while (v6addr.find(":::") != std::string::npos) | ||||||
|  | 		Poco::replaceInPlace(v6addr, ":::", "::"); | ||||||
|  |  | ||||||
|  | 	return v6addr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::string IPAddress::trimIPv6(const std::string v6Addr) | ||||||
|  | { | ||||||
|  | 	std::string v6addr(v6Addr); | ||||||
|  | 	std::string::size_type len = v6addr.length(); | ||||||
|  | 	int dblColOcc = 0; | ||||||
|  | 	auto pos = v6addr.find("::"); | ||||||
|  | 	while ((pos <= len-2) && (pos != std::string::npos)) | ||||||
|  | 	{ | ||||||
|  | 		++dblColOcc; | ||||||
|  | 		pos = v6addr.find("::", pos + 2); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if ((dblColOcc > 1) || | ||||||
|  | 		(std::count(v6addr.begin(), v6addr.end(), ':') > 8) || | ||||||
|  | 		(v6addr.find(":::") != std::string::npos) || | ||||||
|  | 		((len >= 2) && ((v6addr[len-1] == ':') && v6addr[len-2] != ':'))) | ||||||
|  | 	{ | ||||||
|  | 		return v6addr; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return compressV6(v6addr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| IPAddress IPAddress::parse(const std::string& addr) | IPAddress IPAddress::parse(const std::string& addr) | ||||||
| { | { | ||||||
| 	return IPAddress(addr); | 	return IPAddress(addr); | ||||||
| @@ -535,7 +589,7 @@ bool IPAddress::tryParse(const std::string& addr, IPAddress& result) | |||||||
| 	} | 	} | ||||||
| #if defined(POCO_HAVE_IPv6) | #if defined(POCO_HAVE_IPv6) | ||||||
| 	IPv6AddressImpl impl6(IPv6AddressImpl::parse(addr)); | 	IPv6AddressImpl impl6(IPv6AddressImpl::parse(addr)); | ||||||
| 	if (impl6 != IPv6AddressImpl()) | 	if (impl6 != IPv6AddressImpl() || trimIPv6(addr) == "::") | ||||||
| 	{ | 	{ | ||||||
| 		result.newIPv6(impl6.addr(), impl6.scope()); | 		result.newIPv6(impl6.addr(), impl6.scope()); | ||||||
| 		return true; | 		return true; | ||||||
| @@ -572,6 +626,54 @@ IPAddress IPAddress::broadcast() | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | IPAddress::RawIPv4 IPAddress::toV4Bytes() const | ||||||
|  | { | ||||||
|  | 	if (family() != IPv4) | ||||||
|  | 		throw Poco::InvalidAccessException(Poco::format("IPAddress::toV4Bytes(%d)", (int)family())); | ||||||
|  |  | ||||||
|  | 	RawIPv4 bytes; | ||||||
|  | 	std::memcpy(&bytes[0], addr(), IPv4Size); | ||||||
|  | 	return bytes; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | IPAddress::RawIPv6 IPAddress::toV6Bytes() const | ||||||
|  | { | ||||||
|  | 	if (family() != IPv6) | ||||||
|  | 		throw Poco::InvalidAccessException(Poco::format("IPAddress::toV6Bytes(%d)", (int)family())); | ||||||
|  |  | ||||||
|  | 	RawIPv6 bytes; | ||||||
|  | 	std::memcpy(&bytes[0], addr(), IPv6Size); | ||||||
|  | 	return bytes; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::vector<unsigned char> IPAddress::toBytes() const | ||||||
|  | { | ||||||
|  | 	std::size_t sz = 0; | ||||||
|  | 	std::vector<unsigned char> bytes; | ||||||
|  | 	const void* ptr = 0; | ||||||
|  | 	switch (family()) | ||||||
|  | 	{ | ||||||
|  | 		case IPv4: | ||||||
|  | 			sz = sizeof(in_addr); | ||||||
|  | 			ptr = addr(); | ||||||
|  | 			break; | ||||||
|  | #if defined(POCO_HAVE_IPv6) | ||||||
|  | 		case IPv6: | ||||||
|  | 			sz = sizeof(in6_addr); | ||||||
|  | 			ptr = addr(); | ||||||
|  | 			break; | ||||||
|  | #endif | ||||||
|  | 		default: | ||||||
|  | 			throw Poco::IllegalStateException(Poco::format("IPAddress::toBytes(%d)", (int)family())); | ||||||
|  | 	} | ||||||
|  | 	bytes.resize(sz); | ||||||
|  | 	std::memcpy(&bytes[0], ptr, sz); | ||||||
|  | 	return bytes; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| } } // namespace Poco::Net | } } // namespace Poco::Net | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,23 +18,13 @@ | |||||||
| #include <set> | #include <set> | ||||||
|  |  | ||||||
|  |  | ||||||
| #if defined(_WIN32) && _WIN32_WINNT >= 0x0600 |  | ||||||
| #ifndef POCO_HAVE_FD_POLL |  | ||||||
| #define POCO_HAVE_FD_POLL 1 |  | ||||||
| #endif |  | ||||||
| #elif defined(POCO_OS_FAMILY_BSD) |  | ||||||
| #ifndef POCO_HAVE_FD_POLL |  | ||||||
| #define POCO_HAVE_FD_POLL 1 |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #if defined(POCO_HAVE_FD_EPOLL) | #if defined(POCO_HAVE_FD_EPOLL) | ||||||
| #include <sys/epoll.h> | 	#include <sys/epoll.h> | ||||||
|  | 	#include <sys/eventfd.h> | ||||||
| #elif defined(POCO_HAVE_FD_POLL) | #elif defined(POCO_HAVE_FD_POLL) | ||||||
| #ifndef _WIN32 | 	#ifndef _WIN32 | ||||||
| #include <poll.h> | 		#include <poll.h> | ||||||
| #endif | 	#endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -51,12 +41,12 @@ namespace Net { | |||||||
| class PollSetImpl | class PollSetImpl | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	PollSetImpl(): | 	PollSetImpl(): _epollfd(epoll_create(1)), | ||||||
| 		_epollfd(-1), | 		_events(1024), | ||||||
| 		_events(1024) | 		_eventfd(eventfd(0, 0)) | ||||||
| 	{ | 	{ | ||||||
| 		_epollfd = epoll_create(1); | 		int err = addImpl(_eventfd, PollSet::POLL_READ, 0); | ||||||
| 		if (_epollfd < 0) | 		if ((err) || (_epollfd < 0)) | ||||||
| 		{ | 		{ | ||||||
| 			SocketImpl::error(); | 			SocketImpl::error(); | ||||||
| 		} | 		} | ||||||
| @@ -64,8 +54,8 @@ public: | |||||||
|  |  | ||||||
| 	~PollSetImpl() | 	~PollSetImpl() | ||||||
| 	{ | 	{ | ||||||
| 		if (_epollfd >= 0) | 		if (_epollfd >= 0) ::close(_epollfd); | ||||||
| 			::close(_epollfd); | 		if (_eventfd >= 0) ::close(_eventfd); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void add(const Socket& socket, int mode) | 	void add(const Socket& socket, int mode) | ||||||
| @@ -73,17 +63,8 @@ public: | |||||||
| 		Poco::FastMutex::ScopedLock lock(_mutex); | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  |  | ||||||
| 		SocketImpl* sockImpl = socket.impl(); | 		SocketImpl* sockImpl = socket.impl(); | ||||||
| 		poco_socket_t fd = sockImpl->sockfd(); |  | ||||||
| 		struct epoll_event ev; | 		int err = addImpl(sockImpl->sockfd(), mode, sockImpl); | ||||||
| 		ev.events = 0; |  | ||||||
| 		if (mode & PollSet::POLL_READ) |  | ||||||
| 			ev.events |= EPOLLIN; |  | ||||||
| 		if (mode & PollSet::POLL_WRITE) |  | ||||||
| 			ev.events |= EPOLLOUT; |  | ||||||
| 		if (mode & PollSet::POLL_ERROR) |  | ||||||
| 			ev.events |= EPOLLERR; |  | ||||||
| 		ev.data.ptr = socket.impl(); |  | ||||||
| 		int err = epoll_ctl(_epollfd, EPOLL_CTL_ADD, fd, &ev); |  | ||||||
|  |  | ||||||
| 		if (err) | 		if (err) | ||||||
| 		{ | 		{ | ||||||
| @@ -158,18 +139,13 @@ public: | |||||||
| 	PollSet::SocketModeMap poll(const Poco::Timespan& timeout) | 	PollSet::SocketModeMap poll(const Poco::Timespan& timeout) | ||||||
| 	{ | 	{ | ||||||
| 		PollSet::SocketModeMap result; | 		PollSet::SocketModeMap result; | ||||||
|  |  | ||||||
| 		{ |  | ||||||
| 			Poco::FastMutex::ScopedLock lock(_mutex); |  | ||||||
| 			if(_socketMap.empty()) return result; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		Poco::Timespan remainingTime(timeout); | 		Poco::Timespan remainingTime(timeout); | ||||||
| 		int rc; | 		int rc; | ||||||
| 		do | 		do | ||||||
| 		{ | 		{ | ||||||
| 			Poco::Timestamp start; | 			Poco::Timestamp start; | ||||||
| 			rc = epoll_wait(_epollfd, &_events[0], _events.size(), remainingTime.totalMilliseconds()); | 			rc = epoll_wait(_epollfd, &_events[0], _events.size(), remainingTime.totalMilliseconds()); | ||||||
|  | 			if (rc == 0) return result; | ||||||
| 			if (rc < 0 && SocketImpl::lastError() == POCO_EINTR) | 			if (rc < 0 && SocketImpl::lastError() == POCO_EINTR) | ||||||
| 			{ | 			{ | ||||||
| 				Poco::Timestamp end; | 				Poco::Timestamp end; | ||||||
| @@ -187,7 +163,9 @@ public: | |||||||
|  |  | ||||||
| 		for (int i = 0; i < rc; i++) | 		for (int i = 0; i < rc; i++) | ||||||
| 		{ | 		{ | ||||||
| 			std::map<void*, Socket>::iterator it = _socketMap.find(_events[i].data.ptr); | 			if (_events[i].data.ptr) // skip eventfd | ||||||
|  | 			{ | ||||||
|  | 				std::map<void *, Socket>::iterator it = _socketMap.find(_events[i].data.ptr); | ||||||
| 				if (it != _socketMap.end()) | 				if (it != _socketMap.end()) | ||||||
| 				{ | 				{ | ||||||
| 					if (_events[i].events & EPOLLIN) | 					if (_events[i].events & EPOLLIN) | ||||||
| @@ -198,15 +176,44 @@ public: | |||||||
| 						result[it->second] |= PollSet::POLL_ERROR; | 						result[it->second] |= PollSet::POLL_ERROR; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return result; | 		return result; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	void wakeUp() | ||||||
|  | 	{ | ||||||
|  | 		uint64_t val = 1; | ||||||
|  | 		int n = ::write(_eventfd, &val, sizeof(val)); | ||||||
|  | 		if (n < 0) Socket::error(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	int count() const | ||||||
|  | 	{ | ||||||
|  | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  | 		return static_cast<int>(_socketMap.size()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| private: | private: | ||||||
|  | 	int addImpl(int fd, int mode, void* ptr) | ||||||
|  | 	{ | ||||||
|  | 		struct epoll_event ev; | ||||||
|  | 		ev.events = 0; | ||||||
|  | 		if (mode & PollSet::POLL_READ) | ||||||
|  | 			ev.events |= EPOLLIN; | ||||||
|  | 		if (mode & PollSet::POLL_WRITE) | ||||||
|  | 			ev.events |= EPOLLOUT; | ||||||
|  | 		if (mode & PollSet::POLL_ERROR) | ||||||
|  | 			ev.events |= EPOLLERR; | ||||||
|  | 		ev.data.ptr = ptr; | ||||||
|  | 		return epoll_ctl(_epollfd, EPOLL_CTL_ADD, fd, &ev); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	mutable Poco::FastMutex         _mutex; | 	mutable Poco::FastMutex         _mutex; | ||||||
| 	int                             _epollfd; | 	int                             _epollfd; | ||||||
| 	std::map<void*, Socket>         _socketMap; | 	std::map<void*, Socket>         _socketMap; | ||||||
| 	std::vector<struct epoll_event> _events; | 	std::vector<struct epoll_event> _events; | ||||||
|  | 	int                             _eventfd; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -222,7 +229,6 @@ public: | |||||||
| 	void add(const Socket& socket, int mode) | 	void add(const Socket& socket, int mode) | ||||||
| 	{ | 	{ | ||||||
| 		Poco::FastMutex::ScopedLock lock(_mutex); | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  |  | ||||||
| 		poco_socket_t fd = socket.impl()->sockfd(); | 		poco_socket_t fd = socket.impl()->sockfd(); | ||||||
| 		_addMap[fd] = mode; | 		_addMap[fd] = mode; | ||||||
| 		_removeSet.erase(fd); | 		_removeSet.erase(fd); | ||||||
| @@ -232,7 +238,6 @@ public: | |||||||
| 	void remove(const Socket& socket) | 	void remove(const Socket& socket) | ||||||
| 	{ | 	{ | ||||||
| 		Poco::FastMutex::ScopedLock lock(_mutex); | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  |  | ||||||
| 		poco_socket_t fd = socket.impl()->sockfd(); | 		poco_socket_t fd = socket.impl()->sockfd(); | ||||||
| 		_removeSet.insert(fd); | 		_removeSet.insert(fd); | ||||||
| 		_addMap.erase(fd); | 		_addMap.erase(fd); | ||||||
| @@ -256,7 +261,6 @@ public: | |||||||
| 	void update(const Socket& socket, int mode) | 	void update(const Socket& socket, int mode) | ||||||
| 	{ | 	{ | ||||||
| 		Poco::FastMutex::ScopedLock lock(_mutex); | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  |  | ||||||
| 		poco_socket_t fd = socket.impl()->sockfd(); | 		poco_socket_t fd = socket.impl()->sockfd(); | ||||||
| 		for (auto it = _pollfds.begin(); it != _pollfds.end(); ++it) | 		for (auto it = _pollfds.begin(); it != _pollfds.end(); ++it) | ||||||
| 		{ | 		{ | ||||||
| @@ -264,7 +268,7 @@ public: | |||||||
| 			{ | 			{ | ||||||
| 				it->events = 0; | 				it->events = 0; | ||||||
| 				it->revents = 0; | 				it->revents = 0; | ||||||
| 				setMode(it->fd, it->events, mode); | 				setMode(it->events, mode); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -305,7 +309,7 @@ public: | |||||||
| 				pfd.fd = it->first; | 				pfd.fd = it->first; | ||||||
| 				pfd.events = 0; | 				pfd.events = 0; | ||||||
| 				pfd.revents = 0; | 				pfd.revents = 0; | ||||||
| 				setMode(pfd.fd, pfd.events, it->second); | 				setMode(pfd.events, it->second); | ||||||
| 				_pollfds.push_back(pfd); | 				_pollfds.push_back(pfd); | ||||||
| 			} | 			} | ||||||
| 			_addMap.clear(); | 			_addMap.clear(); | ||||||
| @@ -320,12 +324,6 @@ public: | |||||||
| 			Poco::Timestamp start; | 			Poco::Timestamp start; | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| 			rc = WSAPoll(&_pollfds[0], static_cast<ULONG>(_pollfds.size()), static_cast<INT>(remainingTime.totalMilliseconds())); | 			rc = WSAPoll(&_pollfds[0], static_cast<ULONG>(_pollfds.size()), static_cast<INT>(remainingTime.totalMilliseconds())); | ||||||
| 			// see https://github.com/pocoproject/poco/issues/3248 |  | ||||||
| 			if ((remainingTime > 0) && (rc > 0) && !hasSignaledFDs()) |  | ||||||
| 			{ |  | ||||||
| 				rc = -1; |  | ||||||
| 				WSASetLastError(WSAEINTR); |  | ||||||
| 			} |  | ||||||
| #else | #else | ||||||
| 			rc = ::poll(&_pollfds[0], _pollfds.size(), remainingTime.totalMilliseconds()); | 			rc = ::poll(&_pollfds[0], _pollfds.size(), remainingTime.totalMilliseconds()); | ||||||
| #endif | #endif | ||||||
| @@ -358,13 +356,9 @@ public: | |||||||
| #endif | #endif | ||||||
| 							) | 							) | ||||||
| 							result[its->second] |= PollSet::POLL_READ; | 							result[its->second] |= PollSet::POLL_READ; | ||||||
| 						if ((it->revents & POLLOUT) | 						if (it->revents & POLLOUT) | ||||||
| #ifdef _WIN32 |  | ||||||
| 							&& (_wantPOLLOUT.find(it->fd) != _wantPOLLOUT.end()) |  | ||||||
| #endif |  | ||||||
| 							) |  | ||||||
| 							result[its->second] |= PollSet::POLL_WRITE; | 							result[its->second] |= PollSet::POLL_WRITE; | ||||||
| 						if (it->revents & POLLERR) | 						if (it->revents & POLLERR || (it->revents & POLLHUP)) | ||||||
| 							result[its->second] |= PollSet::POLL_ERROR; | 							result[its->second] |= PollSet::POLL_ERROR; | ||||||
| 					} | 					} | ||||||
| 					it->revents = 0; | 					it->revents = 0; | ||||||
| @@ -375,38 +369,20 @@ public: | |||||||
| 		return result; | 		return result; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	void wakeUp() | ||||||
|  | 	{ | ||||||
|  | 		// TODO | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	int count() const | ||||||
|  | 	{ | ||||||
|  | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  | 		return static_cast<int>(_socketMap.size()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| private: | private: | ||||||
|  |  | ||||||
| #ifdef _WIN32 | 	void setMode(short& target, int mode) | ||||||
|  |  | ||||||
| 	void setMode(poco_socket_t fd, short& target, int mode) |  | ||||||
| 	{ |  | ||||||
| 		if (mode & PollSet::POLL_READ) |  | ||||||
| 			target |= POLLIN; |  | ||||||
|  |  | ||||||
| 		if (mode & PollSet::POLL_WRITE) |  | ||||||
| 			_wantPOLLOUT.insert(fd); |  | ||||||
| 		else |  | ||||||
| 			_wantPOLLOUT.erase(fd); |  | ||||||
| 		target |= POLLOUT; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	bool hasSignaledFDs() |  | ||||||
| 	{ |  | ||||||
| 		for (const auto& pollfd : _pollfds) |  | ||||||
| 		{ |  | ||||||
| 			if ((pollfd.revents | POLLOUT) && |  | ||||||
| 				(_wantPOLLOUT.find(pollfd.fd) != _wantPOLLOUT.end())) |  | ||||||
| 			{ |  | ||||||
| 				return true; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| #else |  | ||||||
|  |  | ||||||
| 	void setMode(poco_socket_t fd, short& target, int mode) |  | ||||||
| 	{ | 	{ | ||||||
| 		if (mode & PollSet::POLL_READ) | 		if (mode & PollSet::POLL_READ) | ||||||
| 			target |= POLLIN; | 			target |= POLLIN; | ||||||
| @@ -415,13 +391,8 @@ private: | |||||||
| 			target |= POLLOUT; | 			target |= POLLOUT; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	mutable Poco::FastMutex         _mutex; | 	mutable Poco::FastMutex         _mutex; | ||||||
| 	std::map<poco_socket_t, Socket> _socketMap; | 	std::map<poco_socket_t, Socket> _socketMap; | ||||||
| #ifdef _WIN32 |  | ||||||
| 	std::set<poco_socket_t>         _wantPOLLOUT; |  | ||||||
| #endif |  | ||||||
| 	std::map<poco_socket_t, int>    _addMap; | 	std::map<poco_socket_t, int>    _addMap; | ||||||
| 	std::set<poco_socket_t>         _removeSet; | 	std::set<poco_socket_t>         _removeSet; | ||||||
| 	std::vector<pollfd>             _pollfds; | 	std::vector<pollfd>             _pollfds; | ||||||
| @@ -431,6 +402,300 @@ private: | |||||||
| #else | #else | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #ifdef POCO_OS_FAMILY_WINDOWS | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Windows-specific implementation using select() | ||||||
|  | // The size of select set is determined at compile | ||||||
|  | // time (see FD_SETSIZE in SocketDefs.h). | ||||||
|  | // | ||||||
|  | // This implementation works around that limit by | ||||||
|  | // having multiple socket descriptor sets and, | ||||||
|  | // when needed, calling select() multiple times. | ||||||
|  | // To avoid multiple sets situtation, the FD_SETSIZE | ||||||
|  | // can be increased, however then Poco::Net library | ||||||
|  | // must be recompiled in order for the new setting | ||||||
|  | // to be in effect. | ||||||
|  | // | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class PollSetImpl | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	PollSetImpl() : _fdRead(1, {0, {0}}), | ||||||
|  | 		_fdWrite(1, {0, {0}}), | ||||||
|  | 		_fdExcept(1, {0, {0}}), | ||||||
|  | 		_pFDRead(std::make_unique<fd_set>()), | ||||||
|  | 		_pFDWrite(std::make_unique<fd_set>()), | ||||||
|  | 		_pFDExcept(std::make_unique<fd_set>()), | ||||||
|  | 		_nfd(0) | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void add(const Socket& socket, int mode) | ||||||
|  | 	{ | ||||||
|  | 		Poco::Net::SocketImpl* pImpl = socket.impl(); | ||||||
|  | 		poco_check_ptr(pImpl); | ||||||
|  | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  | 		_map[socket] = mode; | ||||||
|  | 		setMode(pImpl->sockfd(), mode); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void remove(const Socket& socket) | ||||||
|  | 	{ | ||||||
|  | 		Poco::Net::SocketImpl* pImpl = socket.impl(); | ||||||
|  | 		poco_check_ptr(pImpl); | ||||||
|  | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  | 		remove(pImpl->sockfd()); | ||||||
|  | 		_map.erase(socket); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool has(const Socket& socket) const | ||||||
|  | 	{ | ||||||
|  | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  | 		return _map.find(socket) != _map.end(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool empty() const | ||||||
|  | 	{ | ||||||
|  | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  | 		return _map.empty(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void update(const Socket& socket, int mode) | ||||||
|  | 	{ | ||||||
|  | 		Poco::Net::SocketImpl* pImpl = socket.impl(); | ||||||
|  | 		poco_check_ptr(pImpl); | ||||||
|  | 		SOCKET fd = pImpl->sockfd(); | ||||||
|  | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  | 		_map[socket] = mode; | ||||||
|  | 		setMode(fd, mode); | ||||||
|  | 		if (!(mode & PollSet::POLL_READ)) remove(fd, _fdRead); | ||||||
|  | 		if (!(mode & PollSet::POLL_WRITE)) remove(fd, _fdWrite); | ||||||
|  | 		if (!(mode & PollSet::POLL_ERROR)) remove(fd, _fdExcept); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void clear() | ||||||
|  | 	{ | ||||||
|  | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  | 		_map.clear(); | ||||||
|  | 		for (auto& fd : _fdRead) std::memset(&fd, 0, sizeof(fd)); | ||||||
|  | 		for (auto& fd : _fdWrite) std::memset(&fd, 0, sizeof(fd)); | ||||||
|  | 		for (auto& fd : _fdExcept) std::memset(&fd, 0, sizeof(fd)); | ||||||
|  | 		_nfd = 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	PollSet::SocketModeMap poll(const Poco::Timespan& timeout) | ||||||
|  | 	{ | ||||||
|  | 		Poco::Timestamp start; | ||||||
|  | 		poco_assert_dbg(_fdRead.size() == _fdWrite.size()); | ||||||
|  | 		poco_assert_dbg(_fdWrite.size() == _fdExcept.size()); | ||||||
|  |  | ||||||
|  | 		PollSet::SocketModeMap result; | ||||||
|  | 		if (_nfd == 0) return result; | ||||||
|  |  | ||||||
|  | 		Poco::Timespan remainingTime(timeout); | ||||||
|  | 		struct timeval tv {0, 1000}; | ||||||
|  |  | ||||||
|  | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  |  | ||||||
|  | 		auto readIt = _fdRead.begin(); | ||||||
|  | 		auto writeIt = _fdWrite.begin(); | ||||||
|  | 		auto exceptIt = _fdExcept.begin(); | ||||||
|  | 		do | ||||||
|  | 		{ | ||||||
|  | 			std::memcpy(_pFDRead.get(), &*readIt, sizeof(fd_set)); | ||||||
|  | 			std::memcpy(_pFDWrite.get(), &*writeIt, sizeof(fd_set)); | ||||||
|  | 			std::memcpy(_pFDExcept.get(), &*exceptIt, sizeof(fd_set)); | ||||||
|  |  | ||||||
|  | 			int rc; | ||||||
|  | 			do | ||||||
|  | 			{ | ||||||
|  | 				rc = ::select((int)_nfd + 1, _pFDRead.get(), _pFDWrite.get(), _pFDExcept.get(), &tv); | ||||||
|  | 			} while (rc < 0 && SocketImpl::lastError() == POCO_EINTR); | ||||||
|  | 			if (rc < 0) SocketImpl::error(); | ||||||
|  | 			else if (rc > 0) | ||||||
|  | 			{ | ||||||
|  | 				for (auto it = _map.begin(); it != _map.end(); ++it) | ||||||
|  | 				{ | ||||||
|  | 					poco_socket_t fd = it->first.impl()->sockfd(); | ||||||
|  | 					if (fd != POCO_INVALID_SOCKET) | ||||||
|  | 					{ | ||||||
|  | 						if (FD_ISSET(fd, _pFDRead.get())) | ||||||
|  | 						{ | ||||||
|  | 							result[it->first] |= PollSet::POLL_READ; | ||||||
|  | 						} | ||||||
|  | 						if (FD_ISSET(fd, _pFDWrite.get())) | ||||||
|  | 						{ | ||||||
|  | 							result[it->first] |= PollSet::POLL_WRITE; | ||||||
|  | 						} | ||||||
|  | 						if (FD_ISSET(fd, _pFDExcept.get())) | ||||||
|  | 						{ | ||||||
|  | 							result[it->first] |= PollSet::POLL_ERROR; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			Timespan elapsed = Timestamp() - start; | ||||||
|  | 			if (++readIt == _fdRead.end()) | ||||||
|  | 			{ | ||||||
|  | 				if ((rc > 0) || (elapsed.totalMilliseconds() > timeout.totalMilliseconds())) | ||||||
|  | 					break; | ||||||
|  | 				readIt = _fdRead.begin(); | ||||||
|  | 				writeIt = _fdWrite.begin(); | ||||||
|  | 				exceptIt = _fdExcept.begin(); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				++writeIt; | ||||||
|  | 				++exceptIt; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			Poco::UInt64 tOut = (((Poco::UInt64)tv.tv_sec * 1000000) + tv.tv_usec) * 2; | ||||||
|  | 			Poco::Timespan left = timeout - elapsed; | ||||||
|  | 			if (tOut > left.totalMicroseconds()) | ||||||
|  | 				tOut = left.totalMicroseconds(); | ||||||
|  |  | ||||||
|  | 			tv.tv_sec = static_cast<long>(tOut / 1000000); | ||||||
|  | 			tv.tv_usec = tOut % 1000000; | ||||||
|  | 		} while (true); | ||||||
|  |  | ||||||
|  | 		return result; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	int count() const | ||||||
|  | 	{ | ||||||
|  | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  | 		return static_cast<int>(_map.size()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void wakeUp() | ||||||
|  | 	{ | ||||||
|  | 		// TODO | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |  | ||||||
|  | 	void setMode(std::vector<fd_set>& fdSet, SOCKET fd) | ||||||
|  | 	{ | ||||||
|  | 		SOCKET* pFD = 0; | ||||||
|  | 		for (auto& fdr : fdSet) | ||||||
|  | 		{ | ||||||
|  | 			SOCKET* begin = fdr.fd_array; | ||||||
|  | 			SOCKET* end = fdr.fd_array + fdr.fd_count; | ||||||
|  | 			pFD = std::find(begin, end, fd); | ||||||
|  | 			if (end != pFD) | ||||||
|  | 			{ | ||||||
|  | 				FD_SET(fd, &fdr); | ||||||
|  | 				if (fd > _nfd) _nfd = fd; | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		// not found, insert at first free location | ||||||
|  | 		for (auto& fdr : fdSet) | ||||||
|  | 		{ | ||||||
|  | 			if (fdr.fd_count < FD_SETSIZE) | ||||||
|  | 			{ | ||||||
|  | 				fdr.fd_count++; | ||||||
|  | 				fdr.fd_array[fdr.fd_count-1] = fd; | ||||||
|  | 				if (fd > _nfd) _nfd = fd; | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		// all fd sets are full; insert another one | ||||||
|  | 		fdSet.push_back({0, {0}}); | ||||||
|  | 		fd_set& fds = fdSet.back(); | ||||||
|  | 		fds.fd_count = 1; | ||||||
|  | 		fds.fd_array[0] = fd; | ||||||
|  | 		if (fd > _nfd) _nfd = fd; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void setMode(SOCKET fd, int mode) | ||||||
|  | 	{ | ||||||
|  | 		if (mode & PollSet::POLL_READ) setMode(_fdRead, fd); | ||||||
|  | 		if (mode & PollSet::POLL_WRITE) setMode(_fdWrite, fd); | ||||||
|  | 		if (mode & PollSet::POLL_ERROR) setMode(_fdExcept, fd); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void remove(SOCKET fd, std::vector<fd_set>& fdSets) | ||||||
|  | 	{ | ||||||
|  | 		bool newNFD = false; | ||||||
|  | 		for (auto& fdSet : fdSets) | ||||||
|  | 		{ | ||||||
|  | 			if (fdSet.fd_count) | ||||||
|  | 			{ | ||||||
|  | 				newNFD = (fd == _nfd); | ||||||
|  | 				int i = 0; | ||||||
|  | 				for (; i < fdSet.fd_count; ++i) | ||||||
|  | 				{ | ||||||
|  | 					if (fdSet.fd_array[i] == fd) | ||||||
|  | 					{ | ||||||
|  | 						if (i == (fdSet.fd_count-1)) | ||||||
|  | 						{ | ||||||
|  | 							fdSet.fd_array[i] = 0; | ||||||
|  | 						} | ||||||
|  | 						else | ||||||
|  | 						{ | ||||||
|  | 							for (; i < fdSet.fd_count-1; ++i) | ||||||
|  | 							{ | ||||||
|  | 								fdSet.fd_array[i] = fdSet.fd_array[i+1]; | ||||||
|  | 								if (newNFD && fdSet.fd_array[i] > _nfd) | ||||||
|  | 									_nfd = fdSet.fd_array[i]; | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 						fdSet.fd_array[fdSet.fd_count-1] = 0; | ||||||
|  | 						fdSet.fd_count--; | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 					if (newNFD && fdSet.fd_array[i] > _nfd) | ||||||
|  | 						_nfd = fdSet.fd_array[i]; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (newNFD) | ||||||
|  | 		{ | ||||||
|  | 			findNFD(_fdRead); | ||||||
|  | 			findNFD(_fdWrite); | ||||||
|  | 			findNFD(_fdExcept); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void findNFD(std::vector<fd_set>& fdSets) | ||||||
|  | 	{ | ||||||
|  | 		for (auto& fdSet : fdSets) | ||||||
|  | 		{ | ||||||
|  | 			for (int i = 0; i < fdSet.fd_count; ++i) | ||||||
|  | 			{ | ||||||
|  | 				if (fdSet.fd_array[i] > _nfd) | ||||||
|  | 					_nfd = fdSet.fd_array[i]; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void remove(SOCKET fd) | ||||||
|  | 	{ | ||||||
|  | 		remove(fd, _fdRead); | ||||||
|  | 		remove(fd, _fdWrite); | ||||||
|  | 		remove(fd, _fdExcept); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mutable Poco::FastMutex _mutex; | ||||||
|  | 	PollSet::SocketModeMap  _map; | ||||||
|  | 	SOCKET                  _nfd; | ||||||
|  | 	std::vector<fd_set>     _fdRead; | ||||||
|  | 	std::vector<fd_set>     _fdWrite; | ||||||
|  | 	std::vector<fd_set>     _fdExcept; | ||||||
|  | 	std::unique_ptr<fd_set> _pFDRead; | ||||||
|  | 	std::unique_ptr<fd_set> _pFDWrite; | ||||||
|  | 	std::unique_ptr<fd_set> _pFDExcept; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |  | ||||||
|  |  | ||||||
| // | // | ||||||
| // Fallback implementation using select() | // Fallback implementation using select() | ||||||
| // | // | ||||||
| @@ -562,12 +827,26 @@ public: | |||||||
| 		return result; | 		return result; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	void wakeUp() | ||||||
|  | 	{ | ||||||
|  | 		// TODO | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	int count() const | ||||||
|  | 	{ | ||||||
|  | 		Poco::FastMutex::ScopedLock lock(_mutex); | ||||||
|  | 		return static_cast<int>(_map.size()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| private: | private: | ||||||
| 	mutable Poco::FastMutex _mutex; | 	mutable Poco::FastMutex _mutex; | ||||||
| 	PollSet::SocketModeMap  _map; | 	PollSet::SocketModeMap  _map; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif // POCO_OS_FAMILY_WINDOWS | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -625,4 +904,16 @@ PollSet::SocketModeMap PollSet::poll(const Poco::Timespan& timeout) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int PollSet::count() const | ||||||
|  | { | ||||||
|  | 	return _pImpl->count(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void PollSet::wakeUp() | ||||||
|  | { | ||||||
|  | 	_pImpl->wakeUp(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| } } // namespace Poco::Net | } } // namespace Poco::Net | ||||||
|   | |||||||
| @@ -50,6 +50,16 @@ RawSocket::RawSocket(const Socket& socket): Socket(socket) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | RawSocket::RawSocket(const RawSocket& socket): Socket(socket) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | RawSocket::RawSocket(RawSocket&& socket): Socket(std::move(socket)) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| RawSocket::RawSocket(SocketImpl* pImpl): Socket(pImpl) | RawSocket::RawSocket(SocketImpl* pImpl): Socket(pImpl) | ||||||
| { | { | ||||||
| 	if (!dynamic_cast<RawSocketImpl*>(impl())) | 	if (!dynamic_cast<RawSocketImpl*>(impl())) | ||||||
| @@ -72,6 +82,30 @@ RawSocket& RawSocket::operator = (const Socket& socket) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | RawSocket& RawSocket::operator = (Socket&& socket) | ||||||
|  | { | ||||||
|  | 	if (dynamic_cast<RawSocketImpl*>(socket.impl())) | ||||||
|  | 		Socket::operator = (std::move(socket)); | ||||||
|  | 	else | ||||||
|  | 		throw InvalidArgumentException("Cannot assign incompatible socket"); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | RawSocket& RawSocket::operator = (const RawSocket& socket) | ||||||
|  | { | ||||||
|  | 	Socket::operator = (socket); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | RawSocket& RawSocket::operator = (RawSocket&& socket) | ||||||
|  | { | ||||||
|  | 	Socket::operator = (std::move(socket)); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void RawSocket::connect(const SocketAddress& address) | void RawSocket::connect(const SocketAddress& address) | ||||||
| { | { | ||||||
| 	impl()->connect(address); | 	impl()->connect(address); | ||||||
|   | |||||||
| @@ -18,10 +18,12 @@ | |||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring> | #include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring> | ||||||
| #if defined(POCO_HAVE_FD_EPOLL) | #if defined(POCO_HAVE_FD_EPOLL) | ||||||
| #include <sys/epoll.h> | 	#include <sys/epoll.h> | ||||||
| #elif defined(POCO_HAVE_FD_POLL) | #elif defined(POCO_HAVE_FD_POLL) | ||||||
| #include "Poco/SharedPtr.h" | 	#include "Poco/SharedPtr.h" | ||||||
| #include <poll.h> | 	#ifndef _WIN32 | ||||||
|  | 		#include <poll.h> | ||||||
|  | 	#endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -50,6 +52,30 @@ Socket::Socket(const Socket& socket): | |||||||
| 	_pImpl->duplicate(); | 	_pImpl->duplicate(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #if POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
|  | Socket::Socket(Socket&& socket): | ||||||
|  | 	_pImpl(socket._pImpl) | ||||||
|  | { | ||||||
|  | 	poco_check_ptr (_pImpl); | ||||||
|  |  | ||||||
|  | 	socket._pImpl = nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Socket& Socket::operator = (Socket&& socket) | ||||||
|  | { | ||||||
|  | 	if (&socket != this) | ||||||
|  | 	{ | ||||||
|  | 		if (_pImpl) _pImpl->release(); | ||||||
|  | 		_pImpl = socket._pImpl; | ||||||
|  | 		socket._pImpl = nullptr; | ||||||
|  | 	} | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif // POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
|  |  | ||||||
| Socket& Socket::operator = (const Socket& socket) | Socket& Socket::operator = (const Socket& socket) | ||||||
| { | { | ||||||
| @@ -62,10 +88,9 @@ Socket& Socket::operator = (const Socket& socket) | |||||||
| 	return *this; | 	return *this; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| Socket::~Socket() | Socket::~Socket() | ||||||
| { | { | ||||||
| 	_pImpl->release(); | 	if (_pImpl) _pImpl->release(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -207,8 +232,11 @@ int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exce | |||||||
|  |  | ||||||
| #elif defined(POCO_HAVE_FD_POLL) | #elif defined(POCO_HAVE_FD_POLL) | ||||||
| 	typedef Poco::SharedPtr<pollfd, Poco::ReferenceCounter, Poco::ReleaseArrayPolicy<pollfd>> SharedPollArray; | 	typedef Poco::SharedPtr<pollfd, Poco::ReferenceCounter, Poco::ReleaseArrayPolicy<pollfd>> SharedPollArray; | ||||||
|  | #ifdef _WIN32 | ||||||
|  | 	typedef ULONG nfds_t; | ||||||
|  | #endif | ||||||
|  | 	nfds_t nfd = static_cast<nfds_t>(readList.size() + writeList.size() + exceptList.size()); | ||||||
|  |  | ||||||
| 	nfds_t nfd = readList.size() + writeList.size() + exceptList.size(); |  | ||||||
| 	if (0 == nfd) return 0; | 	if (0 == nfd) return 0; | ||||||
|  |  | ||||||
| 	SharedPollArray pPollArr = new pollfd[nfd](); | 	SharedPollArray pPollArr = new pollfd[nfd](); | ||||||
| @@ -256,7 +284,11 @@ int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exce | |||||||
| 	do | 	do | ||||||
| 	{ | 	{ | ||||||
| 		Poco::Timestamp start; | 		Poco::Timestamp start; | ||||||
|  | #ifdef _WIN32 | ||||||
|  | 		rc = WSAPoll(pPollArr, nfd, static_cast<INT>(remainingTime.totalMilliseconds())); | ||||||
|  | #else | ||||||
| 		rc = ::poll(pPollArr, nfd, remainingTime.totalMilliseconds()); | 		rc = ::poll(pPollArr, nfd, remainingTime.totalMilliseconds()); | ||||||
|  | #endif | ||||||
| 		if (rc < 0 && SocketImpl::lastError() == POCO_EINTR) | 		if (rc < 0 && SocketImpl::lastError() == POCO_EINTR) | ||||||
| 		{ | 		{ | ||||||
| 			Poco::Timestamp end; | 			Poco::Timestamp end; | ||||||
| @@ -276,17 +308,17 @@ int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exce | |||||||
| 	SocketList::iterator endE = exceptList.end(); | 	SocketList::iterator endE = exceptList.end(); | ||||||
| 	for (int idx = 0; idx < nfd; ++idx) | 	for (int idx = 0; idx < nfd; ++idx) | ||||||
| 	{ | 	{ | ||||||
| 		SocketList::iterator slIt = std::find_if(begR, endR, Socket::FDCompare(pPollArr[idx].fd)); | 		SocketList::iterator slIt = std::find_if(begR, endR, Socket::FDCompare(static_cast<int>(pPollArr[idx].fd))); | ||||||
| 		if (POLLIN & pPollArr[idx].revents && slIt != endR) readyReadList.push_back(*slIt); | 		if (POLLIN & pPollArr[idx].revents && slIt != endR) readyReadList.push_back(*slIt); | ||||||
| 		slIt = std::find_if(begW, endW, Socket::FDCompare(pPollArr[idx].fd)); | 		slIt = std::find_if(begW, endW, Socket::FDCompare(static_cast<int>(pPollArr[idx].fd))); | ||||||
| 		if (POLLOUT & pPollArr[idx].revents && slIt != endW) readyWriteList.push_back(*slIt); | 		if (POLLOUT & pPollArr[idx].revents && slIt != endW) readyWriteList.push_back(*slIt); | ||||||
| 		slIt = std::find_if(begE, endE, Socket::FDCompare(pPollArr[idx].fd)); | 		slIt = std::find_if(begE, endE, Socket::FDCompare(static_cast<int>(pPollArr[idx].fd))); | ||||||
| 		if (POLLERR & pPollArr[idx].revents && slIt != endE) readyExceptList.push_back(*slIt); | 		if (POLLERR & pPollArr[idx].revents && slIt != endE) readyExceptList.push_back(*slIt); | ||||||
| 	} | 	} | ||||||
| 	std::swap(readList, readyReadList); | 	std::swap(readList, readyReadList); | ||||||
| 	std::swap(writeList, readyWriteList); | 	std::swap(writeList, readyWriteList); | ||||||
| 	std::swap(exceptList, readyExceptList); | 	std::swap(exceptList, readyExceptList); | ||||||
| 	return readList.size() + writeList.size() + exceptList.size(); | 	return static_cast<int>(readList.size() + writeList.size() + exceptList.size()); | ||||||
|  |  | ||||||
| #else | #else | ||||||
|  |  | ||||||
| @@ -464,4 +496,16 @@ SocketBufVec Socket::makeBufVec(const std::vector<std::string>& vec) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int Socket::lastError() | ||||||
|  | { | ||||||
|  | 	return SocketImpl::lastError(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void Socket::error() | ||||||
|  | { | ||||||
|  | 	SocketImpl::error(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| } } // namespace Poco::Net | } } // namespace Poco::Net | ||||||
|   | |||||||
| @@ -150,6 +150,12 @@ SocketAddress::SocketAddress(const SocketAddress& socketAddress) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SocketAddress::SocketAddress(SocketAddress&& socketAddress): | ||||||
|  | 	_pImpl(std::move(socketAddress._pImpl)) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| SocketAddress::SocketAddress(const struct sockaddr* sockAddr, poco_socklen_t length) | SocketAddress::SocketAddress(const struct sockaddr* sockAddr, poco_socklen_t length) | ||||||
| { | { | ||||||
| 	if (length == sizeof(struct sockaddr_in) && sockAddr->sa_family == AF_INET) | 	if (length == sizeof(struct sockaddr_in) && sockAddr->sa_family == AF_INET) | ||||||
| @@ -203,6 +209,13 @@ SocketAddress& SocketAddress::operator = (const SocketAddress& socketAddress) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SocketAddress& SocketAddress::operator = (SocketAddress&& socketAddress) | ||||||
|  | { | ||||||
|  | 	_pImpl = std::move(socketAddress._pImpl); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| IPAddress SocketAddress::host() const | IPAddress SocketAddress::host() const | ||||||
| { | { | ||||||
| 	return pImpl()->host(); | 	return pImpl()->host(); | ||||||
|   | |||||||
| @@ -20,23 +20,12 @@ | |||||||
| #include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring> | #include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring> | ||||||
|  |  | ||||||
|  |  | ||||||
| #if defined(_WIN32) && _WIN32_WINNT >= 0x0600 |  | ||||||
| #ifndef POCO_HAVE_FD_POLL |  | ||||||
| #define POCO_HAVE_FD_POLL 1 |  | ||||||
| #endif |  | ||||||
| #elif defined(POCO_OS_FAMILY_BSD) |  | ||||||
| #ifndef POCO_HAVE_FD_POLL |  | ||||||
| #define POCO_HAVE_FD_POLL 1 |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #if defined(POCO_HAVE_FD_EPOLL) | #if defined(POCO_HAVE_FD_EPOLL) | ||||||
| #include <sys/epoll.h> | 	#include <sys/epoll.h> | ||||||
| #elif defined(POCO_HAVE_FD_POLL) | #elif defined(POCO_HAVE_FD_POLL) | ||||||
| #ifndef _WIN32 | 	#ifndef _WIN32 | ||||||
| #include <poll.h> | 		#include <poll.h> | ||||||
| #endif | 	#endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -219,10 +208,8 @@ void SocketImpl::bind(const SocketAddress& address, bool reuseAddress, bool reus | |||||||
| 	{ | 	{ | ||||||
| 		init(address.af()); | 		init(address.af()); | ||||||
| 	} | 	} | ||||||
| 	if (reuseAddress) | 	setReuseAddress(reuseAddress); | ||||||
| 		setReuseAddress(true); | 	setReusePort(reusePort); | ||||||
| 	if (reusePort) |  | ||||||
| 		setReusePort(true); |  | ||||||
| #if defined(POCO_VXWORKS) | #if defined(POCO_VXWORKS) | ||||||
| 	int rc = ::bind(_sockfd, (sockaddr*) address.addr(), address.length()); | 	int rc = ::bind(_sockfd, (sockaddr*) address.addr(), address.length()); | ||||||
| #else | #else | ||||||
| @@ -253,10 +240,8 @@ void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reu | |||||||
| #else | #else | ||||||
| 	if (ipV6Only) throw Poco::NotImplementedException("IPV6_V6ONLY not defined."); | 	if (ipV6Only) throw Poco::NotImplementedException("IPV6_V6ONLY not defined."); | ||||||
| #endif | #endif | ||||||
| 	if (reuseAddress) | 	setReuseAddress(reuseAddress); | ||||||
| 		setReuseAddress(true); | 	setReusePort(reusePort); | ||||||
| 	if (reusePort) |  | ||||||
| 		setReusePort(true); |  | ||||||
| 	int rc = ::bind(_sockfd, address.addr(), address.length()); | 	int rc = ::bind(_sockfd, address.addr(), address.length()); | ||||||
| 	if (rc != 0) error(address.toString()); | 	if (rc != 0) error(address.toString()); | ||||||
| #else | #else | ||||||
| @@ -614,6 +599,13 @@ int SocketImpl::available() | |||||||
| { | { | ||||||
| 	int result = 0; | 	int result = 0; | ||||||
| 	ioctl(FIONREAD, result); | 	ioctl(FIONREAD, result); | ||||||
|  | #if (POCO_OS != POCO_OS_LINUX) | ||||||
|  | 	if (type() == SOCKET_TYPE_DATAGRAM) | ||||||
|  | 	{ | ||||||
|  | 		std::vector<char> buf(result); | ||||||
|  | 		result = recvfrom(sockfd(), &buf[0], result, MSG_PEEK, NULL, NULL); | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -759,6 +751,14 @@ bool SocketImpl::poll(const Poco::Timespan& timeout, int mode) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int SocketImpl::getError() | ||||||
|  | { | ||||||
|  | 	int result; | ||||||
|  | 	getOption(SOL_SOCKET, SO_ERROR, result); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void SocketImpl::setSendBufferSize(int size) | void SocketImpl::setSendBufferSize(int size) | ||||||
| { | { | ||||||
| 	setOption(SOL_SOCKET, SO_SNDBUF, size); | 	setOption(SOL_SOCKET, SO_SNDBUF, size); | ||||||
| @@ -1027,14 +1027,25 @@ void SocketImpl::setReuseAddress(bool flag) | |||||||
| { | { | ||||||
| 	int value = flag ? 1 : 0; | 	int value = flag ? 1 : 0; | ||||||
| 	setOption(SOL_SOCKET, SO_REUSEADDR, value); | 	setOption(SOL_SOCKET, SO_REUSEADDR, value); | ||||||
|  | #ifdef POCO_OS_FAMILY_WINDOWS | ||||||
|  | 	value = flag ? 0 : 1; | ||||||
|  | 	setOption(SOL_SOCKET, SO_EXCLUSIVEADDRUSE, value); | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool SocketImpl::getReuseAddress() | bool SocketImpl::getReuseAddress() | ||||||
| { | { | ||||||
|  | 	bool ret = false; | ||||||
| 	int value(0); | 	int value(0); | ||||||
| 	getOption(SOL_SOCKET, SO_REUSEADDR, value); | 	getOption(SOL_SOCKET, SO_REUSEADDR, value); | ||||||
| 	return value != 0; | 	ret = (value != 0); | ||||||
|  | #ifdef POCO_OS_FAMILY_WINDOWS | ||||||
|  | 	value = 0; | ||||||
|  | 	getOption(SOL_SOCKET, SO_EXCLUSIVEADDRUSE, value); | ||||||
|  | 	ret = ret && (value == 0); | ||||||
|  | #endif | ||||||
|  | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										808
									
								
								Net/src/SocketProactor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										808
									
								
								Net/src/SocketProactor.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,808 @@ | |||||||
|  | // | ||||||
|  | // SocketProactor.cpp | ||||||
|  | // | ||||||
|  | // Library: Net | ||||||
|  | // Package: Sockets | ||||||
|  | // Module:  SocketProactor | ||||||
|  | // | ||||||
|  | // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. | ||||||
|  | // and Contributors. | ||||||
|  | // | ||||||
|  | // SPDX-License-Identifier:	BSL-1.0 | ||||||
|  | // | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include "Poco/Net/SocketProactor.h" | ||||||
|  | #include "Poco/Net/DatagramSocket.h" | ||||||
|  | #include "Poco/Net/DatagramSocketImpl.h" | ||||||
|  | #include "Poco/Thread.h" | ||||||
|  | #include "Poco/Exception.h" | ||||||
|  | #ifdef POCO_OS_FAMILY_WINDOWS | ||||||
|  | #ifdef max | ||||||
|  | #undef max | ||||||
|  | #endif // max | ||||||
|  | #endif // POCO_OS_FAMILY_WINDOWS | ||||||
|  | #include <limits> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | using Poco::Exception; | ||||||
|  | using Poco::ErrorHandler; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | namespace Poco { | ||||||
|  | namespace Net { | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Worker | ||||||
|  | // | ||||||
|  |  | ||||||
|  | class Worker | ||||||
|  | 	/// Worker is a utility class that executes work (functions). | ||||||
|  | 	/// Workload can be permanent (executed on every doWork() call), | ||||||
|  | 	/// or "one-shot" (scheduled for a single execution at a point | ||||||
|  | 	/// in the future). | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	using MutexType = SocketProactor::MutexType; | ||||||
|  | 	using ScopedLock = SocketProactor::ScopedLock; | ||||||
|  | 	using Work = SocketProactor::Work; | ||||||
|  | 	using WorkEntry = std::pair<Work, Poco::Timestamp>; | ||||||
|  | 	using WorkList = std::deque<WorkEntry>; | ||||||
|  |  | ||||||
|  | 	void addWork(const Work& ch, Timestamp::TimeDiff ms = SocketProactor::PERMANENT_COMPLETION_HANDLER) | ||||||
|  | 	{ | ||||||
|  | 		addWork(Work(ch), ms); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void addWork(Work&& ch, Timestamp::TimeDiff ms, int pos = -1) | ||||||
|  | 	{ | ||||||
|  | 		auto pch = SocketProactor::PERMANENT_COMPLETION_HANDLER; | ||||||
|  | 		Poco::Timestamp expires = (ms != pch) ? Timestamp() + (ms * 1000) : Timestamp(pch); | ||||||
|  | 		if (pos == -1 || (pos + 1) > _funcList.size()) | ||||||
|  | 		{ | ||||||
|  | 			ScopedLock lock(_mutex); | ||||||
|  | 			_funcList.push_back({std::move(ch), expires}); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			if (pos < 0) | ||||||
|  | 				throw Poco::InvalidArgumentException("SocketProactor::addWork()"); | ||||||
|  | 			ScopedLock lock(_mutex); | ||||||
|  | 			_funcList.insert(_funcList.begin() + pos, {std::move(ch), expires}); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void removeWork() | ||||||
|  | 	{ | ||||||
|  | 		ScopedLock lock(_mutex); | ||||||
|  | 		_funcList.clear(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	int scheduledWork() | ||||||
|  | 	{ | ||||||
|  | 		int cnt = 0; | ||||||
|  | 		ScopedLock lock(_mutex); | ||||||
|  | 		WorkList::iterator it = _funcList.begin(); | ||||||
|  | 		for (; it != _funcList.end(); ++it) | ||||||
|  | 		{ | ||||||
|  | 			if (!isPermanent(it->second)) ++cnt; | ||||||
|  | 		} | ||||||
|  | 		return cnt; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	int removeScheduledWork(int count) | ||||||
|  | 	{ | ||||||
|  | 		auto isScheduled = [](const Timestamp &ts) | ||||||
|  | 		{ return !isPermanent(ts); }; | ||||||
|  | 		return removeWork(isScheduled, count); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	int permanentWork() | ||||||
|  | 	{ | ||||||
|  | 		int cnt = 0; | ||||||
|  | 		ScopedLock lock(_mutex); | ||||||
|  | 		WorkList::iterator it = _funcList.begin(); | ||||||
|  | 		for (; it != _funcList.end(); ++it) | ||||||
|  | 		{ | ||||||
|  | 			if (isPermanent(it->second)) | ||||||
|  | 				++cnt; | ||||||
|  | 		} | ||||||
|  | 		return cnt; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	int removePermanentWork(int count) | ||||||
|  | 	{ | ||||||
|  | 		auto perm = [](const Timestamp &ts) | ||||||
|  | 		{ return isPermanent(ts); }; | ||||||
|  | 		return removeWork(perm, count); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static bool isPermanent(const Timestamp &entry) | ||||||
|  | 	{ | ||||||
|  | 		return entry == Timestamp(SocketProactor::PERMANENT_COMPLETION_HANDLER); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	int doWork(bool handleOne, bool expiredOnly) | ||||||
|  | 	{ | ||||||
|  | 		std::unique_ptr<Work> pCH; | ||||||
|  | 		int handled = 0; | ||||||
|  | 		{ | ||||||
|  | 			ScopedLock lock(_mutex); | ||||||
|  | 			WorkList::iterator it = _funcList.begin(); | ||||||
|  | 			try | ||||||
|  | 			{ | ||||||
|  | 				while (it != _funcList.end()) | ||||||
|  | 				{ | ||||||
|  | 					std::size_t prevSize = 0; | ||||||
|  | 					bool alwaysRun = isPermanent(it->second) && !expiredOnly; | ||||||
|  | 					bool isExpired = !alwaysRun && (Timestamp() >= it->second); | ||||||
|  | 					if (isExpired) | ||||||
|  | 					{ | ||||||
|  | 						pCH.reset(new Work(std::move(it->first))); | ||||||
|  | 						it = _funcList.erase(it); | ||||||
|  | 					} | ||||||
|  | 					else if (alwaysRun) | ||||||
|  | 					{ | ||||||
|  | 						pCH.reset(new Work(it->first)); | ||||||
|  | 						++it; | ||||||
|  | 					} | ||||||
|  | 					else ++it; | ||||||
|  | 					prevSize = _funcList.size(); | ||||||
|  |  | ||||||
|  | 					if (pCH) | ||||||
|  | 					{ | ||||||
|  | 						(*pCH)(); | ||||||
|  | 						pCH.reset(); | ||||||
|  | 						++handled; | ||||||
|  | 						if (handleOne) break; | ||||||
|  | 					} | ||||||
|  | 					// handler call may add or remove handlers; | ||||||
|  | 					// if so, we must start from the beginning | ||||||
|  | 					if (prevSize != _funcList.size()) | ||||||
|  | 						it = _funcList.begin(); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			catch (Exception& exc) | ||||||
|  | 			{ | ||||||
|  | 				ErrorHandler::handle(exc); | ||||||
|  | 			} | ||||||
|  | 			catch (std::exception& exc) | ||||||
|  | 			{ | ||||||
|  | 				ErrorHandler::handle(exc); | ||||||
|  | 			} | ||||||
|  | 			catch (...) | ||||||
|  | 			{ | ||||||
|  | 				ErrorHandler::handle(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return handled; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	int runOne() | ||||||
|  | 	{ | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			while (0 == doWork(true, false)); | ||||||
|  | 			return 1; | ||||||
|  | 		} | ||||||
|  | 		catch(...) {} | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	template <typename F> | ||||||
|  | 	int removeWork(F isType, int count) | ||||||
|  | 		/// Removes `count` functions of the specified type; | ||||||
|  | 		/// if count is -1, removes all the functions of the | ||||||
|  | 		/// specified type. | ||||||
|  | 	{ | ||||||
|  | 		int removed = 0; | ||||||
|  | 		ScopedLock lock(_mutex); | ||||||
|  | 		int left = count > -1 ? count : static_cast<int>(_funcList.size()); | ||||||
|  | 		WorkList::iterator it = _funcList.begin(); | ||||||
|  | 		while (left && it != _funcList.end()) | ||||||
|  | 		{ | ||||||
|  | 			if (isType(it->second)) | ||||||
|  | 			{ | ||||||
|  | 				++removed; | ||||||
|  | 				it = _funcList.erase((it)); | ||||||
|  | 				--left; | ||||||
|  | 			} | ||||||
|  | 			else ++it; | ||||||
|  | 		} | ||||||
|  | 		return removed; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	WorkList  _funcList; | ||||||
|  | 	MutexType _mutex; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // SocketProactor | ||||||
|  | // | ||||||
|  |  | ||||||
|  | const Timestamp::TimeDiff SocketProactor::PERMANENT_COMPLETION_HANDLER = | ||||||
|  | 	std::numeric_limits<Timestamp::TimeDiff>::max(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SocketProactor::SocketProactor(bool worker): | ||||||
|  | 	_isRunning(false), | ||||||
|  | 	_isStopped(false), | ||||||
|  | 	_stop(false), | ||||||
|  | 	_timeout(0), | ||||||
|  | 	_maxTimeout(DEFAULT_MAX_TIMEOUT_MS), | ||||||
|  | 	_pThread(nullptr), | ||||||
|  | 	_ioCompletion(_maxTimeout), | ||||||
|  | 	_pWorker(worker ? new Worker : nullptr) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SocketProactor::SocketProactor(const Poco::Timespan& timeout, bool worker): | ||||||
|  | 	_isRunning(false), | ||||||
|  | 	_isStopped(false), | ||||||
|  | 	_stop(false), | ||||||
|  | 	_timeout(0), | ||||||
|  | 	_maxTimeout(static_cast<long>(timeout.totalMilliseconds())), | ||||||
|  | 	_pThread(nullptr), | ||||||
|  | 	_ioCompletion(_maxTimeout), | ||||||
|  | 	_pWorker(worker ? new Worker : nullptr) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SocketProactor::~SocketProactor() | ||||||
|  | { | ||||||
|  | 	_ioCompletion.stop(); | ||||||
|  | 	wait(); | ||||||
|  | 	for (auto& pS : _writeHandlers) | ||||||
|  | 	{ | ||||||
|  | 		for (auto& pH : pS.second) | ||||||
|  | 		{ | ||||||
|  | 			if (pH->_pBuf && pH->_owner) | ||||||
|  | 				delete pH->_pBuf; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::wait() | ||||||
|  | { | ||||||
|  | 	_ioCompletion.wakeUp(); | ||||||
|  | 	_ioCompletion.wait(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool SocketProactor::hasHandlers(SubscriberMap& handlers, int sockfd) | ||||||
|  | { | ||||||
|  | 	Poco::Mutex::ScopedLock l(_writeMutex); | ||||||
|  | 	if (handlers.end() == handlers.find(sockfd)) | ||||||
|  | 		return false; | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int SocketProactor::poll(int* pHandled) | ||||||
|  | { | ||||||
|  | 	int handled = 0; | ||||||
|  | 	int worked = 0; | ||||||
|  | 	PollSet::SocketModeMap sm = _pollSet.poll(_timeout); | ||||||
|  | 	if (sm.size() > 0) | ||||||
|  | 	{ | ||||||
|  | 		auto it = sm.begin(); | ||||||
|  | 		auto end = sm.end(); | ||||||
|  | 		for (; it != end; ++it) | ||||||
|  | 		{ | ||||||
|  | 			if (it->second & PollSet::POLL_READ) | ||||||
|  | 			{ | ||||||
|  | 				Socket sock = it->first; | ||||||
|  | 				if (hasHandlers(_readHandlers, static_cast<int>(sock.impl()->sockfd()))) | ||||||
|  | 					handled += receive(sock); | ||||||
|  | 			} | ||||||
|  | 			if (it->second & PollSet::POLL_WRITE) | ||||||
|  | 			{ | ||||||
|  | 				Socket sock = it->first; | ||||||
|  | 				if (hasHandlers(_writeHandlers, static_cast<int>(sock.impl()->sockfd()))) | ||||||
|  | 					handled += send(sock); | ||||||
|  | 			} | ||||||
|  | 			if (it->second & PollSet::POLL_ERROR) | ||||||
|  | 			{ | ||||||
|  | 				Socket sock = it->first; | ||||||
|  | 				handled += error(sock); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (_pWorker) | ||||||
|  | 	{ | ||||||
|  | 		if (hasSocketHandlers() && handled) worked = doWork(); | ||||||
|  | 		else worked = doWork(false, true); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (pHandled) *pHandled = handled; | ||||||
|  | 	return worked; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::addReceiveFrom(Socket sock, Buffer& buf, Poco::Net::SocketAddress& addr, Callback&& onCompletion) | ||||||
|  | { | ||||||
|  | 	if (!sock.isDatagram()) | ||||||
|  | 		throw Poco::InvalidArgumentException("SocketProactor::addSend(): UDP socket required"); | ||||||
|  | 	std::unique_ptr<Handler> pHandler(new Handler); | ||||||
|  | 	pHandler->_pAddr = std::addressof(addr); | ||||||
|  | 	pHandler->_pBuf = std::addressof(buf); | ||||||
|  | 	pHandler->_onCompletion = std::move(onCompletion); | ||||||
|  |  | ||||||
|  | 	Poco::Mutex::ScopedLock l(_readMutex); | ||||||
|  | 	_readHandlers[sock.impl()->sockfd()].push_back(std::move(pHandler)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::addSendTo(Socket sock, const Buffer& message, const SocketAddress& addr, Callback&& onCompletion) | ||||||
|  | { | ||||||
|  | 	if (!sock.isDatagram()) | ||||||
|  | 		throw Poco::InvalidArgumentException("SocketProactor::addSend(): UDP socket required"); | ||||||
|  | 	Buffer* pMessage = nullptr; | ||||||
|  | 	SocketAddress* pAddr = nullptr; | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		pMessage = new Buffer(message); | ||||||
|  | 		pAddr = new SocketAddress(addr); | ||||||
|  | 	} | ||||||
|  | 	catch(...) | ||||||
|  | 	{ | ||||||
|  | 		delete pMessage; | ||||||
|  | 		delete pAddr; | ||||||
|  | 		throw; | ||||||
|  | 	} | ||||||
|  | 	addSend(sock, pMessage, pAddr, std::move(onCompletion), true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::addSendTo(Socket sock, Buffer&& message, const SocketAddress&& addr, Callback&& onCompletion) | ||||||
|  | { | ||||||
|  | 	if (!sock.isDatagram()) | ||||||
|  | 		throw Poco::InvalidArgumentException("SocketProactor::addSend(): UDP socket required"); | ||||||
|  | 	Buffer* pMessage = nullptr; | ||||||
|  | 	SocketAddress* pAddr = nullptr; | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		pMessage = new Buffer(std::move(message)); | ||||||
|  | 		pAddr = new SocketAddress(std::move(addr)); | ||||||
|  | 	} | ||||||
|  | 	catch(...) | ||||||
|  | 	{ | ||||||
|  | 		delete pMessage; | ||||||
|  | 		delete pAddr; | ||||||
|  | 		throw; | ||||||
|  | 	} | ||||||
|  | 	addSend(sock, pMessage, pAddr, std::move(onCompletion), true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::addReceive(Socket sock, Buffer& buf, Callback&& onCompletion) | ||||||
|  | { | ||||||
|  | 	if (!sock.isStream()) | ||||||
|  | 		throw Poco::InvalidArgumentException("SocketProactor::addSend(): TCP socket required"); | ||||||
|  | 	std::unique_ptr<Handler> pHandler(new Handler); | ||||||
|  | 	pHandler->_pAddr = nullptr; | ||||||
|  | 	pHandler->_pBuf = std::addressof(buf); | ||||||
|  | 	pHandler->_onCompletion = std::move(onCompletion); | ||||||
|  |  | ||||||
|  | 	Poco::Mutex::ScopedLock l(_readMutex); | ||||||
|  | 	_readHandlers[sock.impl()->sockfd()].push_back(std::move(pHandler)); | ||||||
|  | 	if (!has(sock)) addSocket(sock, PollSet::POLL_READ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::addSend(Socket sock, const Buffer& message, Callback&& onCompletion) | ||||||
|  | { | ||||||
|  | 	if (!sock.isStream()) | ||||||
|  | 		throw Poco::InvalidArgumentException("SocketProactor::addSend(): TCP socket required"); | ||||||
|  | 	Buffer* pMessage = nullptr; | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		pMessage = new Buffer(message); | ||||||
|  | 	} | ||||||
|  | 	catch(...) | ||||||
|  | 	{ | ||||||
|  | 		delete pMessage; | ||||||
|  | 		throw; | ||||||
|  | 	} | ||||||
|  | 	addSend(sock, pMessage, nullptr, std::move(onCompletion), true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::addSend(Socket sock, Buffer&& message, Callback&& onCompletion) | ||||||
|  | { | ||||||
|  | 	if (!sock.isStream()) | ||||||
|  | 		throw Poco::InvalidArgumentException("SocketProactor::addSend(): TCP socket required"); | ||||||
|  | 	Buffer* pMessage = nullptr; | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		pMessage = new Buffer(std::move(message)); | ||||||
|  | 	} | ||||||
|  | 	catch(...) | ||||||
|  | 	{ | ||||||
|  | 		delete pMessage; | ||||||
|  | 		throw; | ||||||
|  | 	} | ||||||
|  | 	addSend(sock, pMessage, nullptr, std::move(onCompletion), true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::addSend(Socket sock, Buffer* pMessage, SocketAddress* pAddr, Callback&& onCompletion, bool own) | ||||||
|  | { | ||||||
|  | 	std::unique_ptr<Handler> pHandler(new Handler); | ||||||
|  | 	pHandler->_pAddr = pAddr; | ||||||
|  | 	pHandler->_pBuf = pMessage; | ||||||
|  | 	pHandler->_onCompletion = std::move(onCompletion); | ||||||
|  | 	pHandler->_owner = own; | ||||||
|  |  | ||||||
|  | 	Poco::Mutex::ScopedLock l(_writeMutex); | ||||||
|  | 	_writeHandlers[sock.impl()->sockfd()].push_back(std::move(pHandler)); | ||||||
|  | 	if (!has(sock)) addSocket(sock, PollSet::POLL_WRITE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int SocketProactor::error(Socket& sock) | ||||||
|  | { | ||||||
|  | 	int cnt = errorImpl(sock, _readHandlers, _readMutex); | ||||||
|  | 	cnt += errorImpl(sock, _writeHandlers, _writeMutex); | ||||||
|  | 	return cnt; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int SocketProactor::send(Socket& sock) | ||||||
|  | { | ||||||
|  | 	Poco::Mutex::ScopedLock l(_writeMutex); | ||||||
|  | 	auto hIt = _writeHandlers.find(sock.impl()->sockfd()); | ||||||
|  | 	if (hIt == _writeHandlers.end()) return 0; | ||||||
|  | 	IOHandlerList& handlers = hIt->second; | ||||||
|  | 	int handled = static_cast<int>(handlers.size()); | ||||||
|  | 	auto it = handlers.begin(); | ||||||
|  | 	auto end = handlers.end(); | ||||||
|  | 	while (it != end) | ||||||
|  | 	{ | ||||||
|  | 		if (sock.isDatagram()) | ||||||
|  | 			sendTo(*sock.impl(), it); | ||||||
|  | 		else if (sock.isStream()) | ||||||
|  | 			send(*sock.impl(), it); | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			deleteHandler(handlers, it); | ||||||
|  | 			throw Poco::InvalidArgumentException("Unknown socket type."); | ||||||
|  | 		} | ||||||
|  | 		deleteHandler(handlers, it); | ||||||
|  |  | ||||||
|  | 		// end iterator is invalidated when the last member | ||||||
|  | 		// is removed, so make sure we don't check for it | ||||||
|  | 		if (handlers.empty()) break; | ||||||
|  | 	} | ||||||
|  | 	handled -= static_cast<int>(handlers.size()); | ||||||
|  | 	if (handled) _ioCompletion.wakeUp(); | ||||||
|  | 	return handled; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::sendTo(SocketImpl& sock, IOHandlerIt& it) | ||||||
|  | { | ||||||
|  | 	Buffer* pBuf = (*it)->_pBuf; | ||||||
|  | 	if (pBuf && pBuf->size()) | ||||||
|  | 	{ | ||||||
|  | 		SocketAddress *pAddr = (*it)->_pAddr; | ||||||
|  | 		int n = 0, err = 0; | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			n = sock.sendTo(&(*pBuf)[0], static_cast<int>(pBuf->size()), *pAddr); | ||||||
|  | 		} | ||||||
|  | 		catch(std::exception&) | ||||||
|  | 		{ | ||||||
|  | 			err = Socket::lastError(); | ||||||
|  | 		} | ||||||
|  | 		enqueueIONotification(std::move((*it)->_onCompletion), n, err); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		if (!pBuf) | ||||||
|  | 			throw Poco::NullPointerException("SocketProactor::sendTo(): null buffer"); | ||||||
|  | 		else if (pBuf->empty()) | ||||||
|  | 			throw Poco::InvalidArgumentException("SocketProactor::sendTo(): empty buffer"); | ||||||
|  | 		else // we shouldn't be here | ||||||
|  | 			throw Poco::InvalidAccessException("SocketProactor::sendTo(): unexpected error"); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::send(SocketImpl& sock, IOHandlerIt& it) | ||||||
|  | { | ||||||
|  | 	Buffer* pBuf = (*it)->_pBuf; | ||||||
|  | 	if (pBuf && pBuf->size()) | ||||||
|  | 	{ | ||||||
|  | 		int n = 0, err = 0; | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			n = sock.sendBytes(&(*pBuf)[0], static_cast<int>(pBuf->size())); | ||||||
|  | 		} | ||||||
|  | 		catch(std::exception&) | ||||||
|  | 		{ | ||||||
|  | 			err = Socket::lastError(); | ||||||
|  | 		} | ||||||
|  | 		enqueueIONotification(std::move((*it)->_onCompletion), n, err); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		if (!pBuf) | ||||||
|  | 			throw Poco::NullPointerException("SocketProactor::sendTo(): null buffer"); | ||||||
|  | 		else if (pBuf->empty()) | ||||||
|  | 			throw Poco::InvalidArgumentException("SocketProactor::sendTo(): empty buffer"); | ||||||
|  | 		else // we shouldn't be here | ||||||
|  | 			throw Poco::InvalidAccessException("SocketProactor::sendTo(): unexpected error"); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int SocketProactor::receive(Socket& sock) | ||||||
|  | { | ||||||
|  | 	Poco::Mutex::ScopedLock l(_readMutex); | ||||||
|  | 	auto hIt = _readHandlers.find(sock.impl()->sockfd()); | ||||||
|  | 	if (hIt == _readHandlers.end()) return 0; | ||||||
|  | 	IOHandlerList& handlers = hIt->second; | ||||||
|  | 	int handled = static_cast<int>(handlers.size()); | ||||||
|  | 	int avail = 0; | ||||||
|  | 	auto it = handlers.begin(); | ||||||
|  | 	auto end = handlers.end(); | ||||||
|  | 	for (; it != end;) | ||||||
|  | 	{ | ||||||
|  | 		if ((avail = sock.available())) | ||||||
|  | 		{ | ||||||
|  | 			if (sock.isDatagram()) | ||||||
|  | 				receiveFrom(*sock.impl(), it, avail); | ||||||
|  | 			else if (sock.isStream()) | ||||||
|  | 				receive(*sock.impl(), it, avail); | ||||||
|  | 			else | ||||||
|  | 				throw Poco::InvalidArgumentException("Unknown socket type."); | ||||||
|  |  | ||||||
|  | 			++it; | ||||||
|  | 			handlers.pop_front(); | ||||||
|  | 			// end iterator is invalidated when the last member | ||||||
|  | 			// is removed, so make sure we don't check for it | ||||||
|  | 			if (handlers.size() == 0) break; | ||||||
|  | 		} | ||||||
|  | 		else break; | ||||||
|  | 	} | ||||||
|  | 	handled -= static_cast<int>(handlers.size()); | ||||||
|  | 	if (handled) _ioCompletion.wakeUp(); | ||||||
|  | 	return handled; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::receiveFrom(SocketImpl& sock, IOHandlerIt& it, int available) | ||||||
|  | { | ||||||
|  | 	Buffer *pBuf = (*it)->_pBuf; | ||||||
|  | 	SocketAddress *pAddr = (*it)->_pAddr; | ||||||
|  | 	SocketAddress addr = *pAddr; | ||||||
|  | 	poco_check_ptr(pBuf); | ||||||
|  | 	if (pBuf->size() < available) pBuf->resize(available); | ||||||
|  | 	int n = 0, err = 0; | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		n = sock.receiveFrom(&(*pBuf)[0], available, *pAddr); | ||||||
|  | 	} | ||||||
|  | 	catch(std::exception&) | ||||||
|  | 	{ | ||||||
|  | 		err = Socket::lastError(); | ||||||
|  | 	} | ||||||
|  | 	enqueueIONotification(std::move((*it)->_onCompletion), n, err); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::receive(SocketImpl& sock, IOHandlerIt& it, int available) | ||||||
|  | { | ||||||
|  | 	Buffer *pBuf = (*it)->_pBuf; | ||||||
|  | 	poco_check_ptr(pBuf); | ||||||
|  | 	if (pBuf->size() < available) pBuf->resize(available); | ||||||
|  | 	int n = 0, err = 0; | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		n = sock.receiveBytes(&(*pBuf)[0], available); | ||||||
|  | 	} | ||||||
|  | 	catch(std::exception&) | ||||||
|  | 	{ | ||||||
|  | 		err = Socket::lastError(); | ||||||
|  | 	} | ||||||
|  | 	enqueueIONotification(std::move((*it)->_onCompletion), n, err); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int SocketProactor::doWork(bool handleOne, bool expiredOnly) | ||||||
|  | { | ||||||
|  | 	return worker().doWork(handleOne, expiredOnly); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int SocketProactor::runOne() | ||||||
|  | { | ||||||
|  | 	return worker().runOne(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::sleep(bool isAtWork) | ||||||
|  | { | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		if (isAtWork) | ||||||
|  | 		{ | ||||||
|  | 			_timeout = 0; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			if (_timeout < _maxTimeout) ++_timeout; | ||||||
|  | 		} | ||||||
|  | 		if (_pThread) _pThread->trySleep(_timeout); | ||||||
|  | 		else Thread::sleep(_timeout); | ||||||
|  | 	} | ||||||
|  | 	catch (Exception& exc) | ||||||
|  | 	{ | ||||||
|  | 		ErrorHandler::handle(exc); | ||||||
|  | 	} | ||||||
|  | 	catch (std::exception& exc) | ||||||
|  | 	{ | ||||||
|  | 		ErrorHandler::handle(exc); | ||||||
|  | 	} | ||||||
|  | 	catch (...) | ||||||
|  | 	{ | ||||||
|  | 		ErrorHandler::handle(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::run() | ||||||
|  | { | ||||||
|  | 	_pThread = Thread::current(); | ||||||
|  | 	_ioCompletion.start(); | ||||||
|  | 	int handled = 0; | ||||||
|  | 	if (!_isStopped) _stop = false; | ||||||
|  | 	_isStopped = false; | ||||||
|  | 	while (!_stop) | ||||||
|  | 	{ | ||||||
|  | 		this->sleep(poll(&handled) || handled); | ||||||
|  | 		_isRunning = true; | ||||||
|  | 	} | ||||||
|  | 	_isRunning = false; | ||||||
|  | 	onShutdown(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool SocketProactor::hasSocketHandlers() const | ||||||
|  | { | ||||||
|  | 	if (_readHandlers.size() || _writeHandlers.size()) | ||||||
|  | 		return true; | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::stop() | ||||||
|  | { | ||||||
|  | 	// the reason for two flags is to prevent a race | ||||||
|  | 	// when stop() is called before run() (which sets | ||||||
|  | 	// stop to false before entering the polling loop | ||||||
|  | 	// in order to allow multiple run()/stop() cycles) | ||||||
|  | 	_stop = true; | ||||||
|  | 	_isStopped = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::wakeUp() | ||||||
|  | { | ||||||
|  | 	if (_pThread) _pThread->wakeUp(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::setTimeout(const Poco::Timespan& timeout) | ||||||
|  | { | ||||||
|  | 	_timeout = static_cast<long>(timeout.totalMilliseconds()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Poco::Timespan SocketProactor::getTimeout() const | ||||||
|  | { | ||||||
|  | 	return _maxTimeout; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Worker& SocketProactor::worker() | ||||||
|  | { | ||||||
|  | 	poco_check_ptr(_pWorker); | ||||||
|  | 	return *_pWorker; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::addWork(const Work& ch, Timestamp::TimeDiff ms) | ||||||
|  | { | ||||||
|  | 	worker().addWork(Work(ch), ms); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::addWork(Work&& ch, Timestamp::TimeDiff ms, int pos) | ||||||
|  | { | ||||||
|  | 	worker().addWork(std::move(ch), ms, pos); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::removeWork() | ||||||
|  | { | ||||||
|  | 	worker().removeWork(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int SocketProactor::scheduledWork() | ||||||
|  | { | ||||||
|  | 	return worker().scheduledWork(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int SocketProactor::removeScheduledWork(int count) | ||||||
|  | { | ||||||
|  | 	return worker().removeScheduledWork(count); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int SocketProactor::permanentWork() | ||||||
|  | { | ||||||
|  | 	return worker().permanentWork(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int SocketProactor::removePermanentWork(int count) | ||||||
|  | { | ||||||
|  | 	return worker().removePermanentWork(count); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool SocketProactor::has(const Socket& sock) const | ||||||
|  | { | ||||||
|  | 	return _pollSet.has(sock); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool SocketProactor::ioCompletionInProgress() const | ||||||
|  | { | ||||||
|  | 	return _ioCompletion.queueSize(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::onShutdown() | ||||||
|  | { | ||||||
|  | 	_pollSet.wakeUp(); | ||||||
|  | 	_ioCompletion.stop(); | ||||||
|  | 	_ioCompletion.wait(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactor::deleteHandler(IOHandlerList& handlers, IOHandlerList::iterator& it) | ||||||
|  | { | ||||||
|  | 	if ((*it)->_owner) | ||||||
|  | 	{ | ||||||
|  | 		if ((*it)->_pBuf) | ||||||
|  | 		{ | ||||||
|  | 			delete (*it)->_pBuf; | ||||||
|  | 			(*it)->_pBuf = nullptr; | ||||||
|  | 		} | ||||||
|  | 		if ((*it)->_pAddr) | ||||||
|  | 		{ | ||||||
|  | 			delete (*it)->_pAddr; | ||||||
|  | 			(*it)->_pAddr = nullptr; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	++it; | ||||||
|  | 	handlers.pop_front(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } } // namespace Poco::Net | ||||||
| @@ -179,11 +179,14 @@ bool SocketReactor::hasEventHandler(const Socket& socket, const Poco::AbstractOb | |||||||
|  |  | ||||||
| SocketReactor::NotifierPtr SocketReactor::getNotifier(const Socket& socket, bool makeNew) | SocketReactor::NotifierPtr SocketReactor::getNotifier(const Socket& socket, bool makeNew) | ||||||
| { | { | ||||||
|  | 	const SocketImpl* pImpl = socket.impl(); | ||||||
|  | 	if (pImpl == nullptr) return 0; | ||||||
|  | 	poco_socket_t sockfd = pImpl->sockfd(); | ||||||
| 	ScopedLock lock(_mutex); | 	ScopedLock lock(_mutex); | ||||||
|  |  | ||||||
| 	EventHandlerMap::iterator it = _handlers.find(socket); | 	EventHandlerMap::iterator it = _handlers.find(sockfd); | ||||||
| 	if (it != _handlers.end()) return it->second; | 	if (it != _handlers.end()) return it->second; | ||||||
| 	else if (makeNew) return (_handlers[socket] = new SocketNotifier(socket)); | 	else if (makeNew) return (_handlers[sockfd] = new SocketNotifier(socket)); | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @@ -191,6 +194,8 @@ SocketReactor::NotifierPtr SocketReactor::getNotifier(const Socket& socket, bool | |||||||
|  |  | ||||||
| void SocketReactor::removeEventHandler(const Socket& socket, const Poco::AbstractObserver& observer) | void SocketReactor::removeEventHandler(const Socket& socket, const Poco::AbstractObserver& observer) | ||||||
| { | { | ||||||
|  | 	const SocketImpl* pImpl = socket.impl(); | ||||||
|  | 	if (pImpl == nullptr) return; | ||||||
| 	NotifierPtr pNotifier = getNotifier(socket); | 	NotifierPtr pNotifier = getNotifier(socket); | ||||||
| 	if (pNotifier && pNotifier->hasObserver(observer)) | 	if (pNotifier && pNotifier->hasObserver(observer)) | ||||||
| 	{ | 	{ | ||||||
| @@ -198,7 +203,7 @@ void SocketReactor::removeEventHandler(const Socket& socket, const Poco::Abstrac | |||||||
| 		{ | 		{ | ||||||
| 			{ | 			{ | ||||||
| 				ScopedLock lock(_mutex); | 				ScopedLock lock(_mutex); | ||||||
| 				_handlers.erase(socket); | 				_handlers.erase(pImpl->sockfd()); | ||||||
| 			} | 			} | ||||||
| 			_pollSet.remove(socket); | 			_pollSet.remove(socket); | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -51,6 +51,11 @@ StreamSocket::StreamSocket(const Socket& socket): Socket(socket) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | StreamSocket::StreamSocket(const StreamSocket& socket): Socket(socket) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| StreamSocket::StreamSocket(SocketImpl* pImpl): Socket(pImpl) | StreamSocket::StreamSocket(SocketImpl* pImpl): Socket(pImpl) | ||||||
| { | { | ||||||
| 	if (!dynamic_cast<StreamSocketImpl*>(impl())) | 	if (!dynamic_cast<StreamSocketImpl*>(impl())) | ||||||
| @@ -73,6 +78,40 @@ StreamSocket& StreamSocket::operator = (const Socket& socket) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | StreamSocket& StreamSocket::operator = (const StreamSocket& socket) | ||||||
|  | { | ||||||
|  | 	Socket::operator = (socket); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
|  | StreamSocket::StreamSocket(Socket&& socket): Socket(std::move(socket)) | ||||||
|  | { | ||||||
|  | 	if (!dynamic_cast<StreamSocketImpl*>(impl())) | ||||||
|  | 		throw InvalidArgumentException("Cannot assign incompatible socket"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | StreamSocket::StreamSocket(StreamSocket&& socket): Socket(std::move(socket)) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | StreamSocket& StreamSocket::operator = (Socket&& socket) | ||||||
|  | { | ||||||
|  | 	Socket::operator = (std::move(socket)); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | StreamSocket& StreamSocket::operator = (StreamSocket&& socket) | ||||||
|  | { | ||||||
|  | 	Socket::operator = (std::move(socket)); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif // POCO_NEW_STATE_ON_MOVE | ||||||
|  |  | ||||||
| void StreamSocket::connect(const SocketAddress& address) | void StreamSocket::connect(const SocketAddress& address) | ||||||
| { | { | ||||||
| 	impl()->connect(address); | 	impl()->connect(address); | ||||||
|   | |||||||
| @@ -65,6 +65,26 @@ WebSocket::WebSocket(const Socket& socket): | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WebSocket::WebSocket(Socket&& socket): | ||||||
|  | 	StreamSocket(std::move(socket)) | ||||||
|  | { | ||||||
|  | 	if (!dynamic_cast<WebSocketImpl*>(impl())) | ||||||
|  | 		throw InvalidArgumentException("Cannot assign incompatible socket"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WebSocket::WebSocket(const WebSocket& socket): | ||||||
|  | 	StreamSocket(socket) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WebSocket::WebSocket(WebSocket&& socket): | ||||||
|  | 	StreamSocket(std::move(socket)) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| WebSocket::~WebSocket() | WebSocket::~WebSocket() | ||||||
| { | { | ||||||
| } | } | ||||||
| @@ -80,6 +100,30 @@ WebSocket& WebSocket::operator = (const Socket& socket) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WebSocket& WebSocket::operator = (Socket&& socket) | ||||||
|  | { | ||||||
|  | 	if (dynamic_cast<WebSocketImpl*>(socket.impl())) | ||||||
|  | 		Socket::operator = (std::move(socket)); | ||||||
|  | 	else | ||||||
|  | 		throw InvalidArgumentException("Cannot assign incompatible socket"); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WebSocket& WebSocket::operator = (const WebSocket& socket) | ||||||
|  | { | ||||||
|  | 	Socket::operator = (socket); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WebSocket& WebSocket::operator = (WebSocket&& socket) | ||||||
|  | { | ||||||
|  | 	Socket::operator = (std::move(socket)); | ||||||
|  | 	return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void WebSocket::shutdown() | void WebSocket::shutdown() | ||||||
| { | { | ||||||
| 	shutdown(WS_NORMAL_CLOSE); | 	shutdown(WS_NORMAL_CLOSE); | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ objects = \ | |||||||
| 	MediaTypeTest QuotedPrintableTest DialogSocketTest \ | 	MediaTypeTest QuotedPrintableTest DialogSocketTest \ | ||||||
| 	HTTPClientTestSuite FTPClientTestSuite FTPClientSessionTest \ | 	HTTPClientTestSuite FTPClientTestSuite FTPClientSessionTest \ | ||||||
| 	FTPStreamFactoryTest DialogServer \ | 	FTPStreamFactoryTest DialogServer \ | ||||||
| 	SocketReactorTest ReactorTestSuite \ | 	SocketReactorTest ReactorTestSuite SocketProactorTest \ | ||||||
| 	MailTestSuite MailMessageTest MailStreamTest \ | 	MailTestSuite MailMessageTest MailStreamTest \ | ||||||
| 	SMTPClientSessionTest POP3ClientSessionTest \ | 	SMTPClientSessionTest POP3ClientSessionTest \ | ||||||
| 	RawSocketTest ICMPClientTest ICMPSocketTest ICMPClientTestSuite \ | 	RawSocketTest ICMPClientTest ICMPSocketTest ICMPClientTestSuite \ | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||||
|   <ItemGroup Label="ProjectConfigurations"> |   <ItemGroup Label="ProjectConfigurations"> | ||||||
|     <ProjectConfiguration Include="debug_shared|Win32"> |     <ProjectConfiguration Include="debug_shared|Win32"> | ||||||
| @@ -56,7 +56,7 @@ | |||||||
|     <RootNamespace>TestSuite</RootNamespace> |     <RootNamespace>TestSuite</RootNamespace> | ||||||
|     <Keyword>Win32Proj</Keyword> |     <Keyword>Win32Proj</Keyword> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> | ||||||
|     <ConfigurationType>Application</ConfigurationType> |     <ConfigurationType>Application</ConfigurationType> | ||||||
|     <CharacterSet>MultiByte</CharacterSet> |     <CharacterSet>MultiByte</CharacterSet> | ||||||
| @@ -117,45 +117,45 @@ | |||||||
|     <CharacterSet>MultiByte</CharacterSet> |     <CharacterSet>MultiByte</CharacterSet> | ||||||
|     <PlatformToolset>v142</PlatformToolset> |     <PlatformToolset>v142</PlatformToolset> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | ||||||
|   <ImportGroup Label="ExtensionSettings"/> |   <ImportGroup Label="ExtensionSettings" /> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|Win32'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|Win32'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'" Label="PropertySheets"> |   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'" Label="PropertySheets"> | ||||||
|     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> |     <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|   <PropertyGroup Label="UserMacros"/> |   <PropertyGroup Label="UserMacros" /> | ||||||
|   <PropertyGroup> |   <PropertyGroup> | ||||||
|     <_ProjectFileVersion>15.0.28307.799</_ProjectFileVersion> |     <_ProjectFileVersion>15.0.28307.799</_ProjectFileVersion> | ||||||
|     <TargetName Condition="'$(Configuration)|$(Platform)'=='debug_shared|Win32'">TestSuited</TargetName> |     <TargetName Condition="'$(Configuration)|$(Platform)'=='debug_shared|Win32'">TestSuited</TargetName> | ||||||
| @@ -243,7 +243,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
| @@ -275,9 +275,9 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -304,7 +304,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
| @@ -336,9 +336,9 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -365,7 +365,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
| @@ -397,9 +397,9 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -426,7 +426,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
| @@ -458,9 +458,9 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -487,7 +487,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
| @@ -519,9 +519,9 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -548,7 +548,7 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> |       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
| @@ -580,9 +580,9 @@ | |||||||
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> |       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> | ||||||
|       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> |       <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> | ||||||
|       <RuntimeTypeInfo>true</RuntimeTypeInfo> |       <RuntimeTypeInfo>true</RuntimeTypeInfo> | ||||||
|       <PrecompiledHeader/> |       <PrecompiledHeader /> | ||||||
|       <WarningLevel>Level3</WarningLevel> |       <WarningLevel>Level3</WarningLevel> | ||||||
|       <DebugInformationFormat/> |       <DebugInformationFormat /> | ||||||
|       <CompileAs>Default</CompileAs> |       <CompileAs>Default</CompileAs> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -598,70 +598,71 @@ | |||||||
|     </Link> |     </Link> | ||||||
|   </ItemDefinitionGroup> |   </ItemDefinitionGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClInclude Include="src\DatagramSocketTest.h"/> |     <ClInclude Include="src\DatagramSocketTest.h" /> | ||||||
|     <ClInclude Include="src\DialogServer.h"/> |     <ClInclude Include="src\DialogServer.h" /> | ||||||
|     <ClInclude Include="src\DialogSocketTest.h"/> |     <ClInclude Include="src\DialogSocketTest.h" /> | ||||||
|     <ClInclude Include="src\DNSTest.h"/> |     <ClInclude Include="src\DNSTest.h" /> | ||||||
|     <ClInclude Include="src\EchoServer.h"/> |     <ClInclude Include="src\EchoServer.h" /> | ||||||
|     <ClInclude Include="src\FTPClientSessionTest.h"/> |     <ClInclude Include="src\FTPClientSessionTest.h" /> | ||||||
|     <ClInclude Include="src\FTPClientTestSuite.h"/> |     <ClInclude Include="src\FTPClientTestSuite.h" /> | ||||||
|     <ClInclude Include="src\FTPStreamFactoryTest.h"/> |     <ClInclude Include="src\FTPStreamFactoryTest.h" /> | ||||||
|     <ClInclude Include="src\HTMLFormTest.h"/> |     <ClInclude Include="src\HTMLFormTest.h" /> | ||||||
|     <ClInclude Include="src\HTMLTestSuite.h"/> |     <ClInclude Include="src\HTMLTestSuite.h" /> | ||||||
|     <ClInclude Include="src\HTTPClientSessionTest.h"/> |     <ClInclude Include="src\HTTPClientSessionTest.h" /> | ||||||
|     <ClInclude Include="src\HTTPClientTestSuite.h"/> |     <ClInclude Include="src\HTTPClientTestSuite.h" /> | ||||||
|     <ClInclude Include="src\HTTPCookieTest.h"/> |     <ClInclude Include="src\HTTPCookieTest.h" /> | ||||||
|     <ClInclude Include="src\HTTPCredentialsTest.h"/> |     <ClInclude Include="src\HTTPCredentialsTest.h" /> | ||||||
|     <ClInclude Include="src\HTTPRequestTest.h"/> |     <ClInclude Include="src\HTTPRequestTest.h" /> | ||||||
|     <ClInclude Include="src\HTTPResponseTest.h"/> |     <ClInclude Include="src\HTTPResponseTest.h" /> | ||||||
|     <ClInclude Include="src\HTTPServerTest.h"/> |     <ClInclude Include="src\HTTPServerTest.h" /> | ||||||
|     <ClInclude Include="src\HTTPServerTestSuite.h"/> |     <ClInclude Include="src\HTTPServerTestSuite.h" /> | ||||||
|     <ClInclude Include="src\HTTPStreamFactoryTest.h"/> |     <ClInclude Include="src\HTTPStreamFactoryTest.h" /> | ||||||
|     <ClInclude Include="src\HTTPTestServer.h"/> |     <ClInclude Include="src\HTTPTestServer.h" /> | ||||||
|     <ClInclude Include="src\HTTPTestSuite.h"/> |     <ClInclude Include="src\HTTPTestSuite.h" /> | ||||||
|     <ClInclude Include="src\ICMPClientTest.h"/> |     <ClInclude Include="src\ICMPClientTest.h" /> | ||||||
|     <ClInclude Include="src\ICMPClientTestSuite.h"/> |     <ClInclude Include="src\ICMPClientTestSuite.h" /> | ||||||
|     <ClInclude Include="src\ICMPSocketTest.h"/> |     <ClInclude Include="src\ICMPSocketTest.h" /> | ||||||
|     <ClInclude Include="src\IPAddressTest.h"/> |     <ClInclude Include="src\IPAddressTest.h" /> | ||||||
|     <ClInclude Include="src\MailMessageTest.h"/> |     <ClInclude Include="src\MailMessageTest.h" /> | ||||||
|     <ClInclude Include="src\MailStreamTest.h"/> |     <ClInclude Include="src\MailStreamTest.h" /> | ||||||
|     <ClInclude Include="src\MailTestSuite.h"/> |     <ClInclude Include="src\MailTestSuite.h" /> | ||||||
|     <ClInclude Include="src\MediaTypeTest.h"/> |     <ClInclude Include="src\MediaTypeTest.h" /> | ||||||
|     <ClInclude Include="src\MessageHeaderTest.h"/> |     <ClInclude Include="src\MessageHeaderTest.h" /> | ||||||
|     <ClInclude Include="src\MessagesTestSuite.h"/> |     <ClInclude Include="src\MessagesTestSuite.h" /> | ||||||
|     <ClInclude Include="src\MulticastEchoServer.h"/> |     <ClInclude Include="src\MulticastEchoServer.h" /> | ||||||
|     <ClInclude Include="src\MulticastSocketTest.h"/> |     <ClInclude Include="src\MulticastSocketTest.h" /> | ||||||
|     <ClInclude Include="src\MultipartReaderTest.h"/> |     <ClInclude Include="src\MultipartReaderTest.h" /> | ||||||
|     <ClInclude Include="src\MultipartWriterTest.h"/> |     <ClInclude Include="src\MultipartWriterTest.h" /> | ||||||
|     <ClInclude Include="src\NameValueCollectionTest.h"/> |     <ClInclude Include="src\NameValueCollectionTest.h" /> | ||||||
|     <ClInclude Include="src\NetCoreTestSuite.h"/> |     <ClInclude Include="src\NetCoreTestSuite.h" /> | ||||||
|     <ClInclude Include="src\NetTestSuite.h"/> |     <ClInclude Include="src\NetTestSuite.h" /> | ||||||
|     <ClInclude Include="src\NetworkInterfaceTest.h"/> |     <ClInclude Include="src\NetworkInterfaceTest.h" /> | ||||||
|     <ClInclude Include="src\NTLMCredentialsTest.h"/> |     <ClInclude Include="src\NTLMCredentialsTest.h" /> | ||||||
|     <ClInclude Include="src\NTPClientTest.h"/> |     <ClInclude Include="src\NTPClientTest.h" /> | ||||||
|     <ClInclude Include="src\NTPClientTestSuite.h"/> |     <ClInclude Include="src\NTPClientTestSuite.h" /> | ||||||
|     <ClInclude Include="src\OAuth10CredentialsTest.h"/> |     <ClInclude Include="src\OAuth10CredentialsTest.h" /> | ||||||
|     <ClInclude Include="src\OAuth20CredentialsTest.h"/> |     <ClInclude Include="src\OAuth20CredentialsTest.h" /> | ||||||
|     <ClInclude Include="src\OAuthTestSuite.h"/> |     <ClInclude Include="src\OAuthTestSuite.h" /> | ||||||
|     <ClInclude Include="src\PollSetTest.h"/> |     <ClInclude Include="src\PollSetTest.h" /> | ||||||
|     <ClInclude Include="src\POP3ClientSessionTest.h"/> |     <ClInclude Include="src\POP3ClientSessionTest.h" /> | ||||||
|     <ClInclude Include="src\QuotedPrintableTest.h"/> |     <ClInclude Include="src\QuotedPrintableTest.h" /> | ||||||
|     <ClInclude Include="src\RawSocketTest.h"/> |     <ClInclude Include="src\RawSocketTest.h" /> | ||||||
|     <ClInclude Include="src\ReactorTestSuite.h"/> |     <ClInclude Include="src\ReactorTestSuite.h" /> | ||||||
|     <ClInclude Include="src\SMTPClientSessionTest.h"/> |     <ClInclude Include="src\SMTPClientSessionTest.h" /> | ||||||
|     <ClInclude Include="src\SocketAddressTest.h"/> |     <ClInclude Include="src\SocketAddressTest.h" /> | ||||||
|     <ClInclude Include="src\SocketReactorTest.h"/> |     <ClInclude Include="src\SocketProactorTest.h" /> | ||||||
|     <ClInclude Include="src\SocketsTestSuite.h"/> |     <ClInclude Include="src\SocketReactorTest.h" /> | ||||||
|     <ClInclude Include="src\SocketStreamTest.h"/> |     <ClInclude Include="src\SocketsTestSuite.h" /> | ||||||
|     <ClInclude Include="src\SocketTest.h"/> |     <ClInclude Include="src\SocketStreamTest.h" /> | ||||||
|     <ClInclude Include="src\SyslogTest.h"/> |     <ClInclude Include="src\SocketTest.h" /> | ||||||
|     <ClInclude Include="src\TCPServerTest.h"/> |     <ClInclude Include="src\SyslogTest.h" /> | ||||||
|     <ClInclude Include="src\TCPServerTestSuite.h"/> |     <ClInclude Include="src\TCPServerTest.h" /> | ||||||
|     <ClInclude Include="src\UDPEchoServer.h"/> |     <ClInclude Include="src\TCPServerTestSuite.h" /> | ||||||
|     <ClInclude Include="src\UDPServerTest.h"/> |     <ClInclude Include="src\UDPEchoServer.h" /> | ||||||
|     <ClInclude Include="src\UDPServerTestSuite.h"/> |     <ClInclude Include="src\UDPServerTest.h" /> | ||||||
|     <ClInclude Include="src\WebSocketTest.h"/> |     <ClInclude Include="src\UDPServerTestSuite.h" /> | ||||||
|     <ClInclude Include="src\WebSocketTestSuite.h"/> |     <ClInclude Include="src\WebSocketTest.h" /> | ||||||
|  |     <ClInclude Include="src\WebSocketTestSuite.h" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="src\DatagramSocketTest.cpp"> |     <ClCompile Include="src\DatagramSocketTest.cpp"> | ||||||
| @@ -823,6 +824,7 @@ | |||||||
|     <ClCompile Include="src\SocketAddressTest.cpp"> |     <ClCompile Include="src\SocketAddressTest.cpp"> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="src\SocketProactorTest.cpp" /> | ||||||
|     <ClCompile Include="src\SocketReactorTest.cpp"> |     <ClCompile Include="src\SocketReactorTest.cpp"> | ||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
| @@ -860,6 +862,6 @@ | |||||||
|       <MultiProcessorCompilation>true</MultiProcessorCompilation> |       <MultiProcessorCompilation>true</MultiProcessorCompilation> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | ||||||
|   <ImportGroup Label="ExtensionTargets"/> |   <ImportGroup Label="ExtensionTargets" /> | ||||||
| </Project> | </Project> | ||||||
| @@ -363,6 +363,9 @@ | |||||||
|     <ClInclude Include="src\UDPServerTestSuite.h"> |     <ClInclude Include="src\UDPServerTestSuite.h"> | ||||||
|       <Filter>UDP\Header Files</Filter> |       <Filter>UDP\Header Files</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  |     <ClInclude Include="src\SocketProactorTest.h"> | ||||||
|  |       <Filter>Sockets\Header Files</Filter> | ||||||
|  |     </ClInclude> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="src\DNSTest.cpp"> |     <ClCompile Include="src\DNSTest.cpp"> | ||||||
| @@ -560,5 +563,8 @@ | |||||||
|     <ClCompile Include="src\UDPServerTestSuite.cpp"> |     <ClCompile Include="src\UDPServerTestSuite.cpp"> | ||||||
|       <Filter>UDP\Source Files</Filter> |       <Filter>UDP\Source Files</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="src\SocketProactorTest.cpp"> | ||||||
|  |       <Filter>Sockets\Source Files</Filter> | ||||||
|  |     </ClCompile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| </Project> | </Project> | ||||||
| @@ -13,12 +13,12 @@ | |||||||
| #include "CppUnit/TestSuite.h" | #include "CppUnit/TestSuite.h" | ||||||
| #include "UDPEchoServer.h" | #include "UDPEchoServer.h" | ||||||
| #include "Poco/Net/DatagramSocket.h" | #include "Poco/Net/DatagramSocket.h" | ||||||
| #include "Poco/Net/SocketAddress.h" |  | ||||||
| #include "Poco/Net/NetworkInterface.h" | #include "Poco/Net/NetworkInterface.h" | ||||||
| #include "Poco/Net/NetException.h" | #include "Poco/Net/NetException.h" | ||||||
| #include "Poco/Timespan.h" | #include "Poco/Timespan.h" | ||||||
| #include "Poco/Buffer.h" | #include "Poco/Buffer.h" | ||||||
| #include "Poco/Stopwatch.h" | #include "Poco/Stopwatch.h" | ||||||
|  | #include "Poco/Thread.h" | ||||||
| #include <cstring> | #include <cstring> | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -35,6 +35,7 @@ using Poco::Stopwatch; | |||||||
| using Poco::TimeoutException; | using Poco::TimeoutException; | ||||||
| using Poco::InvalidArgumentException; | using Poco::InvalidArgumentException; | ||||||
| using Poco::IOException; | using Poco::IOException; | ||||||
|  | using Poco::Thread; | ||||||
|  |  | ||||||
|  |  | ||||||
| DatagramSocketTest::DatagramSocketTest(const std::string& name): CppUnit::TestCase(name) | DatagramSocketTest::DatagramSocketTest(const std::string& name): CppUnit::TestCase(name) | ||||||
| @@ -62,6 +63,46 @@ void DatagramSocketTest::testEcho() | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void DatagramSocketTest::testMoveDatagramSocket() | ||||||
|  | { | ||||||
|  | 	UDPEchoServer echoServer; | ||||||
|  | 	DatagramSocket ss0 = DatagramSocket(); | ||||||
|  | 	char buffer[256]; | ||||||
|  | 	ss0.connect(SocketAddress("127.0.0.1", echoServer.port())); | ||||||
|  | 	DatagramSocket ss(std::move(ss0)); | ||||||
|  | #if POCO_NEW_STATE_ON_MOVE | ||||||
|  | 	assertTrue (ss0.isNull()); | ||||||
|  | #else | ||||||
|  | 	assertFalse (ss0.isNull()); | ||||||
|  | #endif | ||||||
|  | 	int n = ss.sendBytes("hello", 5); | ||||||
|  | 	assertTrue (n == 5); | ||||||
|  | 	n = ss.receiveBytes(buffer, sizeof(buffer)); | ||||||
|  | 	assertTrue (n == 5); | ||||||
|  | 	assertTrue (std::string(buffer, n) == "hello"); | ||||||
|  |  | ||||||
|  | 	std::memset(buffer, 0, sizeof(buffer)); | ||||||
|  | 	ss0 = ss; | ||||||
|  | 	assertTrue (ss0.impl()); | ||||||
|  | 	assertTrue (ss.impl()); | ||||||
|  | 	assertTrue (ss0.impl() == ss.impl()); | ||||||
|  | 	ss = std::move(ss0); | ||||||
|  | #if POCO_NEW_STATE_ON_MOVE | ||||||
|  | 	assertTrue (ss0.isNull()); | ||||||
|  | #else | ||||||
|  | 	assertFalse (ss0.isNull()); | ||||||
|  | #endif | ||||||
|  | 	assertTrue (ss.impl()); | ||||||
|  | 	n = ss.sendBytes("hello", 5); | ||||||
|  | 	assertTrue (n == 5); | ||||||
|  | 	n = ss.receiveBytes(buffer, sizeof(buffer)); | ||||||
|  | 	assertTrue (n == 5); | ||||||
|  | 	assertTrue (std::string(buffer, n) == "hello"); | ||||||
|  | 	ss.close(); | ||||||
|  | 	ss0.close(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void DatagramSocketTest::testEchoBuffer() | void DatagramSocketTest::testEchoBuffer() | ||||||
| { | { | ||||||
| 	UDPEchoServer echoServer; | 	UDPEchoServer echoServer; | ||||||
| @@ -81,6 +122,25 @@ void DatagramSocketTest::testEchoBuffer() | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void DatagramSocketTest::testReceiveFromAvailable() | ||||||
|  | { | ||||||
|  | 	UDPEchoServer echoServer(SocketAddress("127.0.0.1", 0)); | ||||||
|  | 	DatagramSocket ss(SocketAddress::IPv4); | ||||||
|  | 	int n = ss.sendTo("hello", 5, SocketAddress("127.0.0.1", echoServer.port())); | ||||||
|  | 	assertTrue (n == 5); | ||||||
|  | 	Thread::sleep(100); | ||||||
|  | 	char buffer[256]; | ||||||
|  | 	SocketAddress sa; | ||||||
|  | 	assertTrue (ss.available() == 5); | ||||||
|  | 	n = ss.receiveFrom(buffer, sizeof(buffer), sa); | ||||||
|  | 	assertTrue (sa.host() == echoServer.address().host()); | ||||||
|  | 	assertTrue (sa.port() == echoServer.port()); | ||||||
|  | 	assertTrue (n == 5); | ||||||
|  | 	assertTrue (std::string(buffer, n) == "hello"); | ||||||
|  | 	ss.close(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void DatagramSocketTest::testSendToReceiveFrom() | void DatagramSocketTest::testSendToReceiveFrom() | ||||||
| { | { | ||||||
| 	UDPEchoServer echoServer(SocketAddress("127.0.0.1", 0)); | 	UDPEchoServer echoServer(SocketAddress("127.0.0.1", 0)); | ||||||
| @@ -113,6 +173,158 @@ void DatagramSocketTest::testUnbound() | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Poco::UInt16 DatagramSocketTest::getFreePort(SocketAddress::Family family, Poco::UInt16 port) | ||||||
|  | { | ||||||
|  | 	bool failed = false; | ||||||
|  | 	poco_assert_dbg(port > 0); | ||||||
|  | 	--port; | ||||||
|  | 	DatagramSocket sock(family); | ||||||
|  | 	do | ||||||
|  | 	{ | ||||||
|  | 		failed = false; | ||||||
|  | 		SocketAddress sa(family, ++port); | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			sock.bind(sa, false); | ||||||
|  | 		} | ||||||
|  | 		catch (Poco::Net::NetException&) | ||||||
|  | 		{ | ||||||
|  | 			failed = true; | ||||||
|  | 		} | ||||||
|  | 	} while (failed && sock.getError() == POCO_EADDRINUSE); | ||||||
|  | 	return port; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void DatagramSocketTest::testReuseAddressPortWildcard() | ||||||
|  | { | ||||||
|  | 	Poco::UInt16 port = getFreePort(SocketAddress::IPv4, 1234); | ||||||
|  | 	Poco::UInt16 port6 = getFreePort(SocketAddress::IPv6, 1234); | ||||||
|  | 	assertTrue(port >= 1234); | ||||||
|  | 	assertTrue(port6 >= 1234); | ||||||
|  |  | ||||||
|  | 	// reuse | ||||||
|  | 	{ | ||||||
|  | 		DatagramSocket ds1(SocketAddress::IPv4); | ||||||
|  | 		ds1.bind(SocketAddress(port), true); | ||||||
|  | 		assertTrue(ds1.getReuseAddress()); | ||||||
|  | 		DatagramSocket ds2; | ||||||
|  | 		ds2.bind(SocketAddress(port), true); | ||||||
|  | 		assertTrue(ds2.getReuseAddress()); | ||||||
|  | #ifdef POCO_HAVE_IPv6 | ||||||
|  | 		DatagramSocket ds3(SocketAddress::IPv6); | ||||||
|  | 		ds3.bind6(SocketAddress(SocketAddress::IPv6, port6), true, true, false); | ||||||
|  | 		assertTrue(ds3.getReuseAddress()); | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | #ifdef POCO_HAVE_IPv6 | ||||||
|  | 	{ | ||||||
|  | 		DatagramSocket ds1(SocketAddress::IPv6); | ||||||
|  | 		ds1.bind6(SocketAddress(SocketAddress::IPv6, port6), true, true, false); | ||||||
|  | 		assertTrue(ds1.getReuseAddress()); | ||||||
|  | 		DatagramSocket ds2; | ||||||
|  | 		ds2.bind6(SocketAddress(SocketAddress::IPv6, port6), true, true, false); | ||||||
|  | 		assertTrue(ds2.getReuseAddress()); | ||||||
|  | 		DatagramSocket ds3; | ||||||
|  | 		ds3.bind(SocketAddress(port), true, true); | ||||||
|  | 		assertTrue(ds3.getReuseAddress()); | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef POCO_HAVE_IPv6 | ||||||
|  | 	{ | ||||||
|  | 		DatagramSocket ds1(SocketAddress::IPv6); | ||||||
|  | 		ds1.bind6(SocketAddress(SocketAddress::IPv6, port), true, true, true); | ||||||
|  | 		assertTrue(ds1.getReuseAddress()); | ||||||
|  | 		DatagramSocket ds2; | ||||||
|  | 		ds2.bind6(SocketAddress(SocketAddress::IPv6, port), true, true, true); | ||||||
|  | 		assertTrue(ds2.getReuseAddress()); | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	// not reuse | ||||||
|  | 	{ | ||||||
|  | 		DatagramSocket ds1(SocketAddress::IPv4); | ||||||
|  | 		ds1.bind(SocketAddress(port), false); | ||||||
|  | 		assertTrue(!ds1.getReuseAddress()); | ||||||
|  | 		DatagramSocket ds2; | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			ds2.bind(SocketAddress(port), false); | ||||||
|  | 			fail("binding to non-reuse address must throw"); | ||||||
|  | 		} | ||||||
|  | 		catch (Poco::IOException&) {} | ||||||
|  |  | ||||||
|  | #ifdef POCO_HAVE_IPv6 | ||||||
|  | 		{ | ||||||
|  | 			DatagramSocket ds1(SocketAddress::IPv6); | ||||||
|  | 			ds1.bind6(SocketAddress(SocketAddress::IPv6, port), false, false, true); | ||||||
|  | 			assertTrue(!ds1.getReuseAddress()); | ||||||
|  | 			DatagramSocket ds2(SocketAddress::IPv6); | ||||||
|  | 			try | ||||||
|  | 			{ | ||||||
|  | 				ds2.bind6(SocketAddress(SocketAddress::IPv6, port), false, false, true); | ||||||
|  | 				fail("binding to non-reuse address must throw"); | ||||||
|  | 			} | ||||||
|  | 			catch (Poco::IOException&) {} | ||||||
|  | 		} | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void DatagramSocketTest::testReuseAddressPortSpecific() | ||||||
|  | { | ||||||
|  | 	Poco::UInt16 port = getFreePort(SocketAddress::IPv4, 1234); | ||||||
|  | 	assertTrue(port >= 1234); | ||||||
|  |  | ||||||
|  | 	// reuse | ||||||
|  | 	{ | ||||||
|  | 		DatagramSocket ds1(SocketAddress::IPv4); | ||||||
|  | 		ds1.bind(SocketAddress(port), true); | ||||||
|  | 		assertTrue(ds1.getReuseAddress()); | ||||||
|  | 		DatagramSocket ds2; | ||||||
|  | 		ds2.bind(SocketAddress("127.0.0.1", port), true); | ||||||
|  | 		assertTrue(ds2.getReuseAddress()); | ||||||
|  | #ifdef POCO_HAVE_IPv6 | ||||||
|  | 		DatagramSocket ds3(SocketAddress::IPv6); | ||||||
|  | 		ds3.bind6(SocketAddress("::1", port), true, true, false); | ||||||
|  | 		assertTrue(ds3.getReuseAddress()); | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// not reuse | ||||||
|  | 	{ | ||||||
|  | 		DatagramSocket ds1(SocketAddress::IPv4); | ||||||
|  | 		ds1.bind(SocketAddress("0.0.0.0", port), false); | ||||||
|  | 		assertTrue(!ds1.getReuseAddress()); | ||||||
|  | 		DatagramSocket ds2; | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			ds2.bind(SocketAddress("127.0.0.1", port), false); | ||||||
|  | 			fail("binding to non-reuse IPv4 address must throw"); | ||||||
|  | 		} | ||||||
|  | 		catch (Poco::IOException&) {} | ||||||
|  |  | ||||||
|  | #ifdef POCO_HAVE_IPv6 | ||||||
|  | 		{ | ||||||
|  | 			DatagramSocket ds1(SocketAddress::IPv6); | ||||||
|  | 			ds1.bind6(SocketAddress("::", port), false, false, true); | ||||||
|  | 			assertTrue(!ds1.getReuseAddress()); | ||||||
|  | 			DatagramSocket ds2(SocketAddress::IPv6); | ||||||
|  | 			try | ||||||
|  | 			{ | ||||||
|  | 				ds2.bind6(SocketAddress("::1", port), false, false, true); | ||||||
|  | 				fail("binding to non-reuse IPv6 address must throw"); | ||||||
|  | 			} | ||||||
|  | 			catch (Poco::IOException&) {} | ||||||
|  | 		} | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void DatagramSocketTest::testBroadcast() | void DatagramSocketTest::testBroadcast() | ||||||
| { | { | ||||||
| 	UDPEchoServer echoServer; | 	UDPEchoServer echoServer; | ||||||
| @@ -607,9 +819,13 @@ CppUnit::Test* DatagramSocketTest::suite() | |||||||
| 	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("DatagramSocketTest"); | 	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("DatagramSocketTest"); | ||||||
|  |  | ||||||
| 	CppUnit_addTest(pSuite, DatagramSocketTest, testEcho); | 	CppUnit_addTest(pSuite, DatagramSocketTest, testEcho); | ||||||
|  | 	CppUnit_addTest(pSuite, DatagramSocketTest, testMoveDatagramSocket); | ||||||
| 	CppUnit_addTest(pSuite, DatagramSocketTest, testEchoBuffer); | 	CppUnit_addTest(pSuite, DatagramSocketTest, testEchoBuffer); | ||||||
|  | 	CppUnit_addTest(pSuite, DatagramSocketTest, testReceiveFromAvailable); | ||||||
| 	CppUnit_addTest(pSuite, DatagramSocketTest, testSendToReceiveFrom); | 	CppUnit_addTest(pSuite, DatagramSocketTest, testSendToReceiveFrom); | ||||||
| 	CppUnit_addTest(pSuite, DatagramSocketTest, testUnbound); | 	CppUnit_addTest(pSuite, DatagramSocketTest, testUnbound); | ||||||
|  | 	CppUnit_addTest(pSuite, DatagramSocketTest, testReuseAddressPortWildcard); | ||||||
|  | 	CppUnit_addTest(pSuite, DatagramSocketTest, testReuseAddressPortSpecific); | ||||||
| #if (POCO_OS != POCO_OS_FREE_BSD) // works only with local net bcast and very randomly | #if (POCO_OS != POCO_OS_FREE_BSD) // works only with local net bcast and very randomly | ||||||
| 	CppUnit_addTest(pSuite, DatagramSocketTest, testBroadcast); | 	CppUnit_addTest(pSuite, DatagramSocketTest, testBroadcast); | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
| #include "Poco/Net/Net.h" | #include "Poco/Net/Net.h" | ||||||
|  | #include "Poco/Net/SocketAddress.h" | ||||||
| #include "CppUnit/TestCase.h" | #include "CppUnit/TestCase.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -25,9 +26,13 @@ public: | |||||||
| 	~DatagramSocketTest(); | 	~DatagramSocketTest(); | ||||||
|  |  | ||||||
| 	void testEcho(); | 	void testEcho(); | ||||||
|  | 	void testMoveDatagramSocket(); | ||||||
| 	void testEchoBuffer(); | 	void testEchoBuffer(); | ||||||
|  | 	void testReceiveFromAvailable(); | ||||||
| 	void testSendToReceiveFrom(); | 	void testSendToReceiveFrom(); | ||||||
| 	void testUnbound(); | 	void testUnbound(); | ||||||
|  | 	void testReuseAddressPortWildcard(); | ||||||
|  | 	void testReuseAddressPortSpecific(); | ||||||
| 	void testBroadcast(); | 	void testBroadcast(); | ||||||
| 	void testGatherScatterFixed(); | 	void testGatherScatterFixed(); | ||||||
| 	void testGatherScatterVariable(); | 	void testGatherScatterVariable(); | ||||||
| @@ -38,6 +43,8 @@ public: | |||||||
| 	static CppUnit::Test* suite(); | 	static CppUnit::Test* suite(); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|  | 	static Poco::UInt16 getFreePort(Poco::Net::SocketAddress::Family family, std::uint16_t port); | ||||||
|  |  | ||||||
| 	// "STRF" are sendto/recvfrom versions of the same functionality | 	// "STRF" are sendto/recvfrom versions of the same functionality | ||||||
| 	void testGatherScatterFixedWin(); | 	void testGatherScatterFixedWin(); | ||||||
| 	void testGatherScatterSTRFFixedWin(); | 	void testGatherScatterSTRFFixedWin(); | ||||||
|   | |||||||
| @@ -59,7 +59,7 @@ void ICMPClientTest::testPing() | |||||||
| 	assertTrue (icmpClient.ping("10.0.2.15", 4) > 0); | 	assertTrue (icmpClient.ping("10.0.2.15", 4) > 0); | ||||||
| 	assertTrue (icmpClient.ping("10.0.2.2", 4) > 0); | 	assertTrue (icmpClient.ping("10.0.2.2", 4) > 0); | ||||||
| #else | #else | ||||||
| 	assertTrue (icmpClient.ping("www.appinf.com", 4) > 0); | 	assertTrue (icmpClient.ping("github.com", 4) > 0); | ||||||
|  |  | ||||||
| 	// warning: may fail depending on the existence of the addresses at test site | 	// warning: may fail depending on the existence of the addresses at test site | ||||||
| 	// if so, adjust accordingly (i.e. specify non-existent or unreachable IP addresses) | 	// if so, adjust accordingly (i.e. specify non-existent or unreachable IP addresses) | ||||||
| @@ -86,7 +86,7 @@ void ICMPClientTest::testBigPing() | |||||||
| 	assertTrue (icmpClient.ping("10.0.2.15", 4) > 0); | 	assertTrue (icmpClient.ping("10.0.2.15", 4) > 0); | ||||||
| 	assertTrue (icmpClient.ping("10.0.2.2", 4) > 0); | 	assertTrue (icmpClient.ping("10.0.2.2", 4) > 0); | ||||||
| #else | #else | ||||||
| 	assertTrue (icmpClient.ping("www.appinf.com", 4) > 0); | 	assertTrue (icmpClient.ping("github.com", 4) > 0); | ||||||
|  |  | ||||||
| 	// warning: may fail depending on the existence of the addresses at test site | 	// warning: may fail depending on the existence of the addresses at test site | ||||||
| 	// if so, adjust accordingly (i.e. specify non-existent or unreachable IP addresses) | 	// if so, adjust accordingly (i.e. specify non-existent or unreachable IP addresses) | ||||||
|   | |||||||
| @@ -56,7 +56,7 @@ void ICMPSocketTest::testSendToReceiveFrom() | |||||||
| { | { | ||||||
| 	ICMPSocket ss(IPAddress::IPv4); | 	ICMPSocket ss(IPAddress::IPv4); | ||||||
|  |  | ||||||
| 	SocketAddress sa("www.appinf.com", 0); | 	SocketAddress sa("github.com", 0); | ||||||
| 	SocketAddress sr(sa); | 	SocketAddress sr(sa); | ||||||
|  |  | ||||||
| 	try | 	try | ||||||
| @@ -90,7 +90,7 @@ void ICMPSocketTest::testMTU() | |||||||
| 		std::cout << addr.toString() << " : MTU=" << mtu << std::endl; | 		std::cout << addr.toString() << " : MTU=" << mtu << std::endl; | ||||||
| 		assertTrue (mtu != 0); | 		assertTrue (mtu != 0); | ||||||
| 		sz = 1500; | 		sz = 1500; | ||||||
| 		addr = SocketAddress("www.appinf.com:0"); | 		addr = SocketAddress("github.com:0"); | ||||||
| 		mtu = ICMPSocket::mtu(addr, sz); | 		mtu = ICMPSocket::mtu(addr, sz); | ||||||
| 		std::cout << addr.toString() << " : MTU=" << mtu << std::endl; | 		std::cout << addr.toString() << " : MTU=" << mtu << std::endl; | ||||||
| 		assertTrue (mtu != 0 && mtu <= sz); | 		assertTrue (mtu != 0 && mtu <= sz); | ||||||
|   | |||||||
| @@ -31,11 +31,13 @@ IPAddressTest::~IPAddressTest() | |||||||
|  |  | ||||||
| void IPAddressTest::testStringConv() | void IPAddressTest::testStringConv() | ||||||
| { | { | ||||||
| 	IPAddress ia1("127.0.0.1"); | 	IPAddress ia01 = IPAddress("127.0.0.1"); | ||||||
|  | 	IPAddress ia1(std::move(ia01)); | ||||||
| 	assertTrue (ia1.family() == IPAddress::IPv4); | 	assertTrue (ia1.family() == IPAddress::IPv4); | ||||||
| 	assertTrue (ia1.toString() == "127.0.0.1"); | 	assertTrue (ia1.toString() == "127.0.0.1"); | ||||||
| 	 | 	 | ||||||
| 	IPAddress ia2("192.168.1.120"); | 	IPAddress ia02 = IPAddress("192.168.1.120"); | ||||||
|  | 	IPAddress ia2(std::move(ia02)); | ||||||
| 	assertTrue (ia2.family() == IPAddress::IPv4); | 	assertTrue (ia2.family() == IPAddress::IPv4); | ||||||
| 	assertTrue (ia2.toString() == "192.168.1.120"); | 	assertTrue (ia2.toString() == "192.168.1.120"); | ||||||
| 	 | 	 | ||||||
| @@ -56,15 +58,18 @@ void IPAddressTest::testStringConv() | |||||||
| void IPAddressTest::testStringConv6() | void IPAddressTest::testStringConv6() | ||||||
| { | { | ||||||
| #ifdef POCO_HAVE_IPv6 | #ifdef POCO_HAVE_IPv6 | ||||||
| 	IPAddress ia0("::1"); | 	IPAddress ia00 = IPAddress("::1"); | ||||||
|  | 	IPAddress ia0(std::move(ia00)); | ||||||
| 	assertTrue (ia0.family() == IPAddress::IPv6); | 	assertTrue (ia0.family() == IPAddress::IPv6); | ||||||
| 	assertTrue (ia0.toString() == "::1"); | 	assertTrue (ia0.toString() == "::1"); | ||||||
|  |  | ||||||
| 	IPAddress ia1("1080:0:0:0:8:600:200a:425c"); | 	IPAddress ia01 = IPAddress("1080:0:0:0:8:600:200a:425c"); | ||||||
|  | 	IPAddress ia1(std::move(ia01)); | ||||||
| 	assertTrue (ia1.family() == IPAddress::IPv6); | 	assertTrue (ia1.family() == IPAddress::IPv6); | ||||||
| 	assertTrue (ia1.toString() == "1080::8:600:200a:425c"); | 	assertTrue (ia1.toString() == "1080::8:600:200a:425c"); | ||||||
| 	 | 	 | ||||||
| 	IPAddress ia2("1080::8:600:200A:425C"); | 	IPAddress ia02 = IPAddress("1080::8:600:200A:425C"); | ||||||
|  | 	IPAddress ia2(std::move(ia02)); | ||||||
| 	assertTrue (ia2.family() == IPAddress::IPv6); | 	assertTrue (ia2.family() == IPAddress::IPv6); | ||||||
| 	assertTrue (ia2.toString() == "1080::8:600:200a:425c"); | 	assertTrue (ia2.toString() == "1080::8:600:200a:425c"); | ||||||
| 	 | 	 | ||||||
| @@ -94,8 +99,9 @@ void IPAddressTest::testStringConv6() | |||||||
| void IPAddressTest::testParse() | void IPAddressTest::testParse() | ||||||
| { | { | ||||||
| 	IPAddress ip; | 	IPAddress ip; | ||||||
|  | 	assertTrue (IPAddress::tryParse("0.0.0.0", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("255.255.255.255", ip)); | ||||||
| 	assertTrue (IPAddress::tryParse("192.168.1.120", ip)); | 	assertTrue (IPAddress::tryParse("192.168.1.120", ip)); | ||||||
| 	 |  | ||||||
| 	assertTrue (!IPAddress::tryParse("192.168.1.280", ip)); | 	assertTrue (!IPAddress::tryParse("192.168.1.280", ip)); | ||||||
|  |  | ||||||
| 	ip = IPAddress::parse("192.168.1.120"); | 	ip = IPAddress::parse("192.168.1.120"); | ||||||
| @@ -107,6 +113,33 @@ void IPAddressTest::testParse() | |||||||
| 	catch (InvalidAddressException&) | 	catch (InvalidAddressException&) | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | #ifdef POCO_HAVE_IPv6 | ||||||
|  | 	assertTrue (IPAddress::tryParse("::", ip)); | ||||||
|  | 	assertFalse (IPAddress::tryParse(":::", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("0::", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("0:0::", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("0:0:0::", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("0:0:0:0::", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("0:0:0:0:0::", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("0:0:0:0:0:0::", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("0:0:0:0:0:0:0::", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("0:0:0:0:0:0:0:0", ip)); | ||||||
|  | 	assertFalse (IPAddress::tryParse("0:0:0:0:0:0:0:0:", ip)); | ||||||
|  | 	assertFalse (IPAddress::tryParse("::0:0::", ip)); | ||||||
|  | 	assertFalse (IPAddress::tryParse("::0::0::", ip)); | ||||||
|  |  | ||||||
|  | 	assertTrue (IPAddress::tryParse("::1", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("1080:0:0:0:8:600:200a:425c", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("1080::8:600:200a:425c", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("1080::8:600:200A:425C", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("1080::8:600:200a:425c", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("::192.168.1.120", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("::ffff:192.168.1.120", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("::ffff:192.168.1.120", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("ffff:ffff:ffff:ffff::", ip)); | ||||||
|  | 	assertTrue (IPAddress::tryParse("ffff:ffff::", ip)); | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ | |||||||
| #include "Poco/Net/NetException.h" | #include "Poco/Net/NetException.h" | ||||||
| #include "Poco/Net/PollSet.h" | #include "Poco/Net/PollSet.h" | ||||||
| #include "Poco/Stopwatch.h" | #include "Poco/Stopwatch.h" | ||||||
|  | #include <iostream> | ||||||
|  |  | ||||||
|  |  | ||||||
| using Poco::Net::Socket; | using Poco::Net::Socket; | ||||||
| @@ -31,6 +32,38 @@ using Poco::Stopwatch; | |||||||
| using Poco::Thread; | using Poco::Thread; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | namespace { | ||||||
|  |  | ||||||
|  | class Poller : public Poco::Runnable | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	Poller(PollSet& pollSet, const Timespan& timeout): _pollSet(pollSet), | ||||||
|  | 		_timeout(timeout) | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void run() | ||||||
|  | 	{ | ||||||
|  | 		_running = true; | ||||||
|  | 		_pollSet.poll(_timeout); | ||||||
|  | 		_running = false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool isRunning() | ||||||
|  | 	{ | ||||||
|  | 		return _running; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	PollSet& _pollSet; | ||||||
|  | 	Timespan _timeout; | ||||||
|  | 	bool _running = false; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| PollSetTest::PollSetTest(const std::string& name): CppUnit::TestCase(name) | PollSetTest::PollSetTest(const std::string& name): CppUnit::TestCase(name) | ||||||
| { | { | ||||||
| } | } | ||||||
| @@ -41,6 +74,69 @@ PollSetTest::~PollSetTest() | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void PollSetTest::testTimeout() | ||||||
|  | { | ||||||
|  | 	EchoServer echoServer; | ||||||
|  | 	StreamSocket ss; | ||||||
|  | 	ss.connect(SocketAddress("127.0.0.1", echoServer.port())); | ||||||
|  | 	PollSet ps; | ||||||
|  | 	ps.add(ss, PollSet::POLL_READ); | ||||||
|  | 	Timespan timeout(1000000); | ||||||
|  | 	Stopwatch sw; sw.start(); | ||||||
|  | 	PollSet::SocketModeMap sm = ps.poll(timeout); | ||||||
|  | 	sw.stop(); | ||||||
|  | 	assertTrue(sm.empty()); | ||||||
|  | 	assertTrue(sw.elapsed() >= 900000); | ||||||
|  |  | ||||||
|  | 	ss.sendBytes("hello", 5); | ||||||
|  | 	sw.restart(); | ||||||
|  | 	sm = ps.poll(timeout); | ||||||
|  | 	sw.stop(); | ||||||
|  | 	assertTrue(ps.poll(timeout).size() == 1); | ||||||
|  |  | ||||||
|  | 	// just here to prevent server exception on connection reset | ||||||
|  | 	char buffer[5]; | ||||||
|  | 	ss.receiveBytes(buffer, sizeof(buffer)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void PollSetTest::testPollNB() | ||||||
|  | { | ||||||
|  | 	EchoServer echoServer1; | ||||||
|  | 	StreamSocket ss1; | ||||||
|  |  | ||||||
|  | 	ss1.connectNB(SocketAddress("127.0.0.1", echoServer1.port())); | ||||||
|  |  | ||||||
|  | 	PollSet ps; | ||||||
|  | 	assertTrue(ps.empty()); | ||||||
|  | 	ps.add(ss1, PollSet::POLL_READ); | ||||||
|  | 	ps.add(ss1, PollSet::POLL_WRITE); | ||||||
|  | 	assertTrue(!ps.empty()); | ||||||
|  | 	assertTrue(ps.has(ss1)); | ||||||
|  |  | ||||||
|  | 	while (!ss1.poll(Timespan(0, 10000), Socket::SELECT_WRITE)) | ||||||
|  | 		Poco::Thread::sleep(10); | ||||||
|  |  | ||||||
|  | 	Timespan timeout(1000000); | ||||||
|  | 	PollSet::SocketModeMap sm; | ||||||
|  | 	while (sm.empty()) sm = ps.poll(timeout); | ||||||
|  | 	assertTrue(sm.find(ss1) != sm.end()); | ||||||
|  | 	assertTrue(sm.find(ss1)->second | PollSet::POLL_WRITE); | ||||||
|  |  | ||||||
|  | 	ss1.setBlocking(true); | ||||||
|  | 	ss1.sendBytes("hello", 5); | ||||||
|  | 	char buffer[256]; | ||||||
|  |  | ||||||
|  | 	sm = ps.poll(timeout); | ||||||
|  | 	assertTrue(sm.find(ss1) != sm.end()); | ||||||
|  | 	assertTrue(sm.find(ss1)->second | PollSet::POLL_READ); | ||||||
|  |  | ||||||
|  | 	int n = ss1.receiveBytes(buffer, sizeof(buffer)); | ||||||
|  | 	assertTrue(n == 5); | ||||||
|  | 	assertTrue(std::string(buffer, n) == "hello"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void PollSetTest::testPoll() | void PollSetTest::testPoll() | ||||||
| { | { | ||||||
| 	EchoServer echoServer1; | 	EchoServer echoServer1; | ||||||
| @@ -76,31 +172,32 @@ void PollSetTest::testPoll() | |||||||
| 	PollSet::SocketModeMap sm = ps.poll(timeout); | 	PollSet::SocketModeMap sm = ps.poll(timeout); | ||||||
| 	assertTrue (sm.find(ss1) != sm.end()); | 	assertTrue (sm.find(ss1) != sm.end()); | ||||||
| 	assertTrue (sm.find(ss2) == sm.end()); | 	assertTrue (sm.find(ss2) == sm.end()); | ||||||
| 	assertTrue (sm.find(ss1)->second == PollSet::POLL_WRITE); | 	assertTrue (sm.find(ss1)->second | PollSet::POLL_WRITE); | ||||||
| 	assertTrue (sw.elapsed() < 1100000); | 	assertTrue (sw.elapsed() < 1100000); | ||||||
|  |  | ||||||
| 	ps.update(ss1, PollSet::POLL_READ); | 	ps.update(ss1, PollSet::POLL_READ); | ||||||
|  |  | ||||||
|  | 	ss1.setBlocking(true); | ||||||
| 	ss1.sendBytes("hello", 5); | 	ss1.sendBytes("hello", 5); | ||||||
| 	char buffer[256]; | 	char buffer[256]; | ||||||
| 	sw.restart(); | 	sw.restart(); | ||||||
| 	sm = ps.poll(timeout); | 	sm = ps.poll(timeout); | ||||||
| 	assertTrue (sm.find(ss1) != sm.end()); | 	assertTrue (sm.find(ss1) != sm.end()); | ||||||
| 	assertTrue (sm.find(ss2) == sm.end()); | 	assertTrue (sm.find(ss2) == sm.end()); | ||||||
| 	assertTrue (sm.find(ss1)->second == PollSet::POLL_READ); | 	assertTrue (sm.find(ss1)->second | PollSet::POLL_READ); | ||||||
| 	assertTrue (sw.elapsed() < 1100000); | 	assertTrue (sw.elapsed() < 1100000); | ||||||
|  |  | ||||||
| 	int n = ss1.receiveBytes(buffer, sizeof(buffer)); | 	int n = ss1.receiveBytes(buffer, sizeof(buffer)); | ||||||
| 	assertTrue (n == 5); | 	assertTrue (n == 5); | ||||||
| 	assertTrue (std::string(buffer, n) == "hello"); | 	assertTrue (std::string(buffer, n) == "hello"); | ||||||
|  |  | ||||||
|  | 	ss2.setBlocking(true); | ||||||
| 	ss2.sendBytes("HELLO", 5); | 	ss2.sendBytes("HELLO", 5); | ||||||
| 	sw.restart(); | 	sw.restart(); | ||||||
| 	sm = ps.poll(timeout); | 	sm = ps.poll(timeout); | ||||||
| 	assertTrue (sm.find(ss1) == sm.end()); | 	assertTrue (sm.find(ss1) == sm.end()); | ||||||
| 	assertTrue (sm.find(ss2) != sm.end()); | 	assertTrue (sm.find(ss2) != sm.end()); | ||||||
| 	assertTrue (sm.find(ss2)->second == PollSet::POLL_READ); | 	assertTrue (sm.find(ss2)->second | PollSet::POLL_READ); | ||||||
| 	assertTrue (sw.elapsed() < 1100000); | 	assertTrue (sw.elapsed() < 1100000); | ||||||
|  |  | ||||||
| 	n = ss2.receiveBytes(buffer, sizeof(buffer)); | 	n = ss2.receiveBytes(buffer, sizeof(buffer)); | ||||||
| @@ -128,16 +225,14 @@ void PollSetTest::testPoll() | |||||||
|  |  | ||||||
| void PollSetTest::testPollNoServer() | void PollSetTest::testPollNoServer() | ||||||
| { | { | ||||||
| #ifndef POCO_OS_FAMILY_WINDOWS |  | ||||||
| 	StreamSocket ss1; | 	StreamSocket ss1; | ||||||
| 	StreamSocket ss2; | 	StreamSocket ss2; | ||||||
|  |  | ||||||
| 	ss1.connectNB(SocketAddress("127.0.0.1", 0xFEFE)); | 	ss1.connectNB(SocketAddress("127.0.0.1", 0xFEFE)); | ||||||
| 	ss2.connectNB(SocketAddress("127.0.0.1", 0xFEFF)); | 	ss2.connectNB(SocketAddress("127.0.0.1", 0xFEFF)); | ||||||
| 	PollSet ps; | 	PollSet ps; | ||||||
| 	assertTrue(ps.empty()); | 	assertTrue(ps.empty()); | ||||||
| 	ps.add(ss1, PollSet::POLL_READ); | 	ps.add(ss1, PollSet::POLL_READ | PollSet::POLL_WRITE | PollSet::POLL_ERROR); | ||||||
| 	ps.add(ss2, PollSet::POLL_READ); | 	ps.add(ss2, PollSet::POLL_READ | PollSet::POLL_WRITE | PollSet::POLL_ERROR); | ||||||
| 	assertTrue(!ps.empty()); | 	assertTrue(!ps.empty()); | ||||||
| 	assertTrue(ps.has(ss1)); | 	assertTrue(ps.has(ss1)); | ||||||
| 	assertTrue(ps.has(ss2)); | 	assertTrue(ps.has(ss2)); | ||||||
| @@ -151,13 +246,11 @@ void PollSetTest::testPollNoServer() | |||||||
| 	assertTrue(sm.size() == 2); | 	assertTrue(sm.size() == 2); | ||||||
| 	for (auto s : sm) | 	for (auto s : sm) | ||||||
| 		assertTrue(0 != (s.second | PollSet::POLL_ERROR)); | 		assertTrue(0 != (s.second | PollSet::POLL_ERROR)); | ||||||
| #endif // POCO_OS_FAMILY_WINDOWS |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void PollSetTest::testPollClosedServer() | void PollSetTest::testPollClosedServer() | ||||||
| { | { | ||||||
| #ifndef POCO_OS_FAMILY_WINDOWS |  | ||||||
| 	EchoServer echoServer1; | 	EchoServer echoServer1; | ||||||
| 	EchoServer echoServer2; | 	EchoServer echoServer2; | ||||||
| 	StreamSocket ss1; | 	StreamSocket ss1; | ||||||
| @@ -165,7 +258,6 @@ void PollSetTest::testPollClosedServer() | |||||||
|  |  | ||||||
| 	ss1.connect(SocketAddress("127.0.0.1", echoServer1.port())); | 	ss1.connect(SocketAddress("127.0.0.1", echoServer1.port())); | ||||||
| 	ss2.connect(SocketAddress("127.0.0.1", echoServer2.port())); | 	ss2.connect(SocketAddress("127.0.0.1", echoServer2.port())); | ||||||
|  |  | ||||||
| 	PollSet ps; | 	PollSet ps; | ||||||
| 	assertTrue(ps.empty()); | 	assertTrue(ps.empty()); | ||||||
| 	ps.add(ss1, PollSet::POLL_READ); | 	ps.add(ss1, PollSet::POLL_READ); | ||||||
| @@ -190,7 +282,28 @@ void PollSetTest::testPollClosedServer() | |||||||
| 	assertTrue(sm.size() == 2); | 	assertTrue(sm.size() == 2); | ||||||
| 	assertTrue(0 == ss1.receiveBytes(0, 0)); | 	assertTrue(0 == ss1.receiveBytes(0, 0)); | ||||||
| 	assertTrue(0 == ss2.receiveBytes(0, 0)); | 	assertTrue(0 == ss2.receiveBytes(0, 0)); | ||||||
| #endif // POCO_OS_FAMILY_WINDOWS | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void PollSetTest::testPollSetWakeUp() | ||||||
|  | { | ||||||
|  | #if defined(POCO_HAVE_FD_EPOLL) | ||||||
|  | 	PollSet ps; | ||||||
|  | 	Timespan timeout(100000000); // 100 seconds | ||||||
|  | 	Poller poller(ps, timeout); | ||||||
|  | 	Thread t; | ||||||
|  | 	Stopwatch sw; | ||||||
|  | 	sw.start(); | ||||||
|  | 	t.start(poller); | ||||||
|  | 	while (!poller.isRunning()) Thread::sleep(100); | ||||||
|  | 	ps.wakeUp(); | ||||||
|  | 	t.join(); | ||||||
|  | 	sw.stop(); | ||||||
|  | 	assertFalse (poller.isRunning()); | ||||||
|  | 	assertTrue(sw.elapsedSeconds() < 1); | ||||||
|  | #else // TODO: other implementations | ||||||
|  | 	std::cout << "not implemented"; | ||||||
|  | #endif // POCO_HAVE_FD_EPOLL | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -208,9 +321,12 @@ CppUnit::Test* PollSetTest::suite() | |||||||
| { | { | ||||||
| 	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("PollSetTest"); | 	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("PollSetTest"); | ||||||
|  |  | ||||||
|  | 	CppUnit_addTest(pSuite, PollSetTest, testTimeout); | ||||||
|  | 	CppUnit_addTest(pSuite, PollSetTest, testPollNB); | ||||||
| 	CppUnit_addTest(pSuite, PollSetTest, testPoll); | 	CppUnit_addTest(pSuite, PollSetTest, testPoll); | ||||||
| 	CppUnit_addTest(pSuite, PollSetTest, testPollNoServer); | 	CppUnit_addTest(pSuite, PollSetTest, testPollNoServer); | ||||||
| 	CppUnit_addTest(pSuite, PollSetTest, testPollClosedServer); | 	CppUnit_addTest(pSuite, PollSetTest, testPollClosedServer); | ||||||
|  | 	CppUnit_addTest(pSuite, PollSetTest, testPollSetWakeUp); | ||||||
|  |  | ||||||
| 	return pSuite; | 	return pSuite; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -24,9 +24,12 @@ public: | |||||||
| 	PollSetTest(const std::string& name); | 	PollSetTest(const std::string& name); | ||||||
| 	~PollSetTest(); | 	~PollSetTest(); | ||||||
|  |  | ||||||
|  | 	void testTimeout(); | ||||||
|  | 	void testPollNB(); | ||||||
| 	void testPoll(); | 	void testPoll(); | ||||||
| 	void testPollNoServer(); | 	void testPollNoServer(); | ||||||
| 	void testPollClosedServer(); | 	void testPollClosedServer(); | ||||||
|  | 	void testPollSetWakeUp(); | ||||||
|  |  | ||||||
| 	void setUp(); | 	void setUp(); | ||||||
| 	void tearDown(); | 	void tearDown(); | ||||||
|   | |||||||
| @@ -84,6 +84,31 @@ void RawSocketTest::testSendToReceiveFromIPv4() | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void RawSocketTest::testEchoIPv4Move() | ||||||
|  | { | ||||||
|  | 	SocketAddress sa("127.0.0.1", 0); | ||||||
|  | 	RawSocket rs0 = RawSocket(IPAddress::IPv4); | ||||||
|  | 	rs0.connect(sa); | ||||||
|  |  | ||||||
|  | 	RawSocket rs(std::move(rs0)); | ||||||
|  | 	assertTrue (rs0.impl() == nullptr); | ||||||
|  | 	int n = rs.sendBytes("hello", 5); | ||||||
|  | 	assertTrue (5 == n); | ||||||
|  |  | ||||||
|  | 	char buffer[256] = ""; | ||||||
|  | 	unsigned char* ptr = (unsigned char*) buffer; | ||||||
|  |  | ||||||
|  | 	n = rs.receiveBytes(buffer, sizeof(buffer)); | ||||||
|  | 	int shift = ((buffer[0] & 0x0F) * 4); | ||||||
|  | 	ptr += shift; | ||||||
|  |  | ||||||
|  | 	assertTrue (5 == (n - shift)); | ||||||
|  | 	assertTrue ("hello" == std::string((char*)ptr, 5)); | ||||||
|  |  | ||||||
|  | 	rs.close(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void RawSocketTest::setUp() | void RawSocketTest::setUp() | ||||||
| { | { | ||||||
| } | } | ||||||
| @@ -100,6 +125,7 @@ CppUnit::Test* RawSocketTest::suite() | |||||||
|  |  | ||||||
| 	CppUnit_addTest(pSuite, RawSocketTest, testEchoIPv4); | 	CppUnit_addTest(pSuite, RawSocketTest, testEchoIPv4); | ||||||
| 	CppUnit_addTest(pSuite, RawSocketTest, testSendToReceiveFromIPv4); | 	CppUnit_addTest(pSuite, RawSocketTest, testSendToReceiveFromIPv4); | ||||||
|  | 	CppUnit_addTest(pSuite, RawSocketTest, testEchoIPv4Move); | ||||||
|  |  | ||||||
| 	return pSuite; | 	return pSuite; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -26,6 +26,7 @@ public: | |||||||
|  |  | ||||||
| 	void testEchoIPv4(); | 	void testEchoIPv4(); | ||||||
| 	void testSendToReceiveFromIPv4(); | 	void testSendToReceiveFromIPv4(); | ||||||
|  | 	void testEchoIPv4Move(); | ||||||
|  |  | ||||||
| 	void setUp(); | 	void setUp(); | ||||||
| 	void tearDown(); | 	void tearDown(); | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ | |||||||
| #include "CppUnit/TestSuite.h" | #include "CppUnit/TestSuite.h" | ||||||
| #include "Poco/Net/SocketAddress.h" | #include "Poco/Net/SocketAddress.h" | ||||||
| #include "Poco/Net/NetException.h" | #include "Poco/Net/NetException.h" | ||||||
|  | #include <iostream> | ||||||
|  |  | ||||||
|  |  | ||||||
| using Poco::Net::SocketAddress; | using Poco::Net::SocketAddress; | ||||||
| @@ -41,19 +42,22 @@ void SocketAddressTest::testSocketAddress() | |||||||
| 	assertTrue (wild.host().isWildcard()); | 	assertTrue (wild.host().isWildcard()); | ||||||
| 	assertTrue (wild.port() == 0); | 	assertTrue (wild.port() == 0); | ||||||
|  |  | ||||||
| 	SocketAddress sa1("192.168.1.100", 100); | 	SocketAddress sa01 = SocketAddress("192.168.1.100", 100); | ||||||
|  | 	SocketAddress sa1(std::move(sa01)); | ||||||
| 	assertTrue (sa1.af() == AF_INET); | 	assertTrue (sa1.af() == AF_INET); | ||||||
| 	assertTrue (sa1.family() == SocketAddress::IPv4); | 	assertTrue (sa1.family() == SocketAddress::IPv4); | ||||||
| 	assertTrue (sa1.host().toString() == "192.168.1.100"); | 	assertTrue (sa1.host().toString() == "192.168.1.100"); | ||||||
| 	assertTrue (sa1.port() == 100); | 	assertTrue (sa1.port() == 100); | ||||||
| 	assertTrue (sa1.toString() == "192.168.1.100:100"); | 	assertTrue (sa1.toString() == "192.168.1.100:100"); | ||||||
|  |  | ||||||
| 	SocketAddress sa2("192.168.1.100", "100"); | 	SocketAddress sa02 = SocketAddress("192.168.1.100", "100"); | ||||||
|  | 	SocketAddress sa2(std::move(sa02)); | ||||||
| 	assertTrue (sa2.host().toString() == "192.168.1.100"); | 	assertTrue (sa2.host().toString() == "192.168.1.100"); | ||||||
| 	assertTrue (sa2.port() == 100); | 	assertTrue (sa2.port() == 100); | ||||||
|  |  | ||||||
| #if !defined(_WIN32_WCE) | #if !defined(_WIN32_WCE) | ||||||
| 	SocketAddress sa3("192.168.1.100", "ftp"); | 	SocketAddress sa03 = SocketAddress("192.168.1.100", "ftp"); | ||||||
|  | 	SocketAddress sa3(std::move(sa03)); | ||||||
| 	assertTrue (sa3.host().toString() == "192.168.1.100"); | 	assertTrue (sa3.host().toString() == "192.168.1.100"); | ||||||
| 	assertTrue (sa3.port() == 21); | 	assertTrue (sa3.port() == 21); | ||||||
| #endif | #endif | ||||||
| @@ -67,7 +71,8 @@ void SocketAddressTest::testSocketAddress() | |||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	SocketAddress sa4("pocoproject.org", 80); | 	SocketAddress sa04 = SocketAddress("pocoproject.org", 80); | ||||||
|  | 	SocketAddress sa4(std::move(sa04)); | ||||||
| 	assertTrue (sa4.host().toString() == "54.93.62.90"); | 	assertTrue (sa4.host().toString() == "54.93.62.90"); | ||||||
| 	assertTrue (sa4.port() == 80); | 	assertTrue (sa4.port() == 80); | ||||||
|  |  | ||||||
| @@ -92,11 +97,13 @@ void SocketAddressTest::testSocketAddress() | |||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	SocketAddress sa7("192.168.2.120:88"); | 	SocketAddress sa07 = SocketAddress("192.168.2.120:88"); | ||||||
|  | 	SocketAddress sa7(std::move(sa07)); | ||||||
| 	assertTrue (sa7.host().toString() == "192.168.2.120"); | 	assertTrue (sa7.host().toString() == "192.168.2.120"); | ||||||
| 	assertTrue (sa7.port() == 88); | 	assertTrue (sa7.port() == 88); | ||||||
|  |  | ||||||
| 	SocketAddress sa8("[192.168.2.120]:88"); | 	SocketAddress sa08 = SocketAddress("[192.168.2.120]:88"); | ||||||
|  | 	SocketAddress sa8(std::move(sa08)); | ||||||
| 	assertTrue (sa8.host().toString() == "192.168.2.120"); | 	assertTrue (sa8.host().toString() == "192.168.2.120"); | ||||||
| 	assertTrue (sa8.port() == 88); | 	assertTrue (sa8.port() == 88); | ||||||
|  |  | ||||||
| @@ -121,7 +128,8 @@ void SocketAddressTest::testSocketAddress() | |||||||
| 	SocketAddress sa10("www6.pocoproject.org", 80); | 	SocketAddress sa10("www6.pocoproject.org", 80); | ||||||
| 	assertTrue (sa10.host().toString() == "54.93.62.90" || sa10.host().toString() == "2001:4801:7828:101:be76:4eff:fe10:1455"); | 	assertTrue (sa10.host().toString() == "54.93.62.90" || sa10.host().toString() == "2001:4801:7828:101:be76:4eff:fe10:1455"); | ||||||
|  |  | ||||||
| 	SocketAddress sa11(SocketAddress::IPv4, "www6.pocoproject.org", 80); | 	SocketAddress sa011 = SocketAddress(SocketAddress::IPv4, "www6.pocoproject.org", 80); | ||||||
|  | 	SocketAddress sa11(std::move(sa011)); | ||||||
| 	assertTrue (sa11.host().toString() == "54.93.62.90"); | 	assertTrue (sa11.host().toString() == "54.93.62.90"); | ||||||
|  |  | ||||||
| #ifdef POCO_HAVE_IPv6 | #ifdef POCO_HAVE_IPv6 | ||||||
| @@ -168,6 +176,8 @@ void SocketAddressTest::testSocketAddress6() | |||||||
| 	assertTrue (sa2.host().toString() == "fe80::e6ce:8fff:fe4a:edd0"); | 	assertTrue (sa2.host().toString() == "fe80::e6ce:8fff:fe4a:edd0"); | ||||||
| 	assertTrue (sa2.port() == 100); | 	assertTrue (sa2.port() == 100); | ||||||
| 	assertTrue (sa2.toString() == "[fe80::e6ce:8fff:fe4a:edd0]:100"); | 	assertTrue (sa2.toString() == "[fe80::e6ce:8fff:fe4a:edd0]:100"); | ||||||
|  | #else | ||||||
|  | 	std::cout << "[IPv6 DISABLED]" << std::endl; | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -191,6 +201,8 @@ void SocketAddressTest::testSocketAddressUnixLocal() | |||||||
| 	SocketAddress sa4("/tmp/sock1"); | 	SocketAddress sa4("/tmp/sock1"); | ||||||
| 	assertTrue (sa1 == sa4); | 	assertTrue (sa1 == sa4); | ||||||
| 	assertTrue (sa4.toString() == "/tmp/sock1"); | 	assertTrue (sa4.toString() == "/tmp/sock1"); | ||||||
|  | #else | ||||||
|  | 	std::cout << "[UNIX LOCAL DISABLED]" << std::endl; | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										314
									
								
								Net/testsuite/src/SocketProactorTest.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								Net/testsuite/src/SocketProactorTest.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,314 @@ | |||||||
|  | // | ||||||
|  | // SocketProactorTest.cpp | ||||||
|  | // | ||||||
|  | // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. | ||||||
|  | // and Contributors. | ||||||
|  | // | ||||||
|  | // SPDX-License-Identifier:	BSL-1.0 | ||||||
|  | // | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include "SocketProactorTest.h" | ||||||
|  | #include "UDPEchoServer.h" | ||||||
|  | #include "CppUnit/TestCaller.h" | ||||||
|  | #include "CppUnit/TestSuite.h" | ||||||
|  | #include "Poco/Net/StreamSocket.h" | ||||||
|  | #include "Poco/Net/DatagramSocket.h" | ||||||
|  | #include "Poco/Net/ServerSocket.h" | ||||||
|  | #include "Poco/Timestamp.h" | ||||||
|  | #include <iostream> | ||||||
|  |  | ||||||
|  | using Poco::Net::SocketProactor; | ||||||
|  | using Poco::Net::StreamSocket; | ||||||
|  | using Poco::Net::DatagramSocket; | ||||||
|  | using Poco::Net::ServerSocket; | ||||||
|  | using Poco::Net::SocketAddress; | ||||||
|  | using Poco::Thread; | ||||||
|  | using Poco::Timestamp; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SocketProactorTest::SocketProactorTest(const std::string& name): CppUnit::TestCase(name) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SocketProactorTest::~SocketProactorTest() | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactorTest::testTCPSocketProactor() | ||||||
|  | { | ||||||
|  | 	EchoServer echoServer; | ||||||
|  | 	SocketProactor proactor(false); | ||||||
|  | 	StreamSocket s; | ||||||
|  | 	s.connect(SocketAddress("127.0.0.1", echoServer.port())); | ||||||
|  | 	int mode = SocketProactor::POLL_READ | SocketProactor::POLL_WRITE | SocketProactor::POLL_ERROR; | ||||||
|  | 	proactor.addSocket(s, mode); | ||||||
|  | 	std::string hello = "hello proactor world"; | ||||||
|  | 	bool sent = false, sendPassed = false; | ||||||
|  | 	auto onSendCompletion = [&](std::error_code err, int bytes) | ||||||
|  | 	{ | ||||||
|  | 		sendPassed = (err.value() == 0) && (bytes == hello.length()); | ||||||
|  | 		sent = true; | ||||||
|  | 	}; | ||||||
|  | 	proactor.addSend(s, SocketProactor::Buffer(hello.begin(), hello.end()), onSendCompletion); | ||||||
|  | 	SocketProactor::Buffer buf(hello.size(), 0); | ||||||
|  | 	bool received = false, receivePassed = false; | ||||||
|  | 	auto onRecvCompletion = [&](std::error_code err, int bytes) | ||||||
|  | 	{ | ||||||
|  | 		receivePassed = (err.value() == 0) && | ||||||
|  | 						(bytes == hello.length()) && | ||||||
|  | 						(std::string(buf.begin(), buf.end()) == hello); | ||||||
|  | 		received = true; | ||||||
|  | 	}; | ||||||
|  | 	proactor.addReceive(s, buf, onRecvCompletion); | ||||||
|  | 	while (!received) proactor.poll(); | ||||||
|  |  | ||||||
|  | 	assertTrue (sent); | ||||||
|  | 	assertTrue (sendPassed); | ||||||
|  | 	assertTrue (received); | ||||||
|  | 	assertTrue (receivePassed); | ||||||
|  |  | ||||||
|  | 	buf.clear(); | ||||||
|  | 	buf.resize(hello.size()); | ||||||
|  | 	assertFalse(std::string(buf.begin(), buf.end()) == hello); | ||||||
|  |  | ||||||
|  | 	sent = false; | ||||||
|  | 	sendPassed = false; | ||||||
|  | 	received = false; | ||||||
|  | 	receivePassed = false; | ||||||
|  |  | ||||||
|  | 	proactor.addSend(s, SocketProactor::Buffer(hello.begin(), hello.end()), nullptr); | ||||||
|  | 	proactor.addReceive(s, buf, nullptr); | ||||||
|  | 	int handled = 0, handledTot = 0; | ||||||
|  | 	do | ||||||
|  | 	{ | ||||||
|  | 		proactor.poll(&handled); | ||||||
|  | 		handledTot += handled; | ||||||
|  | 	} | ||||||
|  | 	while (handledTot < 2); | ||||||
|  |  | ||||||
|  | 	assertTrue(std::string(buf.begin(), buf.end()) == hello); | ||||||
|  | 	assertFalse (sent); | ||||||
|  | 	assertFalse (sendPassed); | ||||||
|  | 	assertFalse (received); | ||||||
|  | 	assertFalse (receivePassed); | ||||||
|  |  | ||||||
|  | 	bool error = false; | ||||||
|  | 	bool errorPassed = false; | ||||||
|  | 	auto onError = [&](std::error_code err, int bytes) | ||||||
|  | 	{ | ||||||
|  | 		errorPassed = (err.value() != 0) && (bytes == 0); | ||||||
|  | 		error = true; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	StreamSocket errSock(SocketAddress::IPv4); | ||||||
|  | 	errSock.connectNB(SocketAddress("127.0.0.1", 0xFFEE)); | ||||||
|  | 	proactor.addSend(errSock, SocketProactor::Buffer(hello.begin(), hello.end()), onError); | ||||||
|  | 	Thread::sleep(100); | ||||||
|  | 	while (!error) proactor.poll(); | ||||||
|  | 	assertTrue (error); | ||||||
|  | 	assertTrue(errorPassed); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactorTest::testUDPSocketProactor() | ||||||
|  | { | ||||||
|  | 	UDPEchoServer echoServer; | ||||||
|  | 	DatagramSocket s(SocketAddress::IPv4); | ||||||
|  | 	SocketProactor proactor(false); | ||||||
|  | 	int mode = SocketProactor::POLL_READ | SocketProactor::POLL_WRITE; | ||||||
|  | 	proactor.addSocket(s, mode); | ||||||
|  | 	std::string hello = "hello proactor world"; | ||||||
|  | 	bool sent = false, sendPassed = false; | ||||||
|  | 	auto onSendCompletion = [&](std::error_code err, int bytes) | ||||||
|  | 	{ | ||||||
|  | 		sendPassed = (err.value() == 0) && | ||||||
|  | 			(bytes == hello.length()); | ||||||
|  | 		sent = true; | ||||||
|  | 	}; | ||||||
|  | 	proactor.addSendTo(s, | ||||||
|  | 		SocketProactor::Buffer(hello.begin(), hello.end()), | ||||||
|  | 		SocketAddress("127.0.0.1", echoServer.port()), | ||||||
|  | 		onSendCompletion); | ||||||
|  | 	Poco::Net::SocketProactor::Buffer buf(hello.size(), 0); | ||||||
|  | 	bool received = false, receivePassed = false; | ||||||
|  | 	SocketAddress sa; | ||||||
|  | 	auto onRecvCompletion = [&](std::error_code err, int bytes) | ||||||
|  | 	{ | ||||||
|  | 		receivePassed = (err.value() == 0) && | ||||||
|  | 			(bytes == hello.length()) && | ||||||
|  | 			(sa.host().toString() == "127.0.0.1") && | ||||||
|  | 			(sa.port() == echoServer.port()) && | ||||||
|  | 			(std::string(buf.begin(), buf.end()) == hello); | ||||||
|  | 		received = true; | ||||||
|  | 	}; | ||||||
|  | 	proactor.addReceiveFrom(s, buf, sa, onRecvCompletion); | ||||||
|  | 	while (!received) proactor.poll(); | ||||||
|  |  | ||||||
|  | 	assertTrue (sent); | ||||||
|  | 	assertTrue (sendPassed); | ||||||
|  | 	assertTrue (received); | ||||||
|  | 	assertTrue (receivePassed); | ||||||
|  |  | ||||||
|  | 	buf.clear(); | ||||||
|  | 	buf.resize(hello.size()); | ||||||
|  | 	assertFalse(std::string(buf.begin(), buf.end()) == hello); | ||||||
|  |  | ||||||
|  | 	sent = false; | ||||||
|  | 	sendPassed = false; | ||||||
|  | 	received = false; | ||||||
|  | 	receivePassed = false; | ||||||
|  |  | ||||||
|  | 	proactor.addSendTo(s, | ||||||
|  | 		SocketProactor::Buffer(hello.begin(), hello.end()), | ||||||
|  | 		SocketAddress("127.0.0.1", echoServer.port()), | ||||||
|  | 		nullptr); | ||||||
|  | 	proactor.addReceiveFrom(s, buf, sa, nullptr); | ||||||
|  | 	int handled = 0, handledTot = 0; | ||||||
|  | 	do | ||||||
|  | 	{ | ||||||
|  | 		proactor.poll(&handled); | ||||||
|  | 		handledTot += handled; | ||||||
|  | 	} while (handledTot < 2); | ||||||
|  |  | ||||||
|  | 	assertTrue(std::string(buf.begin(), buf.end()) == hello); | ||||||
|  | 	assertFalse (sent); | ||||||
|  | 	assertFalse (sendPassed); | ||||||
|  | 	assertFalse (received); | ||||||
|  | 	assertFalse (receivePassed); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactorTest::testSocketProactorStartStop() | ||||||
|  | { | ||||||
|  | 	UDPEchoServer echoServer; | ||||||
|  | 	DatagramSocket s(SocketAddress::IPv4); | ||||||
|  | 	SocketProactor proactor(false); | ||||||
|  | 	int mode = SocketProactor::POLL_READ | SocketProactor::POLL_WRITE; | ||||||
|  | 	proactor.addSocket(s, mode); | ||||||
|  | 	std::string hello = "hello proactor world"; | ||||||
|  | 	bool sent = false, sendPassed = false; | ||||||
|  | 	auto onSendCompletion = [&](std::error_code err, int bytes) | ||||||
|  | 	{ | ||||||
|  | 		sendPassed = (err.value() == 0) && | ||||||
|  | 			(bytes == hello.length()); | ||||||
|  | 		sent = true; | ||||||
|  | 	}; | ||||||
|  | 	proactor.addSendTo(s, | ||||||
|  | 		SocketProactor::Buffer(hello.begin(), hello.end()), | ||||||
|  | 		SocketAddress("127.0.0.1", echoServer.port()), | ||||||
|  | 		onSendCompletion); | ||||||
|  | 	Poco::Net::SocketProactor::Buffer buf(hello.size(), 0); | ||||||
|  | 	bool received = false, receivePassed = false; | ||||||
|  | 	SocketAddress sa; | ||||||
|  | 	auto onRecvCompletion = [&](std::error_code err, int bytes) | ||||||
|  | 	{ | ||||||
|  | 		receivePassed = (err.value() == 0) && | ||||||
|  | 			(bytes == hello.length()) && | ||||||
|  | 			(sa.host().toString() == "127.0.0.1") && | ||||||
|  | 			(sa.port() == echoServer.port()) && | ||||||
|  | 			(std::string(buf.begin(), buf.end()) == hello); | ||||||
|  | 		received = true; | ||||||
|  | 		proactor.stop(); | ||||||
|  | 	}; | ||||||
|  | 	proactor.addReceiveFrom(s, buf, sa, onRecvCompletion); | ||||||
|  |  | ||||||
|  | 	while (!received) proactor.poll(); | ||||||
|  |  | ||||||
|  | 	assertTrue (sent); | ||||||
|  | 	assertTrue (sendPassed); | ||||||
|  | 	assertTrue (received); | ||||||
|  | 	assertTrue (receivePassed); | ||||||
|  |  | ||||||
|  | 	buf.clear(); | ||||||
|  | 	buf.resize(hello.size()); | ||||||
|  | 	assertFalse(std::string(buf.begin(), buf.end()) == hello); | ||||||
|  |  | ||||||
|  | 	sent = false; | ||||||
|  | 	sendPassed = false; | ||||||
|  | 	received = false; | ||||||
|  | 	receivePassed = false; | ||||||
|  |  | ||||||
|  | 	assertFalse (sent); | ||||||
|  | 	assertFalse (sendPassed); | ||||||
|  | 	assertFalse (received); | ||||||
|  | 	assertFalse (receivePassed); | ||||||
|  |  | ||||||
|  | 	proactor.addSendTo(s, | ||||||
|  | 		SocketProactor::Buffer(hello.begin(), hello.end()), | ||||||
|  | 		SocketAddress("127.0.0.1", echoServer.port()), | ||||||
|  | 		onSendCompletion); | ||||||
|  | 	proactor.addReceiveFrom(s, buf, sa, onRecvCompletion); | ||||||
|  | 	while (!received) proactor.poll(); | ||||||
|  |  | ||||||
|  | 	assertTrue(std::string(buf.begin(), buf.end()) == hello); | ||||||
|  | 	assertTrue (sent); | ||||||
|  | 	assertTrue (sendPassed); | ||||||
|  | 	assertTrue (received); | ||||||
|  | 	assertTrue (receivePassed); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactorTest::testWork() | ||||||
|  | { | ||||||
|  | 	SocketProactor proactor; | ||||||
|  | 	int executed = 0; | ||||||
|  | 	SocketProactor::Work work = [&]() { ++executed; }; | ||||||
|  | 	proactor.addWork(work); | ||||||
|  | 	assertTrue (proactor.runOne() == 1); | ||||||
|  | 	assertEquals (executed, 1); | ||||||
|  | 	assertTrue (proactor.poll() == 0); | ||||||
|  | 	assertEquals (executed, 1); | ||||||
|  |  | ||||||
|  | 	UDPEchoServer echoServer; | ||||||
|  | 	DatagramSocket s(SocketAddress::IPv4); | ||||||
|  | 	int mode = SocketProactor::POLL_READ | SocketProactor::POLL_WRITE; | ||||||
|  | 	proactor.addSocket(s, mode); | ||||||
|  | 	proactor.addSendTo(s, | ||||||
|  | 		SocketProactor::Buffer(1, 0), | ||||||
|  | 		SocketAddress("127.0.0.1", echoServer.port()), | ||||||
|  | 		nullptr); | ||||||
|  | 	assertTrue (proactor.poll() == 1); | ||||||
|  | 	assertEquals (executed, 2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactorTest::testTimedWork() | ||||||
|  | { | ||||||
|  | 	SocketProactor proactor; | ||||||
|  | 	int executed = 0; | ||||||
|  | 	SocketProactor::Work work = [&]() { ++executed; }; | ||||||
|  | 	proactor.addWork(work, 0); | ||||||
|  | 	proactor.addWork(work, 1000); | ||||||
|  | 	assertTrue (proactor.poll() == 1); | ||||||
|  | 	assertEquals (executed, 1); | ||||||
|  | 	Thread::sleep(1000); | ||||||
|  | 	assertTrue (proactor.poll() == 1); | ||||||
|  | 	assertEquals (executed, 2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactorTest::setUp() | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void SocketProactorTest::tearDown() | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CppUnit::Test* SocketProactorTest::suite() | ||||||
|  | { | ||||||
|  | 	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("SocketProactorTest"); | ||||||
|  |  | ||||||
|  | 	CppUnit_addTest(pSuite, SocketProactorTest, testTCPSocketProactor); | ||||||
|  | 	CppUnit_addTest(pSuite, SocketProactorTest, testUDPSocketProactor); | ||||||
|  | 	CppUnit_addTest(pSuite, SocketProactorTest, testSocketProactorStartStop); | ||||||
|  | 	CppUnit_addTest(pSuite, SocketProactorTest, testWork); | ||||||
|  | 	CppUnit_addTest(pSuite, SocketProactorTest, testTimedWork); | ||||||
|  |  | ||||||
|  | 	return pSuite; | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								Net/testsuite/src/SocketProactorTest.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								Net/testsuite/src/SocketProactorTest.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | // | ||||||
|  | // SocketProactorTest.h | ||||||
|  | // | ||||||
|  | // Definition of the SocketProactorTest class. | ||||||
|  | // | ||||||
|  | // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. | ||||||
|  | // and Contributors. | ||||||
|  | // | ||||||
|  | // SPDX-License-Identifier:	BSL-1.0 | ||||||
|  | // | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #ifndef SocketProactorTest_INCLUDED | ||||||
|  | #define SocketProactorTest_INCLUDED | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include "Poco/Net/Net.h" | ||||||
|  | #include "Poco/Thread.h" | ||||||
|  | #include "Poco/Observer.h" | ||||||
|  | #include "Poco/Net/SocketAddress.h" | ||||||
|  | #include "Poco/Net/SocketProactor.h" | ||||||
|  | #include "Poco/Net/SocketNotification.h" | ||||||
|  | #include "CppUnit/TestCase.h" | ||||||
|  | #include "EchoServer.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class SocketProactorTest: public CppUnit::TestCase | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	SocketProactorTest(const std::string& name); | ||||||
|  | 	~SocketProactorTest(); | ||||||
|  |  | ||||||
|  | 	void testTCPSocketProactor(); | ||||||
|  | 	void testUDPSocketProactor(); | ||||||
|  | 	void testSocketProactorStartStop(); | ||||||
|  |  | ||||||
|  | 	void testWork(); | ||||||
|  | 	void testTimedWork(); | ||||||
|  |  | ||||||
|  | 	void setUp(); | ||||||
|  | 	void tearDown(); | ||||||
|  |  | ||||||
|  | 	static CppUnit::Test* suite(); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif // SocketProactorTest_INCLUDED | ||||||
| @@ -44,6 +44,10 @@ using Poco::Thread; | |||||||
|  |  | ||||||
| namespace | namespace | ||||||
| { | { | ||||||
|  | 	int DATA_SIZE = 1024; | ||||||
|  | 	int REACTORS_COUNT = 8; | ||||||
|  | 	int MAX_DATA_SIZE = DATA_SIZE * REACTORS_COUNT; | ||||||
|  |  | ||||||
| 	class EchoServiceHandler | 	class EchoServiceHandler | ||||||
| 	{ | 	{ | ||||||
| 	public: | 	public: | ||||||
| @@ -130,7 +134,7 @@ namespace | |||||||
| 				checkReadableObserverCount(1); | 				checkReadableObserverCount(1); | ||||||
| 				_reactor.removeEventHandler(_socket, Observer<ClientServiceHandler, ReadableNotification>(*this, &ClientServiceHandler::onReadable)); | 				_reactor.removeEventHandler(_socket, Observer<ClientServiceHandler, ReadableNotification>(*this, &ClientServiceHandler::onReadable)); | ||||||
| 				checkReadableObserverCount(0); | 				checkReadableObserverCount(0); | ||||||
| 				if (_once || _data.size() == 8192) | 				if (_once || _data.size() == MAX_DATA_SIZE) | ||||||
| 				{ | 				{ | ||||||
| 					_reactor.stop(); | 					_reactor.stop(); | ||||||
| 					delete this; | 					delete this; | ||||||
| @@ -144,7 +148,7 @@ namespace | |||||||
| 			checkWritableObserverCount(1); | 			checkWritableObserverCount(1); | ||||||
| 			_reactor.removeEventHandler(_socket, Observer<ClientServiceHandler, WritableNotification>(*this, &ClientServiceHandler::onWritable)); | 			_reactor.removeEventHandler(_socket, Observer<ClientServiceHandler, WritableNotification>(*this, &ClientServiceHandler::onWritable)); | ||||||
| 			checkWritableObserverCount(0); | 			checkWritableObserverCount(0); | ||||||
| 			std::string data(1024, 'x'); | 			std::string data(DATA_SIZE, 'x'); | ||||||
| 			_socket.sendBytes(data.data(), (int) data.length()); | 			_socket.sendBytes(data.data(), (int) data.length()); | ||||||
| 			_socket.shutdownSend(); | 			_socket.shutdownSend(); | ||||||
| 		} | 		} | ||||||
| @@ -405,7 +409,7 @@ void SocketReactorTest::testSocketReactor() | |||||||
| 	ClientServiceHandler::resetData(); | 	ClientServiceHandler::resetData(); | ||||||
| 	reactor.run(); | 	reactor.run(); | ||||||
| 	std::string data(ClientServiceHandler::data()); | 	std::string data(ClientServiceHandler::data()); | ||||||
| 	assertTrue (data.size() == 1024); | 	assertTrue (data.size() == DATA_SIZE); | ||||||
| 	assertTrue (!ClientServiceHandler::readableError()); | 	assertTrue (!ClientServiceHandler::readableError()); | ||||||
| 	assertTrue (!ClientServiceHandler::writableError()); | 	assertTrue (!ClientServiceHandler::writableError()); | ||||||
| 	assertTrue (!ClientServiceHandler::timeoutError()); | 	assertTrue (!ClientServiceHandler::timeoutError()); | ||||||
| @@ -425,7 +429,7 @@ void SocketReactorTest::testSetSocketReactor() | |||||||
| 	ClientServiceHandler::resetData(); | 	ClientServiceHandler::resetData(); | ||||||
| 	reactor.run(); | 	reactor.run(); | ||||||
| 	std::string data(ClientServiceHandler::data()); | 	std::string data(ClientServiceHandler::data()); | ||||||
| 	assertTrue (data.size() == 1024); | 	assertTrue (data.size() == DATA_SIZE); | ||||||
| 	assertTrue (!ClientServiceHandler::readableError()); | 	assertTrue (!ClientServiceHandler::readableError()); | ||||||
| 	assertTrue (!ClientServiceHandler::writableError()); | 	assertTrue (!ClientServiceHandler::writableError()); | ||||||
| 	assertTrue (!ClientServiceHandler::timeoutError()); | 	assertTrue (!ClientServiceHandler::timeoutError()); | ||||||
| @@ -434,27 +438,26 @@ void SocketReactorTest::testSetSocketReactor() | |||||||
|  |  | ||||||
| void SocketReactorTest::testParallelSocketReactor() | void SocketReactorTest::testParallelSocketReactor() | ||||||
| { | { | ||||||
| 	SocketAddress ssa; | 	SocketAddress ssa("127.0.0.1:22087"); | ||||||
| 	ServerSocket ss(ssa); | 	ServerSocket ss(ssa); | ||||||
| 	SocketReactor reactor; | 	SocketReactor reactor; | ||||||
| 	ParallelSocketAcceptor<EchoServiceHandler, SocketReactor> acceptor(ss, reactor); | 	ParallelSocketAcceptor<EchoServiceHandler, SocketReactor> acceptor(ss, reactor, REACTORS_COUNT); | ||||||
|  |  | ||||||
| 	SocketAddress sa("127.0.0.1", ss.address().port()); | 	SocketAddress sa("127.0.0.1", ss.address().port()); | ||||||
| 	SocketConnector<ClientServiceHandler> connector1(sa, reactor); | 	std::vector<SocketConnector<ClientServiceHandler>*> connectors; | ||||||
| 	SocketConnector<ClientServiceHandler> connector2(sa, reactor); | 	for (int i = 0; i < REACTORS_COUNT; ++i) | ||||||
| 	SocketConnector<ClientServiceHandler> connector3(sa, reactor); | 		connectors.push_back(new SocketConnector<ClientServiceHandler>(sa, reactor)); | ||||||
| 	SocketConnector<ClientServiceHandler> connector4(sa, reactor); |  | ||||||
| 	SocketConnector<ClientServiceHandler> connector5(sa, reactor); |  | ||||||
| 	SocketConnector<ClientServiceHandler> connector6(sa, reactor); |  | ||||||
| 	SocketConnector<ClientServiceHandler> connector7(sa, reactor); |  | ||||||
| 	SocketConnector<ClientServiceHandler> connector8(sa, reactor); |  | ||||||
| 	ClientServiceHandler::setOnce(false); | 	ClientServiceHandler::setOnce(false); | ||||||
| 	ClientServiceHandler::resetData(); | 	ClientServiceHandler::resetData(); | ||||||
| 	reactor.run(); | 	reactor.run(); | ||||||
|  |  | ||||||
| 	std::string data(ClientServiceHandler::data()); | 	std::string data(ClientServiceHandler::data()); | ||||||
| 	assertTrue (data.size() == 8192); | 	assertTrue (data.size() == MAX_DATA_SIZE); | ||||||
| 	assertTrue (!ClientServiceHandler::readableError()); | 	assertTrue (!ClientServiceHandler::readableError()); | ||||||
| 	assertTrue (!ClientServiceHandler::writableError()); | 	assertTrue (!ClientServiceHandler::writableError()); | ||||||
| 	assertTrue (!ClientServiceHandler::timeoutError()); | 	assertTrue (!ClientServiceHandler::timeoutError()); | ||||||
|  | 	for (auto& c : connectors) delete c; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user