fix(sharedMemory): x64 size error #2976 (#4295)

* fix(sharedMemory): x64 size error #2976

* chore: add Util dependency to Prometheus samples

* fix(HTTPClientSession): not working with UNIX_LOCAL SocketAddress #2578

* fix(WebSocketTest): supress connection reset exception assertion

* fix(PollSet): wait on premature epoll_wait return; reinforce tests for windows

* fix(build): add DataTest dependency to Makefile

* fix(Task): intermittently hanging test and some other improvements

* fix(Net): PollSet loop; suppress test WebSocket handler shutdown IOExeption
This commit is contained in:
Aleksandar Fabijanic 2023-11-26 04:57:39 +01:00 committed by GitHub
parent 70bb3a40de
commit 11de40399c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 244 additions and 104 deletions

View File

@ -74,11 +74,11 @@ private:
SharedMemoryImpl& operator = (const SharedMemoryImpl&);
std::string _name;
HANDLE _memHandle;
HANDLE _fileHandle;
DWORD _size;
DWORD _mode;
char* _address;
HANDLE _memHandle;
HANDLE _fileHandle;
std::size_t _size;
DWORD _mode;
char* _address;
};

View File

@ -107,7 +107,7 @@ protected:
/// A Task should use this method in favor of Thread::sleep().
bool yield();
/// Yields cpu to other threads
/// Yields cpu to other threads
///
/// If the task is cancelled while it is suspended,
/// yield() will return true. If the tasks resumes
@ -145,12 +145,12 @@ private:
Task(const Task&);
Task& operator = (const Task&);
std::string _name;
TaskManager* _pOwner;
float _progress;
std::string _name;
TaskManager* _pOwner;
std::atomic<float> _progress;
std::atomic<TaskState> _state;
Event _cancelEvent;
mutable FastMutex _mutex;
Event _cancelEvent;
mutable FastMutex _mutex;
friend class TaskManager;
};
@ -167,8 +167,6 @@ inline const std::string& Task::name() const
inline float Task::progress() const
{
FastMutex::ScopedLock lock(_mutex);
return _progress;
}

View File

@ -122,7 +122,7 @@ private:
TaskList _taskList;
Timestamp _lastProgressNotification;
NotificationCenter _nc;
mutable MutexT _mutex;
mutable MutexT _mutex;
friend class Task;
};

View File

@ -28,7 +28,7 @@ SharedMemoryImpl::SharedMemoryImpl(const std::string& name, std::size_t size, Sh
_name(name),
_memHandle(INVALID_HANDLE_VALUE),
_fileHandle(INVALID_HANDLE_VALUE),
_size(static_cast<DWORD>(size)),
_size(size),
_mode(PAGE_READONLY),
_address(0)
{
@ -37,22 +37,40 @@ SharedMemoryImpl::SharedMemoryImpl(const std::string& name, std::size_t size, Sh
std::wstring utf16name;
UnicodeConverter::toUTF16(_name, utf16name);
_memHandle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, _mode, 0, _size, utf16name.c_str());
#ifdef _WIN64
const DWORD dwMaxSizeLow = static_cast<DWORD>(_size & 0xFFFFFFFFULL);
const DWORD dwMaxSizeHigh = static_cast<DWORD>((_size & (0xFFFFFFFFULL << 32)) >> 32);
#else
if (_size > std::numeric_limits<DWORD>::max())
{
throw Poco::InvalidArgumentException(Poco::format("Requested shared memory size (%z) too large (max %lu)",
_size, std::numeric_limits<DWORD>::max()));
}
const DWORD dwMaxSizeLow = static_cast<DWORD>(_size);
const DWORD dwMaxSizeHigh = 0UL;
#endif
_memHandle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, _mode, dwMaxSizeHigh, dwMaxSizeLow, utf16name.c_str());
if (!_memHandle)
{
DWORD dwRetVal = GetLastError();
int retVal = static_cast<int>(dwRetVal);
#if defined (_WIN32_WCE)
throw SystemException(format("Cannot create shared memory object %s [Error %d: %s]", _name, static_cast<int>(dwRetVal), Error::getMessage(dwRetVal)));
throw SystemException(Poco::format("Cannot create shared memory object %s [Error %d: %s]",
_name, retVal, Error::getMessage(dwRetVal)));
#else
if (_mode != PAGE_READONLY || dwRetVal != 5)
throw SystemException(format("Cannot create shared memory object %s [Error %d: %s]", _name, static_cast<int>(dwRetVal), Error::getMessage(dwRetVal)));
{
throw SystemException(Poco::format("Cannot create shared memory object %s [Error %d: %s]",
_name, retVal, Error::getMessage(dwRetVal)), retVal);
}
_memHandle = OpenFileMappingW(PAGE_READONLY, FALSE, utf16name.c_str());
if (!_memHandle)
{
dwRetVal = GetLastError();
throw SystemException(format("Cannot open shared memory object %s [Error %d: %s]", _name, static_cast<int>(dwRetVal), Error::getMessage(dwRetVal)));
throw SystemException(Poco::format("Cannot open shared memory object %s [Error %d: %s]",
_name, retVal, Error::getMessage(dwRetVal)), retVal);
}
#endif
}

View File

@ -71,12 +71,12 @@ void Task::run()
catch (std::exception& exc)
{
if (pOwner)
pOwner->taskFailed(this, SystemException(exc.what()));
pOwner->taskFailed(this, SystemException("Task::run()", exc.what()));
}
catch (...)
{
if (pOwner)
pOwner->taskFailed(this, SystemException("unknown exception"));
pOwner->taskFailed(this, SystemException("Task::run(): unknown exception"));
}
_state = TASK_FINISHED;
if (pOwner) pOwner->taskFinished(this);
@ -98,11 +98,9 @@ bool Task::yield()
void Task::setProgress(float progress)
{
FastMutex::ScopedLock lock(_mutex);
if (_progress != progress)
if (_progress.exchange(progress) != progress)
{
_progress = progress;
FastMutex::ScopedLock lock(_mutex);
if (_pOwner)
_pOwner->taskProgress(this, _progress);
}
@ -112,7 +110,6 @@ void Task::setProgress(float progress)
void Task::setOwner(TaskManager* pOwner)
{
FastMutex::ScopedLock lock(_mutex);
_pOwner = pOwner;
}

View File

@ -72,6 +72,30 @@ Poco::Path SharedMemoryTest::findDataFile(const std::string& afile)
}
void SharedMemoryTest::testCreateLarge()
{
#if POCO_OS == POCO_OS_WINDOWS_NT
try
{
#ifdef _WIN64
const size_t size = 0x03FFFFFFFFULL;
#else
const size_t size = 0xDFFFFFFFUL;
#endif
SharedMemory mem("hiLarge", size, SharedMemory::AM_WRITE);
assertTrue((mem.end() - mem.begin()) == size);
mem.begin()[0] = 'A';
mem.end()[-1] = 'Z';
}
catch (Poco::SystemException& ex)
{
// no memory, quite posible to happen
assertEqual(ERROR_NOT_ENOUGH_MEMORY, ex.code());
}
#endif
}
void SharedMemoryTest::setUp()
{
}
@ -89,6 +113,7 @@ CppUnit::Test* SharedMemoryTest::suite()
#if !defined(POCO_NO_SHAREDMEMORY)
CppUnit_addTest(pSuite, SharedMemoryTest, testCreate);
CppUnit_addTest(pSuite, SharedMemoryTest, testCreateFromFile);
CppUnit_addTest(pSuite, SharedMemoryTest, testCreateLarge);
#endif
return pSuite;
}

View File

@ -27,6 +27,7 @@ public:
void testCreate();
void testCreateFromFile();
void testCreateLarge();
void setUp();
void tearDown();

View File

@ -35,42 +35,42 @@ namespace
void runTask()
{
try
{
_event.wait();
if (sleep(10))
return;
setProgress(0.5);
_event.wait();
if (isCancelled())
return;
setProgress(1.0);
_event.wait();
}
catch(const Poco::Exception& e)
{
std::cerr << "TestTask::run(): " << e.displayText() << '\n';
}
catch(const std::exception& e)
{
std::cerr << "TestTask::run(): " << e.what() << '\n';
}
catch(...)
{
std::cerr << "TestTask::run(): unknown exception." << '\n';
}
try
{
_event.wait();
if (sleep(100))
return;
setProgress(0.5);
_event.wait();
if (isCancelled())
return;
setProgress(1.0);
_event.wait();
}
catch(const Poco::Exception& e)
{
std::cerr << "TestTask::run(): " << e.displayText() << '\n';
}
catch(const std::exception& e)
{
std::cerr << "TestTask::run(): " << e.what() << '\n';
}
catch(...)
{
std::cerr << "TestTask::run(): unknown exception." << '\n';
}
}
void cont()
{
try
{
_event.set();
}
catch(const Poco::SystemException& e)
{
std::cerr << "TestTask::cont(): " << e.displayText() << '\n';
}
try
{
_event.set();
}
catch(const Poco::SystemException& e)
{
std::cerr << "TestTask::cont(): " << e.displayText() << '\n';
}
}
private:
@ -131,6 +131,8 @@ void TaskTest::testCancel2()
assertTrue (pTT->state() == Task::TASK_IDLE);
Thread thr;
thr.start(*pTT);
while (pTT->state() != Task::TASK_RUNNING)
Thread::sleep(50);
assertTrue (pTT->progress() == 0);
pTT->cancel();
assertTrue (pTT->state() == Task::TASK_CANCELLING);

View File

@ -246,7 +246,10 @@ NetSSL_OpenSSL-clean:
Data-libexec: Foundation-libexec
$(MAKE) -C $(POCO_BASE)/Data
Data-tests: Data-libexec cppunit
DataTest-libexec: Data-libexec
$(MAKE) -C $(POCO_BASE)/Data/testsuite/DataTest
Data-tests: Data-libexec DataTest-libexec cppunit
$(MAKE) -C $(POCO_BASE)/Data/testsuite
Data-samples: Data-libexec Data-libexec Data/SQLite-libexec Net-libexec
@ -260,7 +263,7 @@ Data-clean:
Data/SQLite-libexec: Foundation-libexec Data-libexec
$(MAKE) -C $(POCO_BASE)/Data/SQLite
Data/SQLite-tests: Data/SQLite-libexec cppunit
Data/SQLite-tests: Data/SQLite-libexec DataTest-libexec cppunit
$(MAKE) -C $(POCO_BASE)/Data/SQLite/testsuite
Data/SQLite-clean:
@ -270,7 +273,7 @@ Data/SQLite-clean:
Data/ODBC-libexec: Foundation-libexec Data-libexec
$(MAKE) -C $(POCO_BASE)/Data/ODBC
Data/ODBC-tests: Data/ODBC-libexec cppunit
Data/ODBC-tests: Data/ODBC-libexec DataTest-libexec cppunit
$(MAKE) -C $(POCO_BASE)/Data/ODBC/testsuite
Data/ODBC-clean:
@ -280,7 +283,7 @@ Data/ODBC-clean:
Data/MySQL-libexec: Foundation-libexec Data-libexec
$(MAKE) -C $(POCO_BASE)/Data/MySQL
Data/MySQL-tests: Data/MySQL-libexec cppunit
Data/MySQL-tests: Data/MySQL-libexec DataTest-libexec cppunit
$(MAKE) -C $(POCO_BASE)/Data/MySQL/testsuite
Data/MySQL-clean:
@ -290,7 +293,7 @@ Data/MySQL-clean:
Data/PostgreSQL-libexec: Foundation-libexec Data-libexec
$(MAKE) -C $(POCO_BASE)/Data/PostgreSQL
Data/PostgreSQL-tests: Data/PostgreSQL-libexec cppunit
Data/PostgreSQL-tests: Data/PostgreSQL-libexec DataTest-libexec cppunit
$(MAKE) -C $(POCO_BASE)/Data/PostgreSQL/testsuite
Data/PostgreSQL-clean:
@ -407,7 +410,7 @@ Prometheus-libexec: Foundation-libexec Net-libexec
Prometheus-tests: Prometheus-libexec cppunit
$(MAKE) -C $(POCO_BASE)/Prometheus/testsuite
Prometheus-samples: Prometheus-libexec
Prometheus-samples: Prometheus-libexec Util-libexec
$(MAKE) -C $(POCO_BASE)/Prometheus/samples
Prometheus-clean:

View File

@ -384,7 +384,7 @@ private:
HTTPBasicCredentials _proxyBasicCreds;
HTTPDigestCredentials _proxyDigestCreds;
HTTPNTLMCredentials _proxyNTLMCreds;
bool _ntlmProxyAuthenticated;
bool _ntlmProxyAuthenticated = false;
static ProxyConfig _globalProxyConfig;

View File

@ -208,6 +208,9 @@ public:
/// Maximum length in bytes of a socket address.
};
static bool isUnixLocal(const std::string& hostAndPort);
/// Returns true iff `hostAndPort` is an absolute file path.
protected:
void init(const IPAddress& hostAddress, Poco::UInt16 portNumber);
void init(const std::string& hostAddress, Poco::UInt16 portNumber);

View File

@ -459,7 +459,12 @@ void HTTPClientSession::reconnect()
{
SocketAddress addr;
if (_proxyConfig.host.empty() || bypassProxy())
addr = SocketAddress(_host, _port);
{
if (SocketAddress::isUnixLocal(_host))
addr = SocketAddress(_host);
else
addr = SocketAddress(_host, _port);
}
else
addr = SocketAddress(_proxyConfig.host, _proxyConfig.port);

View File

@ -196,7 +196,8 @@ void HTTPSession::connect(const SocketAddress& address)
_socket.connect(address, _connectionTimeout);
_socket.setReceiveTimeout(_receiveTimeout);
_socket.setSendTimeout(_sendTimeout);
_socket.setNoDelay(true);
if (address.family() != SocketAddress::UNIX_LOCAL)
_socket.setNoDelay(true);
// There may be leftover data from a previous (failed) request in the buffer,
// so we clear it.
_pCurrent = _pEnd = _pBuffer;

View File

@ -171,12 +171,16 @@ public:
Poco::Timespan remainingTime(timeout);
int rc;
do
while (true)
{
Poco::Timestamp start;
rc = epoll_wait(_epollfd, &_events[0],
static_cast<int>(_events.size()), static_cast<int>(remainingTime.totalMilliseconds()));
if (rc == 0) return result;
if (rc == 0)
{
if (keepWaiting(start, remainingTime)) continue;
return result;
}
// if we are hitting the events limit, resize it; even without resizing, the subseqent
// calls would round-robin through the remaining ready sockets, but it's better to give
@ -187,18 +191,12 @@ public:
// if interrupted and there's still time left, keep waiting
if (SocketImpl::lastError() == POCO_EINTR)
{
Poco::Timestamp end;
Poco::Timespan waited = end - start;
if (waited < remainingTime)
{
remainingTime -= waited;
continue;
}
if (keepWaiting(start, remainingTime)) continue;
}
else SocketImpl::error();
}
break;
}
while (false);
ScopedLock lock(_mutex);
@ -304,6 +302,18 @@ private:
return epoll_ctl(_epollfd, op, fd, &ev);
}
static bool keepWaiting(const Poco::Timestamp& start, Poco::Timespan& remainingTime)
{
Poco::Timestamp end;
Poco::Timespan waited = end - start;
if (waited < remainingTime)
{
remainingTime -= waited;
return true;
}
return false;
}
#ifndef WEPOLL_H_
using EPollHandle = std::atomic<int>;
#else // WEPOLL_H_

View File

@ -79,7 +79,7 @@ SocketAddress::SocketAddress()
SocketAddress::SocketAddress(Family fam)
{
init(IPAddress(fam), 0);
init(IPAddress(fam), 0);
}
@ -362,31 +362,34 @@ void SocketAddress::init(Family fam, const std::string& address)
}
bool SocketAddress::isUnixLocal(const std::string& hostAndPort)
{
#if defined(POCO_HAS_UNIX_SOCKET)
#if defined(POCO_OS_FAMILY_WINDOWS)
RegularExpression re(R"((?:[a-zA-Z]\:|\\\\[\w\s\.]+\\[\w\s\.$]+)\\(?:[\w\s\.]+\\)*[\w\s\.]*?$)");
if (re.match(hostAndPort)) return true;
#elif defined(POCO_OS_FAMILY_UNIX)
if (hostAndPort.size() && (hostAndPort[0] == '/')) return true;
#endif
#endif
return false;
}
void SocketAddress::init(const std::string& hostAndPort)
{
poco_assert (!hostAndPort.empty());
#if defined(POCO_OS_FAMILY_WINDOWS) && defined(POCO_HAS_UNIX_SOCKET)
RegularExpression re(R"((?:[a-zA-Z]\:|\\\\[\w\s\.]+\\[\w\s\.$]+)\\(?:[\w\s\.]+\\)*[\w\s\.]*?$)");
if (re.match(hostAndPort))
if (isUnixLocal(hostAndPort))
{
newLocal(hostAndPort);
return;
}
#endif
std::string host;
std::string port;
std::string::const_iterator it = hostAndPort.begin();
std::string::const_iterator end = hostAndPort.end();
#if defined(POCO_OS_FAMILY_UNIX)
if (*it == '/')
{
newLocal(hostAndPort);
return;
}
#endif
if (*it == '[')
{
++it;

View File

@ -83,8 +83,10 @@ void EchoServer::run()
{
std::cerr << "EchoServer: " << exc.displayText() << std::endl;
}
ss.close();
}
}
_socket.close();
_done = true;
}
@ -99,4 +101,3 @@ bool EchoServer::done()
{
return _done;
}

View File

@ -15,6 +15,8 @@
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/StreamCopier.h"
#include "Poco/File.h"
#include "Poco/Path.h"
#include "HTTPTestServer.h"
#include <istream>
#include <ostream>
@ -26,6 +28,8 @@ using Poco::Net::HTTPRequest;
using Poco::Net::HTTPResponse;
using Poco::Net::HTTPMessage;
using Poco::StreamCopier;
using Poco::File;
using Poco::Path;
HTTPClientSessionTest::HTTPClientSessionTest(const std::string& name): CppUnit::TestCase(name)
@ -54,6 +58,32 @@ void HTTPClientSessionTest::testGetSmall()
}
void HTTPClientSessionTest::testGetSmallUnix()
{
#if defined(POCO_HAS_UNIX_SOCKET)
#if POCO_OS == POCO_OS_ANDROID
File socketFile("/data/local/tmp/SocketTest.sock");
#elif defined(POCO_OS_FAMILY_WINDOWS)
File socketFile(Path::tempHome() + "SocketTest.sock");
#else
File socketFile("/tmp/SocketTest.sock");
#endif // POCO_OS == POCO_OS_ANDROID
if (socketFile.exists()) socketFile.remove();
HTTPTestServer srv(socketFile.path());
HTTPClientSession s(socketFile.path());
HTTPRequest request(HTTPRequest::HTTP_GET, "/small");
s.sendRequest(request);
HTTPResponse response;
std::istream& rs = s.receiveResponse(response);
assertTrue(response.getContentLength() == HTTPTestServer::SMALL_BODY.length());
assertTrue(response.getContentType() == "text/plain");
std::ostringstream ostr;
StreamCopier::copyStream(rs, ostr);
assertTrue(ostr.str() == HTTPTestServer::SMALL_BODY);
#endif // POCO_HAS_UNIX_SOCKET
}
void HTTPClientSessionTest::testGetLarge()
{
HTTPTestServer srv;
@ -373,6 +403,7 @@ CppUnit::Test* HTTPClientSessionTest::suite()
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("HTTPClientSessionTest");
CppUnit_addTest(pSuite, HTTPClientSessionTest, testGetSmall);
CppUnit_addTest(pSuite, HTTPClientSessionTest, testGetSmallUnix);
CppUnit_addTest(pSuite, HTTPClientSessionTest, testGetLarge);
CppUnit_addTest(pSuite, HTTPClientSessionTest, testHead);
CppUnit_addTest(pSuite, HTTPClientSessionTest, testPostSmallIdentity);

View File

@ -25,6 +25,7 @@ public:
~HTTPClientSessionTest();
void testGetSmall();
void testGetSmallUnix();
void testGetLarge();
void testHead();
void testPostSmallIdentity();

View File

@ -37,6 +37,17 @@ HTTPTestServer::HTTPTestServer():
}
HTTPTestServer::HTTPTestServer(const std::string& addr) :
_socket(SocketAddress(addr)),
_thread("HTTPTestServer"),
_stop(false)
{
_thread.start(*this);
_ready.wait();
_lastRequest.reserve(4000);
}
HTTPTestServer::~HTTPTestServer()
{
_stop = true;
@ -74,13 +85,15 @@ void HTTPTestServer::run()
{
_lastRequest.append(buffer, n);
if (!requestComplete())
{
n = ss.receiveBytes(buffer, sizeof(buffer));
}
else
n = 0;
}
std::string response = handleRequest();
ss.sendBytes(response.data(), (int) response.size());
Poco::Thread::sleep(1000);
n = ss.sendBytes(response.data(), (int) response.size());
if (n) Poco::Thread::sleep(1000);
try
{
ss.shutdown();

View File

@ -27,6 +27,9 @@ public:
HTTPTestServer();
/// Creates the HTTPTestServer.
HTTPTestServer(const std::string& addr);
/// Creates the HTTPTestServer on the specified address.
~HTTPTestServer();
/// Destroys the HTTPTestServer.

View File

@ -404,9 +404,19 @@ void PollSetTest::testPollClosedServer()
"waiting on server after %ds", secs), __LINE__);
}
}
char buffer[5];
int n = ss1.receiveBytes(buffer, sizeof(buffer));
assertTrue(n == 0);
auto smm = ps.poll(Timespan(1000000));
assertEqual(1, smm.size());
assertTrue(ss1 == smm.begin()->first);
ps.remove(ss1);
assertTrue(!ps.empty());
assertTrue(!ps.has(ss1));
assertTrue(ps.has(ss2));
echoServer2.stop();
assertTrue (len == ss2.sendBytes(str.data(), len));
sw.restart();
while (!echoServer2.done())
{
Thread::sleep(10);
@ -417,8 +427,11 @@ void PollSetTest::testPollClosedServer()
"waiting on server after %ds", secs), __LINE__);
}
}
assertEqual(2, ps.poll(Timespan(1000000)).size());
n = ss2.receiveBytes(buffer, sizeof(buffer));
assertTrue(n == 0);
smm = ps.poll(Timespan(1000000));
assertEqual(1, smm.size());
assertTrue(ss2 == smm.begin()->first);
// socket closed or error
assertTrue(0 >= ss1.receiveBytes(0, 0));

View File

@ -562,8 +562,10 @@ void SocketTest::testEchoUnixLocal()
if (socketFile.exists()) socketFile.remove();
echoServer.stop();
#else // POCO_HAS_UNIX_SOCKET
#pragma message("[UNIX LOCAL SOCKET DISABLED]")
std::cout << "[UNIX LOCAL SOCKET DISABLED]" << std::endl;
#if POCO_OS == POCO_OS_WINDOWS_NT
#pragma message("[UNIX LOCAL SOCKET DISABLED]")
#endif
std::cout << "[UNIX LOCAL SOCKET DISABLED]";
#endif
}
@ -588,8 +590,10 @@ void SocketTest::testUnixLocalAbstract()
ss.close();
echoServer.stop();
#else // POCO_HAS_UNIX_SOCKET
#pragma message("[ABSTRACT UNIX LOCAL SOCKET DISABLED]")
std::cout << "[ABSTRACT UNIX LOCAL SOCKET DISABLED]" << std::endl;
#if POCO_OS == POCO_OS_WINDOWS_NT
#pragma message("[ABSTRACT UNIX LOCAL SOCKET DISABLED]")
#endif
std::cout << "[ABSTRACT UNIX LOCAL SOCKET DISABLED]";
#endif
}

View File

@ -53,10 +53,10 @@ private:
void onReadable(bool& b);
void onWritable(bool& b);
int _readableToNot;
int _notToReadable;
int _writableToNot;
int _notToWritable;
int _readableToNot = 0;
int _notToReadable = 0;
int _writableToNot = 0;
int _notToWritable = 0;
};

View File

@ -34,6 +34,8 @@ using Poco::Net::HTTPServerResponse;
using Poco::Net::SocketStream;
using Poco::Net::WebSocket;
using Poco::Net::WebSocketException;
using Poco::Net::ConnectionAbortedException;
using Poco::IOException;
namespace
@ -76,6 +78,12 @@ namespace
break;
}
}
catch (ConnectionAbortedException&)
{
}
catch (IOException&)
{
}
}
private: