mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2026-08-25 17:17:11 +02:00
Update POCO library.
This commit is contained in:
Vendored
+1
-1
@@ -117,7 +117,7 @@ HostEntry DNS::hostByAddress(const IPAddress& address, unsigned
|
||||
|
||||
#if defined(POCO_HAVE_ADDRINFO)
|
||||
SocketAddress sa(address, 0);
|
||||
static char fqname[1024];
|
||||
char fqname[1024];
|
||||
int rc = getnameinfo(sa.addr(), sa.length(), fqname, sizeof(fqname), NULL, 0, NI_NAMEREQD);
|
||||
if (rc == 0)
|
||||
{
|
||||
|
||||
+54
-8
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
DatagramSocket::DatagramSocket(const SocketAddress& address, bool reuseAddress, bool reusePort): Socket(new DatagramSocketImpl(address.family()))
|
||||
{
|
||||
bind(address, reuseAddress, reusePort);
|
||||
if (address.family() == SocketAddress::IPv6)
|
||||
bind6(address, reuseAddress, reusePort, ipV6Only);
|
||||
else 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)
|
||||
{
|
||||
if (!dynamic_cast<DatagramSocketImpl*>(impl()))
|
||||
@@ -74,6 +76,44 @@ DatagramSocket& DatagramSocket::operator = (const Socket& socket)
|
||||
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)
|
||||
{
|
||||
@@ -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)
|
||||
{
|
||||
return impl()->sendBytes(buffer, length, flags);
|
||||
|
||||
+10
-4
@@ -28,10 +28,11 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
FTPClientSession::FTPClientSession():
|
||||
FTPClientSession::FTPClientSession(Poco::UInt16 activeDataPort):
|
||||
_pControlSocket(0),
|
||||
_pDataStream(0),
|
||||
_port(FTP_PORT),
|
||||
_activeDataPort(activeDataPort),
|
||||
_passiveMode(true),
|
||||
_fileType(TYPE_BINARY),
|
||||
_supports1738(true),
|
||||
@@ -42,11 +43,14 @@ FTPClientSession::FTPClientSession():
|
||||
}
|
||||
|
||||
|
||||
FTPClientSession::FTPClientSession(const StreamSocket& socket, bool readWelcomeMessage):
|
||||
FTPClientSession::FTPClientSession(const StreamSocket& socket,
|
||||
bool readWelcomeMessage,
|
||||
Poco::UInt16 activeDataPort):
|
||||
_pControlSocket(new DialogSocket(socket)),
|
||||
_pDataStream(0),
|
||||
_host(socket.address().host().toString()),
|
||||
_port(socket.address().port()),
|
||||
_activeDataPort(activeDataPort),
|
||||
_passiveMode(true),
|
||||
_fileType(TYPE_BINARY),
|
||||
_supports1738(true),
|
||||
@@ -69,11 +73,13 @@ FTPClientSession::FTPClientSession(const StreamSocket& socket, bool readWelcomeM
|
||||
FTPClientSession::FTPClientSession(const std::string& host,
|
||||
Poco::UInt16 port,
|
||||
const std::string& username,
|
||||
const std::string& password):
|
||||
const std::string& password,
|
||||
Poco::UInt16 activeDataPort):
|
||||
_pControlSocket(new DialogSocket(SocketAddress(host, port))),
|
||||
_pDataStream(0),
|
||||
_host(host),
|
||||
_port(port),
|
||||
_activeDataPort(activeDataPort),
|
||||
_passiveMode(true),
|
||||
_fileType(TYPE_BINARY),
|
||||
_supports1738(true),
|
||||
@@ -452,7 +458,7 @@ StreamSocket FTPClientSession::activeDataConnection(const std::string& command,
|
||||
if (!isOpen())
|
||||
throw FTPException("Connection is closed.");
|
||||
|
||||
ServerSocket server(SocketAddress(_pControlSocket->address().host(), 0));
|
||||
ServerSocket server(SocketAddress(_pControlSocket->address().host(), _activeDataPort));
|
||||
sendPortCommand(server.address());
|
||||
std::string response;
|
||||
int status = sendCommand(command, arg, response);
|
||||
|
||||
+13
-13
@@ -41,17 +41,17 @@ public:
|
||||
// make sure exceptions from underlying string propagate
|
||||
_istr.exceptions(std::ios::badbit);
|
||||
}
|
||||
|
||||
|
||||
~FTPStreamBuf()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
int readFromDevice()
|
||||
{
|
||||
return _istr.get();
|
||||
}
|
||||
|
||||
|
||||
std::istream& _istr;
|
||||
};
|
||||
|
||||
@@ -64,11 +64,11 @@ public:
|
||||
{
|
||||
poco_ios_init(&_buf);
|
||||
}
|
||||
|
||||
|
||||
~FTPIOS()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FTPStreamBuf* rdbuf()
|
||||
{
|
||||
return &_buf;
|
||||
@@ -88,12 +88,12 @@ public:
|
||||
_pSession(pSession)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~FTPStream()
|
||||
{
|
||||
delete _pSession;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
FTPClientSession* _pSession;
|
||||
};
|
||||
@@ -133,15 +133,15 @@ std::istream* FTPStreamFactory::open(const URI& uri)
|
||||
std::string username;
|
||||
std::string password;
|
||||
getUserInfo(uri, username, password);
|
||||
|
||||
|
||||
std::string path;
|
||||
char type;
|
||||
getPathAndType(uri, path, type);
|
||||
|
||||
|
||||
pSession->login(username, password);
|
||||
if (type == 'a')
|
||||
pSession->setFileType(FTPClientSession::TYPE_TEXT);
|
||||
|
||||
|
||||
Path p(path, Path::PATH_UNIX);
|
||||
p.makeFile();
|
||||
for (int i = 0; i < p.depth(); ++i)
|
||||
@@ -163,19 +163,19 @@ void FTPStreamFactory::setAnonymousPassword(const std::string& password)
|
||||
_anonymousPassword = password;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::string& FTPStreamFactory::getAnonymousPassword()
|
||||
{
|
||||
return _anonymousPassword;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FTPStreamFactory::setPasswordProvider(FTPPasswordProvider* pProvider)
|
||||
{
|
||||
_pPasswordProvider = pProvider;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FTPPasswordProvider* FTPStreamFactory::getPasswordProvider()
|
||||
{
|
||||
return _pPasswordProvider;
|
||||
|
||||
+47
-12
@@ -13,6 +13,7 @@
|
||||
|
||||
|
||||
#include "Poco/Net/HTTPChunkedStream.h"
|
||||
#include "Poco/Net/HTTPStream.h"
|
||||
#include "Poco/Net/HTTPSession.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include "Poco/NumberParser.h"
|
||||
@@ -32,11 +33,12 @@ namespace Net {
|
||||
//
|
||||
|
||||
|
||||
HTTPChunkedStreamBuf::HTTPChunkedStreamBuf(HTTPSession& session, openmode mode):
|
||||
HTTPChunkedStreamBuf::HTTPChunkedStreamBuf(HTTPSession& session, openmode mode, MessageHeader* pTrailer):
|
||||
HTTPBasicStreamBuf(HTTPBufferAllocator::BUFFER_SIZE, mode),
|
||||
_session(session),
|
||||
_mode(mode),
|
||||
_chunk(0)
|
||||
_chunk(0),
|
||||
_pTrailer(pTrailer)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -51,7 +53,16 @@ void HTTPChunkedStreamBuf::close()
|
||||
if (_mode & std::ios::out)
|
||||
{
|
||||
sync();
|
||||
_session.write("0\r\n\r\n", 5);
|
||||
_session.write("0\r\n", 3);
|
||||
if (_pTrailer && !_pTrailer->empty())
|
||||
{
|
||||
HTTPOutputStream hos(_session);
|
||||
_pTrailer->write(hos);
|
||||
}
|
||||
else
|
||||
{
|
||||
_session.write("\r\n", 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,9 +81,14 @@ int HTTPChunkedStreamBuf::readFromDevice(char* buffer, std::streamsize length)
|
||||
while (ch != eof && ch != '\n') ch = _session.get();
|
||||
unsigned chunk;
|
||||
if (NumberParser::tryParseHex(chunkLen, chunk))
|
||||
{
|
||||
_chunk = (std::streamsize) chunk;
|
||||
}
|
||||
else
|
||||
{
|
||||
_chunk = -1;
|
||||
return eof;
|
||||
}
|
||||
}
|
||||
if (_chunk > 0)
|
||||
{
|
||||
@@ -81,12 +97,31 @@ int HTTPChunkedStreamBuf::readFromDevice(char* buffer, std::streamsize length)
|
||||
if (n > 0) _chunk -= n;
|
||||
return n;
|
||||
}
|
||||
else
|
||||
else if (_chunk == 0)
|
||||
{
|
||||
int ch = _session.get();
|
||||
while (ch != eof && ch != '\n') ch = _session.get();
|
||||
int ch = _session.peek();
|
||||
if (ch != eof && ch != '\r' && ch != '\n')
|
||||
{
|
||||
HTTPInputStream his(_session);
|
||||
if (_pTrailer)
|
||||
{
|
||||
_pTrailer->read(his);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageHeader trailer;
|
||||
trailer.read(his);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = _session.get();
|
||||
while (ch != eof && ch != '\n') ch = _session.get();
|
||||
}
|
||||
_chunk = -1;
|
||||
return 0;
|
||||
}
|
||||
else return eof;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,8 +142,8 @@ int HTTPChunkedStreamBuf::writeToDevice(const char* buffer, std::streamsize leng
|
||||
//
|
||||
|
||||
|
||||
HTTPChunkedIOS::HTTPChunkedIOS(HTTPSession& session, HTTPChunkedStreamBuf::openmode mode):
|
||||
_buf(session, mode)
|
||||
HTTPChunkedIOS::HTTPChunkedIOS(HTTPSession& session, HTTPChunkedStreamBuf::openmode mode, MessageHeader* pTrailer):
|
||||
_buf(session, mode, pTrailer)
|
||||
{
|
||||
poco_ios_init(&_buf);
|
||||
}
|
||||
@@ -140,8 +175,8 @@ HTTPChunkedStreamBuf* HTTPChunkedIOS::rdbuf()
|
||||
Poco::MemoryPool HTTPChunkedInputStream::_pool(sizeof(HTTPChunkedInputStream));
|
||||
|
||||
|
||||
HTTPChunkedInputStream::HTTPChunkedInputStream(HTTPSession& session):
|
||||
HTTPChunkedIOS(session, std::ios::in),
|
||||
HTTPChunkedInputStream::HTTPChunkedInputStream(HTTPSession& session, MessageHeader* pTrailer):
|
||||
HTTPChunkedIOS(session, std::ios::in, pTrailer),
|
||||
std::istream(&_buf)
|
||||
{
|
||||
}
|
||||
@@ -179,8 +214,8 @@ void HTTPChunkedInputStream::operator delete(void* ptr)
|
||||
Poco::MemoryPool HTTPChunkedOutputStream::_pool(sizeof(HTTPChunkedOutputStream));
|
||||
|
||||
|
||||
HTTPChunkedOutputStream::HTTPChunkedOutputStream(HTTPSession& session):
|
||||
HTTPChunkedIOS(session, std::ios::out),
|
||||
HTTPChunkedOutputStream::HTTPChunkedOutputStream(HTTPSession& session, MessageHeader* pTrailer):
|
||||
HTTPChunkedIOS(session, std::ios::out, pTrailer),
|
||||
std::ostream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
+70
-9
@@ -40,6 +40,8 @@ HTTPClientSession::ProxyConfig HTTPClientSession::_globalProxyConfig;
|
||||
|
||||
HTTPClientSession::HTTPClientSession():
|
||||
_port(HTTPSession::HTTP_PORT),
|
||||
_sourceAddress4(IPAddress::wildcard(IPAddress::IPv4), 0),
|
||||
_sourceAddress6(IPAddress::wildcard(IPAddress::IPv6), 0),
|
||||
_proxyConfig(_globalProxyConfig),
|
||||
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
|
||||
_reconnect(false),
|
||||
@@ -54,6 +56,8 @@ HTTPClientSession::HTTPClientSession():
|
||||
HTTPClientSession::HTTPClientSession(const StreamSocket& socket):
|
||||
HTTPSession(socket),
|
||||
_port(HTTPSession::HTTP_PORT),
|
||||
_sourceAddress4(IPAddress::wildcard(IPAddress::IPv4), 0),
|
||||
_sourceAddress6(IPAddress::wildcard(IPAddress::IPv6), 0),
|
||||
_proxyConfig(_globalProxyConfig),
|
||||
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
|
||||
_reconnect(false),
|
||||
@@ -68,6 +72,8 @@ HTTPClientSession::HTTPClientSession(const StreamSocket& socket):
|
||||
HTTPClientSession::HTTPClientSession(const SocketAddress& address):
|
||||
_host(address.host().toString()),
|
||||
_port(address.port()),
|
||||
_sourceAddress4(IPAddress::wildcard(IPAddress::IPv4), 0),
|
||||
_sourceAddress6(IPAddress::wildcard(IPAddress::IPv6), 0),
|
||||
_proxyConfig(_globalProxyConfig),
|
||||
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
|
||||
_reconnect(false),
|
||||
@@ -82,6 +88,8 @@ HTTPClientSession::HTTPClientSession(const SocketAddress& address):
|
||||
HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port):
|
||||
_host(host),
|
||||
_port(port),
|
||||
_sourceAddress4(IPAddress::wildcard(IPAddress::IPv4), 0),
|
||||
_sourceAddress6(IPAddress::wildcard(IPAddress::IPv6), 0),
|
||||
_proxyConfig(_globalProxyConfig),
|
||||
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
|
||||
_reconnect(false),
|
||||
@@ -107,6 +115,21 @@ HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port,
|
||||
}
|
||||
|
||||
|
||||
HTTPClientSession::HTTPClientSession(const StreamSocket& socket, const ProxyConfig& proxyConfig):
|
||||
HTTPSession(socket),
|
||||
_port(HTTPSession::HTTP_PORT),
|
||||
_sourceAddress4(IPAddress::wildcard(IPAddress::IPv4), 0),
|
||||
_sourceAddress6(IPAddress::wildcard(IPAddress::IPv6), 0),
|
||||
_proxyConfig(proxyConfig),
|
||||
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
|
||||
_reconnect(false),
|
||||
_mustReconnect(false),
|
||||
_expectResponseBody(false),
|
||||
_responseReceived(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HTTPClientSession::~HTTPClientSession()
|
||||
{
|
||||
}
|
||||
@@ -130,6 +153,39 @@ void HTTPClientSession::setPort(Poco::UInt16 port)
|
||||
}
|
||||
|
||||
|
||||
void HTTPClientSession::setSourceAddress(const SocketAddress& address)
|
||||
{
|
||||
if (!connected())
|
||||
{
|
||||
if (address.family() == IPAddress::IPv4)
|
||||
_sourceAddress4 = address;
|
||||
else
|
||||
_sourceAddress6 = address;
|
||||
_sourceAddress = address;
|
||||
}
|
||||
else
|
||||
throw IllegalStateException("Cannot set the source address for an already connected session");
|
||||
}
|
||||
|
||||
|
||||
const SocketAddress& HTTPClientSession::getSourceAddress()
|
||||
{
|
||||
return _sourceAddress;
|
||||
}
|
||||
|
||||
|
||||
const SocketAddress& HTTPClientSession::getSourceAddress4()
|
||||
{
|
||||
return _sourceAddress4;
|
||||
}
|
||||
|
||||
|
||||
const SocketAddress& HTTPClientSession::getSourceAddress6()
|
||||
{
|
||||
return _sourceAddress6;
|
||||
}
|
||||
|
||||
|
||||
void HTTPClientSession::setProxy(const std::string& host, Poco::UInt16 port)
|
||||
{
|
||||
if (!connected())
|
||||
@@ -253,7 +309,7 @@ std::ostream& HTTPClientSession::sendRequestImpl(const HTTPRequest& request)
|
||||
{
|
||||
HTTPHeaderOutputStream hos(*this);
|
||||
request.write(hos);
|
||||
_pRequestStream = new HTTPChunkedOutputStream(*this);
|
||||
_pRequestStream = new HTTPChunkedOutputStream(*this, &requestTrailer());
|
||||
}
|
||||
else if (request.hasContentLength())
|
||||
{
|
||||
@@ -293,6 +349,7 @@ void HTTPClientSession::flushRequest()
|
||||
std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
|
||||
{
|
||||
flushRequest();
|
||||
responseTrailer().clear();
|
||||
if (!_responseReceived)
|
||||
{
|
||||
do
|
||||
@@ -320,7 +377,7 @@ std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
|
||||
if (!_expectResponseBody || response.getStatus() < 200 || response.getStatus() == HTTPResponse::HTTP_NO_CONTENT || response.getStatus() == HTTPResponse::HTTP_NOT_MODIFIED)
|
||||
_pResponseStream = new HTTPFixedLengthInputStream(*this, 0);
|
||||
else if (response.getChunkedTransferEncoding())
|
||||
_pResponseStream = new HTTPChunkedInputStream(*this);
|
||||
_pResponseStream = new HTTPChunkedInputStream(*this, &responseTrailer());
|
||||
else if (response.hasContentLength())
|
||||
#if defined(POCO_HAVE_INT64)
|
||||
_pResponseStream = new HTTPFixedLengthInputStream(*this, response.getContentLength64());
|
||||
@@ -400,16 +457,18 @@ int HTTPClientSession::write(const char* buffer, std::streamsize length)
|
||||
|
||||
void HTTPClientSession::reconnect()
|
||||
{
|
||||
SocketAddress addr;
|
||||
if (_proxyConfig.host.empty() || bypassProxy())
|
||||
{
|
||||
SocketAddress addr(_host, _port);
|
||||
connect(addr);
|
||||
}
|
||||
addr = SocketAddress(_host, _port);
|
||||
else
|
||||
addr = SocketAddress(_proxyConfig.host, _proxyConfig.port);
|
||||
|
||||
if ((!_sourceAddress4.host().isWildcard()) || (_sourceAddress4.port() != 0))
|
||||
connect(addr, _sourceAddress4);
|
||||
else if ((!_sourceAddress6.host().isWildcard()) || (_sourceAddress6.port() != 0))
|
||||
connect(addr, _sourceAddress6);
|
||||
else
|
||||
{
|
||||
SocketAddress addr(_proxyConfig.host, _proxyConfig.port);
|
||||
connect(addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -536,6 +595,8 @@ StreamSocket HTTPClientSession::proxyConnect()
|
||||
proxyRequest.set(HTTPRequest::HOST, getHost());
|
||||
proxySession.proxyAuthenticateImpl(proxyRequest, _proxyConfig);
|
||||
proxySession.setKeepAlive(true);
|
||||
proxySession.setSourceAddress(_sourceAddress4);
|
||||
proxySession.setSourceAddress(_sourceAddress6);
|
||||
proxySession.sendRequest(proxyRequest);
|
||||
proxySession.receiveResponse(proxyResponse);
|
||||
if (proxyResponse.getStatus() != HTTPResponse::HTTP_OK)
|
||||
|
||||
+118
-13
@@ -18,12 +18,15 @@
|
||||
#include "Poco/DateTimeFormatter.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/MD5Engine.h"
|
||||
#include "Poco/SHA1Engine.h"
|
||||
#include "Poco/SHA2Engine.h"
|
||||
#include "Poco/Net/HTTPDigestCredentials.h"
|
||||
#include "Poco/Net/HTTPRequest.h"
|
||||
#include "Poco/Net/HTTPResponse.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -68,7 +71,28 @@ namespace Net {
|
||||
|
||||
|
||||
const std::string HTTPDigestCredentials::SCHEME = "Digest";
|
||||
const std::string HTTPDigestCredentials::DEFAULT_ALGORITHM("MD5");
|
||||
const std::vector<std::string> HTTPDigestCredentials::SUPPORTED_ALGORITHMS = {
|
||||
"MD5",
|
||||
"MD5-sess",
|
||||
"SHA",
|
||||
"SHA-sess",
|
||||
"SHA-256",
|
||||
"SHA-256-sess",
|
||||
"SHA-512-256",
|
||||
"SHA-512-256-sess",
|
||||
"SHA-512",
|
||||
"SHA-512-sess"
|
||||
};
|
||||
const std::string HTTPDigestCredentials::MD_5_ALGORITHM = "MD5";
|
||||
const std::string HTTPDigestCredentials::MD_5_SESS_ALGORITHM = "MD5-sess";
|
||||
const std::string HTTPDigestCredentials::SHA_ALGORITHM = "SHA";
|
||||
const std::string HTTPDigestCredentials::SHA_SESS_ALGORITHM = "SHA-sess";
|
||||
const std::string HTTPDigestCredentials::SHA_256_ALGORITHM = "SHA-256";
|
||||
const std::string HTTPDigestCredentials::SHA_256_SESS_ALGORITHM = "SHA-256-sess";
|
||||
const std::string HTTPDigestCredentials::SHA_512_256_ALGORITHM = "SHA-512-256";
|
||||
const std::string HTTPDigestCredentials::SHA_512_256_SESS_ALGORITHM = "SHA-512-256-sess";
|
||||
const std::string HTTPDigestCredentials::SHA_512_ALGORITHM = "SHA-512";
|
||||
const std::string HTTPDigestCredentials::SHA_512_SESS_ALGORITHM = "SHA-512-sess";
|
||||
const std::string HTTPDigestCredentials::DEFAULT_QOP("");
|
||||
const std::string HTTPDigestCredentials::NONCE_PARAM("nonce");
|
||||
const std::string HTTPDigestCredentials::REALM_PARAM("realm");
|
||||
@@ -84,6 +108,44 @@ const std::string HTTPDigestCredentials::NC_PARAM("nc");
|
||||
int HTTPDigestCredentials::_nonceCounter(0);
|
||||
Poco::FastMutex HTTPDigestCredentials::_nonceMutex;
|
||||
|
||||
class HTTPDigestCredentials::DigestEngineProvider {
|
||||
public:
|
||||
DigestEngineProvider(std::string algorithm): _algorithm(algorithm) {
|
||||
_isSessionAlgorithm = _algorithm.find("sess") != std::string::npos;
|
||||
}
|
||||
|
||||
DigestEngine& engine() {
|
||||
if (icompare(_algorithm, SHA_ALGORITHM) == 0 || icompare(_algorithm, SHA_SESS_ALGORITHM) == 0)
|
||||
{
|
||||
return _sha1Engine;
|
||||
}
|
||||
if (icompare(_algorithm, SHA_256_ALGORITHM) == 0 || icompare(_algorithm, SHA_256_SESS_ALGORITHM) == 0)
|
||||
{
|
||||
return _sha256Engine;
|
||||
} else if (icompare(_algorithm, SHA_512_256_ALGORITHM) == 0 || icompare(_algorithm, SHA_512_256_SESS_ALGORITHM) == 0)
|
||||
{
|
||||
return _sha512_256Engine;
|
||||
} else if (icompare(_algorithm, SHA_512_ALGORITHM) == 0 || icompare(_algorithm, SHA_512_SESS_ALGORITHM) == 0)
|
||||
{
|
||||
return _sha512;
|
||||
}
|
||||
else {
|
||||
return _md5Engine;
|
||||
}
|
||||
}
|
||||
|
||||
bool isSessionAlgorithm() {
|
||||
return _isSessionAlgorithm;
|
||||
}
|
||||
private:
|
||||
std::string _algorithm;
|
||||
SHA1Engine _sha1Engine;
|
||||
MD5Engine _md5Engine;
|
||||
SHA2Engine _sha256Engine { SHA2Engine::ALGORITHM::SHA_256 };
|
||||
SHA2Engine _sha512_256Engine { SHA2Engine::ALGORITHM::SHA_512_256 };
|
||||
SHA2Engine _sha512 { SHA2Engine::ALGORITHM::SHA_512 };
|
||||
bool _isSessionAlgorithm;
|
||||
};
|
||||
|
||||
HTTPDigestCredentials::HTTPDigestCredentials()
|
||||
{
|
||||
@@ -191,11 +253,6 @@ void HTTPDigestCredentials::createAuthParams(const HTTPRequest& request, const H
|
||||
if (!responseAuthParams.has(NONCE_PARAM) || !responseAuthParams.has(REALM_PARAM))
|
||||
throw InvalidArgumentException("Invalid HTTP authentication parameters");
|
||||
|
||||
const std::string& algorithm = responseAuthParams.get(ALGORITHM_PARAM, DEFAULT_ALGORITHM);
|
||||
|
||||
if (icompare(algorithm, DEFAULT_ALGORITHM) != 0)
|
||||
throw NotImplementedException("Unsupported digest algorithm", algorithm);
|
||||
|
||||
const std::string& nonce = responseAuthParams.get(NONCE_PARAM);
|
||||
const std::string& qop = responseAuthParams.get(QOP_PARAM, DEFAULT_QOP);
|
||||
const std::string& realm = responseAuthParams.getRealm();
|
||||
@@ -208,6 +265,10 @@ void HTTPDigestCredentials::createAuthParams(const HTTPRequest& request, const H
|
||||
{
|
||||
_requestAuthParams.set(OPAQUE_PARAM, responseAuthParams.get(OPAQUE_PARAM));
|
||||
}
|
||||
if (responseAuthParams.has(ALGORITHM_PARAM))
|
||||
{
|
||||
_requestAuthParams.set(ALGORITHM_PARAM, responseAuthParams.get(ALGORITHM_PARAM));
|
||||
}
|
||||
|
||||
if (qop.empty())
|
||||
{
|
||||
@@ -233,10 +294,8 @@ void HTTPDigestCredentials::createAuthParams(const HTTPRequest& request, const H
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HTTPDigestCredentials::updateAuthParams(const HTTPRequest& request)
|
||||
{
|
||||
MD5Engine engine;
|
||||
const std::string qop = _requestAuthParams.get(QOP_PARAM, DEFAULT_QOP);
|
||||
const std::string realm = _requestAuthParams.getRealm();
|
||||
const std::string nonce = _requestAuthParams.get(NONCE_PARAM);
|
||||
@@ -245,6 +304,11 @@ void HTTPDigestCredentials::updateAuthParams(const HTTPRequest& request)
|
||||
|
||||
if (qop.empty())
|
||||
{
|
||||
/// Assume that https://tools.ietf.org/html/rfc7616 does not supported
|
||||
/// and still using https://tools.ietf.org/html/rfc2069#section-2.4
|
||||
|
||||
MD5Engine engine;
|
||||
|
||||
const std::string ha1 = digest(engine, _username, realm, _password);
|
||||
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
|
||||
|
||||
@@ -252,13 +316,28 @@ void HTTPDigestCredentials::updateAuthParams(const HTTPRequest& request)
|
||||
}
|
||||
else if (icompare(qop, AUTH_PARAM) == 0)
|
||||
{
|
||||
const std::string cnonce = _requestAuthParams.get(CNONCE_PARAM);
|
||||
const std::string algorithm = _requestAuthParams.get(ALGORITHM_PARAM, MD_5_ALGORITHM);
|
||||
|
||||
const std::string ha1 = digest(engine, _username, realm, _password);
|
||||
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
|
||||
if (!isAlgorithmSupported(algorithm)) {
|
||||
throw NotImplementedException("Unsupported digest algorithm", algorithm);
|
||||
}
|
||||
|
||||
const std::string cnonce = _requestAuthParams.get(CNONCE_PARAM);
|
||||
const std::string nc = formatNonceCounter(updateNonceCounter(nonce));
|
||||
|
||||
DigestEngineProvider engineProvider(algorithm);
|
||||
DigestEngine &engine = engineProvider.engine();
|
||||
|
||||
std::string ha1 = digest(engine, _username, realm, _password);
|
||||
|
||||
if (engineProvider.isSessionAlgorithm()) {
|
||||
ha1 = digest(engine, ha1, nonce, cnonce);
|
||||
}
|
||||
|
||||
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
|
||||
|
||||
_requestAuthParams.set(NC_PARAM, nc);
|
||||
_requestAuthParams.set(CNONCE_PARAM, cnonce);
|
||||
_requestAuthParams.set(RESPONSE_PARAM, digest(engine, ha1, nonce, nc, cnonce, qop, ha2));
|
||||
}
|
||||
}
|
||||
@@ -277,18 +356,34 @@ bool HTTPDigestCredentials::verifyAuthParams(const HTTPRequest& request, const H
|
||||
const std::string& realm = params.getRealm();
|
||||
const std::string& qop = params.get(QOP_PARAM, DEFAULT_QOP);
|
||||
std::string response;
|
||||
MD5Engine engine;
|
||||
if (qop.empty())
|
||||
{
|
||||
MD5Engine engine;
|
||||
|
||||
const std::string ha1 = digest(engine, _username, realm, _password);
|
||||
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
|
||||
response = digest(engine, ha1, nonce, ha2);
|
||||
}
|
||||
else if (icompare(qop, AUTH_PARAM) == 0)
|
||||
{
|
||||
const std::string& algorithm = params.get(ALGORITHM_PARAM, MD_5_ALGORITHM);
|
||||
|
||||
if (!isAlgorithmSupported(algorithm)) {
|
||||
throw NotImplementedException("Unsupported digest algorithm", algorithm);
|
||||
}
|
||||
|
||||
DigestEngineProvider engineProvider(algorithm);
|
||||
DigestEngine& engine = engineProvider.engine();
|
||||
|
||||
const std::string& cnonce = params.get(CNONCE_PARAM);
|
||||
const std::string& nc = params.get(NC_PARAM);
|
||||
const std::string ha1 = digest(engine, _username, realm, _password);
|
||||
|
||||
std::string ha1 = digest(engine, _username, realm, _password);
|
||||
|
||||
if (engineProvider.isSessionAlgorithm()) {
|
||||
ha1 = digest(engine, ha1, nonce, cnonce);
|
||||
}
|
||||
|
||||
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
|
||||
response = digest(engine, ha1, nonce, nc, cnonce, qop, ha2);
|
||||
}
|
||||
@@ -309,5 +404,15 @@ int HTTPDigestCredentials::updateNonceCounter(const std::string& nonce)
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool HTTPDigestCredentials::isAlgorithmSupported(const std::string& algorithm) const
|
||||
{
|
||||
bool isAlgorithmSupported = std::find_if(std::begin(SUPPORTED_ALGORITHMS),
|
||||
std::end(SUPPORTED_ALGORITHMS),
|
||||
[&algorithm](const std::string& supportedAlgorithm) {
|
||||
return icompare(algorithm, supportedAlgorithm) == 0;
|
||||
}) != std::end(SUPPORTED_ALGORITHMS);
|
||||
|
||||
return isAlgorithmSupported;
|
||||
}
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
Vendored
+3
@@ -81,6 +81,7 @@ const std::string HTTPResponse::HTTP_REASON_MISDIRECTED_REQUEST = "M
|
||||
const std::string HTTPResponse::HTTP_REASON_UNPROCESSABLE_ENTITY = "Unprocessable Entity";
|
||||
const std::string HTTPResponse::HTTP_REASON_LOCKED = "Locked";
|
||||
const std::string HTTPResponse::HTTP_REASON_FAILED_DEPENDENCY = "Failed Dependency";
|
||||
const std::string HTTPResponse::HTTP_REASON_TOO_EARLY = "Too Early";
|
||||
const std::string HTTPResponse::HTTP_REASON_UPGRADE_REQUIRED = "Upgrade Required";
|
||||
const std::string HTTPResponse::HTTP_REASON_PRECONDITION_REQUIRED = "Precondition Required";
|
||||
const std::string HTTPResponse::HTTP_REASON_TOO_MANY_REQUESTS = "Too Many Requests";
|
||||
@@ -363,6 +364,8 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
|
||||
return HTTP_REASON_LOCKED;
|
||||
case HTTP_FAILED_DEPENDENCY:
|
||||
return HTTP_REASON_FAILED_DEPENDENCY;
|
||||
case HTTP_TOO_EARLY:
|
||||
return HTTP_REASON_TOO_EARLY;
|
||||
case HTTP_UPGRADE_REQUIRED:
|
||||
return HTTP_REASON_UPGRADE_REQUIRED;
|
||||
case HTTP_PRECONDITION_REQUIRED:
|
||||
|
||||
@@ -76,6 +76,8 @@ void HTTPServerConnection::run()
|
||||
response.set("Server", server);
|
||||
try
|
||||
{
|
||||
session.requestTrailer().clear();
|
||||
session.responseTrailer().clear();
|
||||
std::unique_ptr<HTTPRequestHandler> pHandler(_pFactory->createRequestHandler(request));
|
||||
if (pHandler.get())
|
||||
{
|
||||
|
||||
+6
-6
@@ -32,12 +32,12 @@ HTTPServerParams::~HTTPServerParams()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPServerParams::setServerName(const std::string& serverName)
|
||||
{
|
||||
_serverName = serverName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPServerParams::setSoftwareVersion(const std::string& softwareVersion)
|
||||
{
|
||||
@@ -50,24 +50,24 @@ void HTTPServerParams::setTimeout(const Poco::Timespan& timeout)
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPServerParams::setKeepAlive(bool keepAlive)
|
||||
{
|
||||
_keepAlive = keepAlive;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPServerParams::setKeepAliveTimeout(const Poco::Timespan& timeout)
|
||||
{
|
||||
_keepAliveTimeout = timeout;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPServerParams::setMaxKeepAliveRequests(int maxKeepAliveRequests)
|
||||
{
|
||||
poco_assert (maxKeepAliveRequests >= 0);
|
||||
_maxKeepAliveRequests = maxKeepAliveRequests;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
+3
-3
@@ -41,13 +41,13 @@ HTTPServerRequestImpl::HTTPServerRequestImpl(HTTPServerResponseImpl& response, H
|
||||
|
||||
HTTPHeaderInputStream hs(session);
|
||||
read(hs);
|
||||
|
||||
|
||||
// Now that we know socket is still connected, obtain addresses
|
||||
_clientAddress = session.clientAddress();
|
||||
_serverAddress = session.serverAddress();
|
||||
|
||||
|
||||
if (getChunkedTransferEncoding())
|
||||
_pStream = new HTTPChunkedInputStream(session);
|
||||
_pStream = new HTTPChunkedInputStream(session, &session.requestTrailer());
|
||||
else if (hasContentLength())
|
||||
#if defined(POCO_HAVE_INT64)
|
||||
_pStream = new HTTPFixedLengthInputStream(session, getContentLength64());
|
||||
|
||||
+5
-5
@@ -82,13 +82,13 @@ std::ostream& HTTPServerResponseImpl::send()
|
||||
{
|
||||
HTTPHeaderOutputStream hs(_session);
|
||||
write(hs);
|
||||
_pStream = new HTTPChunkedOutputStream(_session);
|
||||
_pStream = new HTTPChunkedOutputStream(_session, &_session.responseTrailer());
|
||||
}
|
||||
else if (hasContentLength())
|
||||
{
|
||||
Poco::CountingOutputStream cs;
|
||||
write(cs);
|
||||
#if defined(POCO_HAVE_INT64)
|
||||
#if defined(POCO_HAVE_INT64)
|
||||
_pStream = new HTTPFixedLengthOutputStream(_session, getContentLength64() + cs.chars());
|
||||
#else
|
||||
_pStream = new HTTPFixedLengthOutputStream(_session, getContentLength() + cs.chars());
|
||||
@@ -113,7 +113,7 @@ void HTTPServerResponseImpl::sendFile(const std::string& path, const std::string
|
||||
Timestamp dateTime = f.getLastModified();
|
||||
File::FileSize length = f.getSize();
|
||||
set("Last-Modified", DateTimeFormatter::format(dateTime, DateTimeFormat::HTTP_FORMAT));
|
||||
#if defined(POCO_HAVE_INT64)
|
||||
#if defined(POCO_HAVE_INT64)
|
||||
setContentLength64(length);
|
||||
#else
|
||||
setContentLength(static_cast<int>(length));
|
||||
@@ -141,7 +141,7 @@ void HTTPServerResponseImpl::sendBuffer(const void* pBuffer, std::size_t length)
|
||||
|
||||
setContentLength(static_cast<int>(length));
|
||||
setChunkedTransferEncoding(false);
|
||||
|
||||
|
||||
_pStream = new HTTPHeaderOutputStream(_session);
|
||||
write(*_pStream);
|
||||
if (_pRequest && _pRequest->getMethod() != HTTPRequest::HTTP_HEAD)
|
||||
@@ -169,7 +169,7 @@ void HTTPServerResponseImpl::redirect(const std::string& uri, HTTPStatus status)
|
||||
void HTTPServerResponseImpl::requireAuthentication(const std::string& realm)
|
||||
{
|
||||
poco_assert (!_pStream);
|
||||
|
||||
|
||||
setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED);
|
||||
std::string auth("Basic realm=\"");
|
||||
auth.append(realm);
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ bool HTTPServerSession::hasMoreRequests()
|
||||
}
|
||||
else if (_maxKeepAliveRequests != 0 && getKeepAlive())
|
||||
{
|
||||
if (_maxKeepAliveRequests > 0)
|
||||
if (_maxKeepAliveRequests > 0)
|
||||
--_maxKeepAliveRequests;
|
||||
return buffered() > 0 || socket().poll(_keepAliveTimeout, Socket::SELECT_READ);
|
||||
}
|
||||
|
||||
Vendored
+10
-3
@@ -111,14 +111,14 @@ int HTTPSession::get()
|
||||
{
|
||||
if (_pCurrent == _pEnd)
|
||||
refill();
|
||||
|
||||
|
||||
if (_pCurrent < _pEnd)
|
||||
return *_pCurrent++;
|
||||
else
|
||||
return std::char_traits<char>::eof();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int HTTPSession::peek()
|
||||
{
|
||||
if (_pCurrent == _pEnd)
|
||||
@@ -130,7 +130,7 @@ int HTTPSession::peek()
|
||||
return std::char_traits<char>::eof();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int HTTPSession::read(char* buffer, std::streamsize length)
|
||||
{
|
||||
if (_pCurrent < _pEnd)
|
||||
@@ -203,6 +203,13 @@ void HTTPSession::connect(const SocketAddress& address)
|
||||
}
|
||||
|
||||
|
||||
void HTTPSession::connect(const SocketAddress& targetAddress, const SocketAddress& sourceAddress)
|
||||
{
|
||||
_socket.bind(sourceAddress, true);
|
||||
connect(targetAddress);
|
||||
}
|
||||
|
||||
|
||||
void HTTPSession::abort()
|
||||
{
|
||||
_socket.shutdown();
|
||||
|
||||
+12
-12
@@ -85,7 +85,7 @@ std::istream* HTTPStreamFactory::open(const URI& uri)
|
||||
if (!pSession)
|
||||
{
|
||||
pSession = new HTTPClientSession(resolvedURI.getHost(), resolvedURI.getPort());
|
||||
|
||||
|
||||
if (proxyUri.empty())
|
||||
{
|
||||
if (!_proxyHost.empty())
|
||||
@@ -103,28 +103,28 @@ std::istream* HTTPStreamFactory::open(const URI& uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string path = resolvedURI.getPathAndQuery();
|
||||
if (path.empty()) path = "/";
|
||||
HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
|
||||
|
||||
|
||||
if (authorize)
|
||||
{
|
||||
HTTPCredentials::extractCredentials(uri, username, password);
|
||||
HTTPCredentials cred(username, password);
|
||||
cred.authenticate(req, res);
|
||||
}
|
||||
|
||||
req.set("User-Agent", Poco::format("poco/%d.%d.%d",
|
||||
|
||||
req.set("User-Agent", Poco::format("poco/%d.%d.%d",
|
||||
(POCO_VERSION >> 24) & 0xFF,
|
||||
(POCO_VERSION >> 16) & 0xFF,
|
||||
(POCO_VERSION >> 8) & 0xFF));
|
||||
req.set("Accept", "*/*");
|
||||
|
||||
|
||||
pSession->sendRequest(req);
|
||||
std::istream& rs = pSession->receiveResponse(res);
|
||||
bool moved = (res.getStatus() == HTTPResponse::HTTP_MOVED_PERMANENTLY ||
|
||||
res.getStatus() == HTTPResponse::HTTP_FOUND ||
|
||||
bool moved = (res.getStatus() == HTTPResponse::HTTP_MOVED_PERMANENTLY ||
|
||||
res.getStatus() == HTTPResponse::HTTP_FOUND ||
|
||||
res.getStatus() == HTTPResponse::HTTP_SEE_OTHER ||
|
||||
res.getStatus() == HTTPResponse::HTTP_TEMPORARY_REDIRECT);
|
||||
if (moved)
|
||||
@@ -142,13 +142,13 @@ std::istream* HTTPStreamFactory::open(const URI& uri)
|
||||
}
|
||||
else if (res.getStatus() == HTTPResponse::HTTP_USE_PROXY && !retry)
|
||||
{
|
||||
// The requested resource MUST be accessed through the proxy
|
||||
// given by the Location field. The Location field gives the
|
||||
// URI of the proxy. The recipient is expected to repeat this
|
||||
// The requested resource MUST be accessed through the proxy
|
||||
// given by the Location field. The Location field gives the
|
||||
// URI of the proxy. The recipient is expected to repeat this
|
||||
// single request via the proxy. 305 responses MUST only be generated by origin servers.
|
||||
// only use for one single request!
|
||||
proxyUri.resolve(res.get("Location"));
|
||||
delete pSession;
|
||||
delete pSession;
|
||||
pSession = 0;
|
||||
retry = true; // only allow useproxy once
|
||||
}
|
||||
|
||||
Vendored
+3
-3
@@ -30,7 +30,7 @@ HostEntry::HostEntry(struct hostent* entry)
|
||||
{
|
||||
poco_check_ptr (entry);
|
||||
|
||||
_name = entry->h_name;
|
||||
_name = entry->h_name;
|
||||
char** alias = entry->h_aliases;
|
||||
if (alias)
|
||||
{
|
||||
@@ -61,7 +61,7 @@ HostEntry::HostEntry(struct hostent* entry)
|
||||
HostEntry::HostEntry(struct addrinfo* ainfo)
|
||||
{
|
||||
poco_check_ptr (ainfo);
|
||||
|
||||
|
||||
for (struct addrinfo* ai = ainfo; ai; ai = ai->ai_next)
|
||||
{
|
||||
if (ai->ai_canonname)
|
||||
@@ -123,7 +123,7 @@ HostEntry& HostEntry::operator = (const HostEntry& entry)
|
||||
}
|
||||
|
||||
|
||||
void HostEntry::swap(HostEntry& hostEntry)
|
||||
void HostEntry::swap(HostEntry& hostEntry) noexcept
|
||||
{
|
||||
std::swap(_name, hostEntry._name);
|
||||
std::swap(_aliases, hostEntry._aliases);
|
||||
|
||||
+12
-12
@@ -31,11 +31,11 @@ namespace Net {
|
||||
|
||||
|
||||
ICMPEventArgs::ICMPEventArgs(const SocketAddress& address, int repetitions, int dataSize, int ttl):
|
||||
_address(address),
|
||||
_address(address),
|
||||
_sent(0),
|
||||
_dataSize(dataSize),
|
||||
_ttl(ttl),
|
||||
_rtt(repetitions, 0),
|
||||
_dataSize(dataSize),
|
||||
_ttl(ttl),
|
||||
_rtt(repetitions, 0),
|
||||
_errors(repetitions)
|
||||
{
|
||||
}
|
||||
@@ -52,10 +52,10 @@ std::string ICMPEventArgs::hostName() const
|
||||
{
|
||||
return DNS::resolve(_address.host().toString()).name();
|
||||
}
|
||||
catch (HostNotFoundException&)
|
||||
catch (HostNotFoundException&)
|
||||
{
|
||||
}
|
||||
catch (NoAddressFoundException&)
|
||||
catch (NoAddressFoundException&)
|
||||
{
|
||||
}
|
||||
catch (DNSException&)
|
||||
@@ -101,7 +101,7 @@ int ICMPEventArgs::received() const
|
||||
{
|
||||
int received = 0;
|
||||
|
||||
for (int i = 0; i < _rtt.size(); ++i)
|
||||
for (int i = 0; i < _rtt.size(); ++i)
|
||||
{
|
||||
if (_rtt[i]) ++received;
|
||||
}
|
||||
@@ -111,7 +111,7 @@ int ICMPEventArgs::received() const
|
||||
|
||||
void ICMPEventArgs::setError(int index, const std::string& text)
|
||||
{
|
||||
if (index >= _errors.size())
|
||||
if (index >= _errors.size())
|
||||
throw InvalidArgumentException("Supplied index exceeds vector capacity.");
|
||||
|
||||
_errors[index] = text;
|
||||
@@ -120,7 +120,7 @@ void ICMPEventArgs::setError(int index, const std::string& text)
|
||||
|
||||
const std::string& ICMPEventArgs::error(int index) const
|
||||
{
|
||||
if (0 == _errors.size())
|
||||
if (0 == _errors.size())
|
||||
throw InvalidArgumentException("Supplied index exceeds vector capacity.");
|
||||
|
||||
if (-1 == index) index = _sent - 1;
|
||||
@@ -131,7 +131,7 @@ const std::string& ICMPEventArgs::error(int index) const
|
||||
|
||||
void ICMPEventArgs::setReplyTime(int index, int time)
|
||||
{
|
||||
if (index >= _rtt.size())
|
||||
if (index >= _rtt.size())
|
||||
throw InvalidArgumentException("Supplied index exceeds array capacity.");
|
||||
if (0 == time) time = 1;
|
||||
_rtt[index] = time;
|
||||
@@ -140,7 +140,7 @@ void ICMPEventArgs::setReplyTime(int index, int time)
|
||||
|
||||
int ICMPEventArgs::replyTime(int index) const
|
||||
{
|
||||
if (0 == _rtt.size())
|
||||
if (0 == _rtt.size())
|
||||
throw InvalidArgumentException("Supplied index exceeds array capacity.");
|
||||
|
||||
if (-1 == index) index = _sent - 1;
|
||||
@@ -152,7 +152,7 @@ int ICMPEventArgs::replyTime(int index) const
|
||||
int ICMPEventArgs::avgRTT() const
|
||||
{
|
||||
if (0 == _rtt.size()) return 0;
|
||||
|
||||
|
||||
return (int) (std::accumulate(_rtt.begin(), _rtt.end(), 0) / _rtt.size());
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -81,13 +81,13 @@ unsigned short ICMPPacketImpl::checksum(UInt16 *addr, Int32 len)
|
||||
UInt16 answer;
|
||||
Int32 sum = 0;
|
||||
|
||||
while (nleft > 1)
|
||||
while (nleft > 1)
|
||||
{
|
||||
sum += *w++;
|
||||
nleft -= sizeof(UInt16);
|
||||
}
|
||||
|
||||
if (nleft == 1)
|
||||
if (nleft == 1)
|
||||
{
|
||||
UInt16 u = 0;
|
||||
*(UInt8*) (&u) = *(UInt8*) w;
|
||||
|
||||
Vendored
+3
-3
@@ -25,13 +25,13 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
ICMPSocket::ICMPSocket(IPAddress::Family family, int dataSize, int ttl, int timeout):
|
||||
ICMPSocket::ICMPSocket(IPAddress::Family family, int dataSize, int ttl, int timeout):
|
||||
Socket(new ICMPSocketImpl(family, dataSize, ttl, timeout))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ICMPSocket::ICMPSocket(const Socket& socket):
|
||||
ICMPSocket::ICMPSocket(const Socket& socket):
|
||||
Socket(socket)
|
||||
{
|
||||
if (!dynamic_cast<ICMPSocketImpl*>(impl()))
|
||||
@@ -39,7 +39,7 @@ ICMPSocket::ICMPSocket(const Socket& socket):
|
||||
}
|
||||
|
||||
|
||||
ICMPSocket::ICMPSocket(SocketImpl* pImpl):
|
||||
ICMPSocket::ICMPSocket(SocketImpl* pImpl):
|
||||
Socket(pImpl)
|
||||
{
|
||||
if (!dynamic_cast<ICMPSocketImpl*>(impl()))
|
||||
|
||||
+8
-7
@@ -66,7 +66,7 @@ int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags)
|
||||
{
|
||||
int maxPacketSize = _icmpPacket.maxPacketSize();
|
||||
Poco::Buffer<unsigned char> buffer(maxPacketSize);
|
||||
int expected = _icmpPacket.packetSize();
|
||||
int leftover = _icmpPacket.packetSize();
|
||||
int type = 0, code = 0;
|
||||
|
||||
try
|
||||
@@ -83,8 +83,8 @@ int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags)
|
||||
if (rc == 0) break;
|
||||
if (respAddr == address)
|
||||
{
|
||||
expected -= rc;
|
||||
if (expected <= 0)
|
||||
leftover -= rc;
|
||||
if (leftover <= 0)
|
||||
{
|
||||
if (_icmpPacket.validReplyID(buffer.begin(), maxPacketSize)) break;
|
||||
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;
|
||||
}
|
||||
while (expected > 0 && !_icmpPacket.validReplyID(buffer.begin(), maxPacketSize));
|
||||
while (leftover > 0 && !_icmpPacket.validReplyID(buffer.begin(), maxPacketSize));
|
||||
}
|
||||
catch (ICMPException&)
|
||||
{
|
||||
@@ -113,10 +113,11 @@ int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags)
|
||||
else throw;
|
||||
}
|
||||
|
||||
if (expected > 0)
|
||||
if (leftover > 0)
|
||||
{
|
||||
throw ICMPException(Poco::format("No response: expected %d, received: %d", _icmpPacket.packetSize(),
|
||||
_icmpPacket.packetSize() - expected));
|
||||
std::string err = leftover < _icmpPacket.packetSize() ? "Incomplete" : "No";
|
||||
throw ICMPException(Poco::format("%s response: expected %d, received: %d", err, _icmpPacket.packetSize(),
|
||||
_icmpPacket.packetSize() - leftover));
|
||||
}
|
||||
|
||||
struct timeval then = _icmpPacket.time(buffer.begin(), maxPacketSize);
|
||||
|
||||
Vendored
+109
-7
@@ -19,6 +19,7 @@
|
||||
#include "Poco/BinaryReader.h"
|
||||
#include "Poco/BinaryWriter.h"
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/Format.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)
|
||||
{
|
||||
if (family == IPv4)
|
||||
@@ -99,7 +105,7 @@ IPAddress::IPAddress(const std::string& addr)
|
||||
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
IPv6AddressImpl empty6 = IPv6AddressImpl();
|
||||
if (addr.empty() || trim(addr) == "::")
|
||||
if (addr.empty() || trimIPv6(addr) == "::")
|
||||
{
|
||||
newIPv6(empty6.addr());
|
||||
return;
|
||||
@@ -230,13 +236,20 @@ IPAddress& IPAddress::operator = (const IPAddress& addr)
|
||||
else if (addr.family() == IPAddress::IPv6)
|
||||
newIPv6(addr.addr(), addr.scope());
|
||||
#endif
|
||||
else
|
||||
else
|
||||
throw Poco::InvalidArgumentException("Invalid or unsupported address family");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
IPAddress& IPAddress::operator = (IPAddress&& addr)
|
||||
{
|
||||
_pImpl = std::move(addr._pImpl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
IPAddress::Family IPAddress::family() const
|
||||
{
|
||||
return pImpl()->family();
|
||||
@@ -248,7 +261,7 @@ Poco::UInt32 IPAddress::scope() const
|
||||
return pImpl()->scope();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string IPAddress::toString() const
|
||||
{
|
||||
return pImpl()->toString();
|
||||
@@ -278,13 +291,13 @@ bool IPAddress::isMulticast() const
|
||||
return pImpl()->isMulticast();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool IPAddress::isUnicast() const
|
||||
{
|
||||
return !isWildcard() && !isBroadcast() && !isMulticast();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool IPAddress::isLinkLocal() const
|
||||
{
|
||||
return pImpl()->isLinkLocal();
|
||||
@@ -500,7 +513,7 @@ poco_socklen_t IPAddress::length() const
|
||||
return pImpl()->length();
|
||||
}
|
||||
|
||||
|
||||
|
||||
const void* IPAddress::addr() const
|
||||
{
|
||||
return pImpl()->addr();
|
||||
@@ -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)
|
||||
{
|
||||
return IPAddress(addr);
|
||||
@@ -535,7 +589,7 @@ bool IPAddress::tryParse(const std::string& addr, IPAddress& result)
|
||||
}
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
IPv6AddressImpl impl6(IPv6AddressImpl::parse(addr));
|
||||
if (impl6 != IPv6AddressImpl())
|
||||
if (impl6 != IPv6AddressImpl() || trimIPv6(addr) == "::")
|
||||
{
|
||||
result.newIPv6(impl6.addr(), impl6.scope());
|
||||
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
|
||||
|
||||
|
||||
|
||||
+14
-11
@@ -40,8 +40,8 @@ namespace {
|
||||
template <typename T>
|
||||
unsigned maskBits(T val, unsigned size)
|
||||
/// Returns the length of the mask (number of bits set in val).
|
||||
/// The val should be either all zeros or two contiguos areas of 1s and 0s.
|
||||
/// The algorithm ignores invalid non-contiguous series of 1s and treats val
|
||||
/// The val should be either all zeros or two contiguos areas of 1s and 0s.
|
||||
/// The algorithm ignores invalid non-contiguous series of 1s and treats val
|
||||
/// as if all bits between MSb and last non-zero bit are set to 1.
|
||||
{
|
||||
unsigned count = 0;
|
||||
@@ -261,7 +261,7 @@ bool IPv4AddressImpl::isGlobalMC() const
|
||||
IPv4AddressImpl IPv4AddressImpl::parse(const std::string& addr)
|
||||
{
|
||||
if (addr.empty()) return IPv4AddressImpl();
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32)
|
||||
struct in_addr ia;
|
||||
ia.s_addr = inet_addr(addr.c_str());
|
||||
if (ia.s_addr == INADDR_NONE && addr != "255.255.255.255")
|
||||
@@ -290,7 +290,7 @@ IPv4AddressImpl IPv4AddressImpl::parse(const std::string& addr)
|
||||
void IPv4AddressImpl::mask(const IPAddressImpl* pMask, const IPAddressImpl* pSet)
|
||||
{
|
||||
poco_assert (pMask->af() == AF_INET && pSet->af() == AF_INET);
|
||||
|
||||
|
||||
_addr.s_addr &= static_cast<const IPv4AddressImpl*>(pMask)->_addr.s_addr;
|
||||
_addr.s_addr |= static_cast<const IPv4AddressImpl*>(pSet)->_addr.s_addr & ~static_cast<const IPv4AddressImpl*>(pMask)->_addr.s_addr;
|
||||
}
|
||||
@@ -394,7 +394,7 @@ IPv6AddressImpl::IPv6AddressImpl(unsigned prefix):
|
||||
{
|
||||
unsigned i = 0;
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
for (; prefix >= 16; ++i, prefix -= 16)
|
||||
for (; prefix >= 16; ++i, prefix -= 16)
|
||||
{
|
||||
_addr.s6_addr16[i] = 0xffff;
|
||||
}
|
||||
@@ -407,7 +407,7 @@ IPv6AddressImpl::IPv6AddressImpl(unsigned prefix):
|
||||
_addr.s6_addr16[i++] = 0;
|
||||
}
|
||||
#else
|
||||
for (; prefix >= 32; ++i, prefix -= 32)
|
||||
for (; prefix >= 32; ++i, prefix -= 32)
|
||||
{
|
||||
_addr.s6_addr32[i] = 0xffffffff;
|
||||
}
|
||||
@@ -551,7 +551,7 @@ Poco::UInt32 IPv6AddressImpl::scope() const
|
||||
bool IPv6AddressImpl::isWildcard() const
|
||||
{
|
||||
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
|
||||
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
|
||||
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
|
||||
words[4] == 0 && words[5] == 0 && words[6] == 0 && words[7] == 0;
|
||||
}
|
||||
|
||||
@@ -564,8 +564,11 @@ bool IPv6AddressImpl::isBroadcast() const
|
||||
|
||||
bool IPv6AddressImpl::isLoopback() const
|
||||
{
|
||||
if (isIPv4Mapped())
|
||||
return (ByteOrder::fromNetwork(_addr.s6_addr[6]) & 0xFF000000) == 0x7F000000;
|
||||
|
||||
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
|
||||
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
|
||||
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
|
||||
words[4] == 0 && words[5] == 0 && words[6] == 0 && ByteOrder::fromNetwork(words[7]) == 0x0001;
|
||||
}
|
||||
|
||||
@@ -729,9 +732,9 @@ IPv6AddressImpl IPv6AddressImpl::operator & (const IPv6AddressImpl& addr) const
|
||||
|
||||
IPv6AddressImpl IPv6AddressImpl::operator | (const IPv6AddressImpl& addr) const
|
||||
{
|
||||
if (_scope != addr._scope)
|
||||
if (_scope != addr._scope)
|
||||
throw Poco::InvalidArgumentException("Scope ID of passed IPv6 address does not match with the source one.");
|
||||
|
||||
|
||||
IPv6AddressImpl result(*this);
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
result._addr.s6_addr16[0] |= addr._addr.s6_addr16[0];
|
||||
@@ -756,7 +759,7 @@ IPv6AddressImpl IPv6AddressImpl::operator ^ (const IPv6AddressImpl& addr) const
|
||||
{
|
||||
if (_scope != addr._scope)
|
||||
throw Poco::InvalidArgumentException("Scope ID of passed IPv6 address does not match with the source one.");
|
||||
|
||||
|
||||
IPv6AddressImpl result(*this);
|
||||
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
|
||||
Vendored
+27
-27
@@ -52,7 +52,7 @@ namespace Net {
|
||||
namespace
|
||||
{
|
||||
class MultiPartHandler: public PartHandler
|
||||
/// This is a default part handler for multipart messages, used when there
|
||||
/// This is a default part handler for multipart messages, used when there
|
||||
/// is no external handler provided to he MailMessage. This handler
|
||||
/// will handle all types of message parts, including attachments.
|
||||
{
|
||||
@@ -65,14 +65,14 @@ namespace
|
||||
/// in its entirety, including attachments.
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~MultiPartHandler()
|
||||
/// Destroys string part handler.
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void handlePart(const MessageHeader& header, std::istream& stream)
|
||||
/// Handles a part. If message pointer was provided at construction time,
|
||||
/// Handles a part. If message pointer was provided at construction time,
|
||||
/// the message pointed to will be properly populated so it could be written
|
||||
/// back out at a later point in time.
|
||||
{
|
||||
@@ -97,7 +97,7 @@ namespace
|
||||
std::string filename;
|
||||
if (!contentDisp.empty())
|
||||
filename = getParamFromHeader(contentDisp, "filename");
|
||||
if (filename.empty())
|
||||
if (filename.empty())
|
||||
filename = getParamFromHeader(contentType, "name");
|
||||
PartSource* pPS = _pMsg->createPartStore(tmp, contentType, filename);
|
||||
poco_check_ptr (pPS);
|
||||
@@ -108,13 +108,13 @@ namespace
|
||||
{
|
||||
if (!added && MailMessage::HEADER_CONTENT_DISPOSITION == it->first)
|
||||
{
|
||||
if (it->second == "inline")
|
||||
if (it->second == "inline")
|
||||
_pMsg->addContent(pPS, cte);
|
||||
else
|
||||
else
|
||||
_pMsg->addAttachment("", pPS, cte);
|
||||
added = true;
|
||||
}
|
||||
|
||||
|
||||
pPS->headers().set(it->first, it->second);
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace
|
||||
if (!added) delete pPS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::string getParamFromHeader(const std::string& header, const std::string& param)
|
||||
{
|
||||
@@ -159,12 +159,12 @@ namespace
|
||||
/// The content parameter represents the part content.
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~StringPartHandler()
|
||||
/// Destroys string part handler.
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void handlePart(const MessageHeader& header, std::istream& stream)
|
||||
/// Handles a part.
|
||||
{
|
||||
@@ -172,7 +172,7 @@ namespace
|
||||
Poco::StreamCopier::copyToString(stream, tmp);
|
||||
_str.append(tmp);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::string& _str;
|
||||
};
|
||||
@@ -198,7 +198,7 @@ const std::string MailMessage::CTE_QUOTED_PRINTABLE("quoted-printable");
|
||||
const std::string MailMessage::CTE_BASE64("base64");
|
||||
|
||||
|
||||
MailMessage::MailMessage(PartStoreFactory* pStoreFactory):
|
||||
MailMessage::MailMessage(PartStoreFactory* pStoreFactory):
|
||||
_encoding(),
|
||||
_pStoreFactory(pStoreFactory)
|
||||
{
|
||||
@@ -216,7 +216,7 @@ MailMessage::~MailMessage()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MailMessage::addRecipient(const MailRecipient& recipient)
|
||||
{
|
||||
_recipients.push_back(recipient);
|
||||
@@ -234,7 +234,7 @@ void MailMessage::setSender(const std::string& sender)
|
||||
set(HEADER_FROM, sender);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::string& MailMessage::getSender() const
|
||||
{
|
||||
if (has(HEADER_FROM))
|
||||
@@ -243,13 +243,13 @@ const std::string& MailMessage::getSender() const
|
||||
return EMPTY_HEADER;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MailMessage::setSubject(const std::string& subject)
|
||||
{
|
||||
set(HEADER_SUBJECT, subject);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::string& MailMessage::getSubject() const
|
||||
{
|
||||
if (has(HEADER_SUBJECT))
|
||||
@@ -272,13 +272,13 @@ void MailMessage::setContentType(const std::string& mediaType)
|
||||
set(HEADER_CONTENT_TYPE, mediaType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MailMessage::setContentType(const MediaType& mediaType)
|
||||
{
|
||||
setContentType(mediaType.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::string& MailMessage::getContentType() const
|
||||
{
|
||||
if (has(HEADER_CONTENT_TYPE))
|
||||
@@ -293,7 +293,7 @@ void MailMessage::setDate(const Poco::Timestamp& dateTime)
|
||||
set(HEADER_DATE, DateTimeFormatter::format(dateTime, DateTimeFormat::RFC1123_FORMAT));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Poco::Timestamp MailMessage::getDate() const
|
||||
{
|
||||
const std::string& dateTime = get(HEADER_DATE);
|
||||
@@ -301,7 +301,7 @@ Poco::Timestamp MailMessage::getDate() const
|
||||
return DateTimeParser::parse(dateTime, tzd).timestamp();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool MailMessage::isMultipart() const
|
||||
{
|
||||
MediaType mediaType = getContentType();
|
||||
@@ -328,7 +328,7 @@ void MailMessage::addContent(PartSource* pSource, ContentTransferEncoding encodi
|
||||
addPart("", pSource, CONTENT_INLINE, encoding);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MailMessage::addAttachment(const std::string& name, PartSource* pSource, ContentTransferEncoding encoding)
|
||||
{
|
||||
addPart(name, pSource, CONTENT_ATTACHMENT, encoding);
|
||||
@@ -388,7 +388,7 @@ void MailMessage::makeMultipart()
|
||||
if (!isMultipart())
|
||||
{
|
||||
MediaType mediaType("multipart", "mixed");
|
||||
setContentType(mediaType);
|
||||
setContentType(mediaType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,7 +408,7 @@ void MailMessage::writeMultipart(MessageHeader& header, std::ostream& ostr) cons
|
||||
header.set(HEADER_CONTENT_TYPE, mediaType.toString());
|
||||
header.set(HEADER_MIME_VERSION, "1.0");
|
||||
writeHeader(header, ostr);
|
||||
|
||||
|
||||
MultipartWriter writer(ostr, _boundary);
|
||||
for (const auto& part: _parts)
|
||||
{
|
||||
@@ -542,7 +542,7 @@ void MailMessage::setRecipientHeaders(MessageHeader& headers) const
|
||||
std::string to;
|
||||
std::string cc;
|
||||
std::string bcc;
|
||||
|
||||
|
||||
for (const auto& rec: _recipients)
|
||||
{
|
||||
switch (rec.getType())
|
||||
@@ -622,7 +622,7 @@ std::string MailMessage::encodeWord(const std::string& text, const std::string&
|
||||
}
|
||||
}
|
||||
if (!containsNonASCII) return text;
|
||||
|
||||
|
||||
std::string encodedText;
|
||||
std::string::size_type lineLength = 0;
|
||||
for (auto ch: text)
|
||||
@@ -680,7 +680,7 @@ std::string MailMessage::encodeWord(const std::string& text, const std::string&
|
||||
if (lineLength > 0)
|
||||
{
|
||||
encodedText += "?=";
|
||||
}
|
||||
}
|
||||
return encodedText;
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -25,7 +25,7 @@ MailRecipient::MailRecipient():
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
MailRecipient::MailRecipient(const MailRecipient& recipient):
|
||||
_address(recipient._address),
|
||||
_realName(recipient._realName),
|
||||
@@ -33,7 +33,7 @@ MailRecipient::MailRecipient(const MailRecipient& recipient):
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
MailRecipient::MailRecipient(RecipientType type, const std::string& address):
|
||||
_address(address),
|
||||
_type(type)
|
||||
@@ -53,7 +53,7 @@ MailRecipient::~MailRecipient()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
MailRecipient& MailRecipient::operator = (const MailRecipient& recipient)
|
||||
{
|
||||
if (this != &recipient)
|
||||
@@ -65,26 +65,26 @@ MailRecipient& MailRecipient::operator = (const MailRecipient& recipient)
|
||||
}
|
||||
|
||||
|
||||
void MailRecipient::swap(MailRecipient& recipient)
|
||||
void MailRecipient::swap(MailRecipient& recipient) noexcept
|
||||
{
|
||||
std::swap(_type, recipient._type);
|
||||
std::swap(_address, recipient._address);
|
||||
std::swap(_realName, recipient._realName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MailRecipient::setType(RecipientType type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MailRecipient::setAddress(const std::string& address)
|
||||
{
|
||||
_address = address;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MailRecipient::setRealName(const std::string& realName)
|
||||
{
|
||||
_realName = realName;
|
||||
|
||||
Vendored
+7
-7
@@ -20,7 +20,7 @@ namespace Net {
|
||||
|
||||
|
||||
MailStreamBuf::MailStreamBuf(std::istream& istr):
|
||||
_pIstr(&istr),
|
||||
_pIstr(&istr),
|
||||
_pOstr(0),
|
||||
_state(ST_CR_LF)
|
||||
{
|
||||
@@ -28,7 +28,7 @@ MailStreamBuf::MailStreamBuf(std::istream& istr):
|
||||
|
||||
|
||||
MailStreamBuf::MailStreamBuf(std::ostream& ostr):
|
||||
_pIstr(0),
|
||||
_pIstr(0),
|
||||
_pOstr(&ostr),
|
||||
_state(ST_CR_LF)
|
||||
{
|
||||
@@ -53,7 +53,7 @@ void MailStreamBuf::close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int MailStreamBuf::readFromDevice()
|
||||
{
|
||||
int c = std::char_traits<char>::eof();
|
||||
@@ -194,8 +194,8 @@ MailStreamBuf* MailIOS::rdbuf()
|
||||
}
|
||||
|
||||
|
||||
MailInputStream::MailInputStream(std::istream& istr):
|
||||
MailIOS(istr),
|
||||
MailInputStream::MailInputStream(std::istream& istr):
|
||||
MailIOS(istr),
|
||||
std::istream(&_buf)
|
||||
{
|
||||
}
|
||||
@@ -206,8 +206,8 @@ MailInputStream::~MailInputStream()
|
||||
}
|
||||
|
||||
|
||||
MailOutputStream::MailOutputStream(std::ostream& ostr):
|
||||
MailIOS(ostr),
|
||||
MailOutputStream::MailOutputStream(std::ostream& ostr):
|
||||
MailIOS(ostr),
|
||||
std::ostream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -89,7 +89,7 @@ MediaType& MediaType::operator = (const std::string& mediaType)
|
||||
}
|
||||
|
||||
|
||||
void MediaType::swap(MediaType& mediaType)
|
||||
void MediaType::swap(MediaType& mediaType) noexcept
|
||||
{
|
||||
std::swap(_type, mediaType._type);
|
||||
std::swap(_subType, mediaType._subType);
|
||||
|
||||
+53
-22
@@ -28,14 +28,18 @@ namespace Net {
|
||||
|
||||
|
||||
MessageHeader::MessageHeader():
|
||||
_fieldLimit(DFL_FIELD_LIMIT)
|
||||
_fieldLimit(DFL_FIELD_LIMIT),
|
||||
_nameLengthLimit(DFL_NAME_LENGTH_LIMIT),
|
||||
_valueLengthLimit(DFL_VALUE_LENGTH_LIMIT)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
MessageHeader::MessageHeader(const MessageHeader& messageHeader):
|
||||
NameValueCollection(messageHeader),
|
||||
_fieldLimit(DFL_FIELD_LIMIT)
|
||||
_fieldLimit(DFL_FIELD_LIMIT),
|
||||
_nameLengthLimit(DFL_NAME_LENGTH_LIMIT),
|
||||
_valueLengthLimit(DFL_VALUE_LENGTH_LIMIT)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -80,12 +84,12 @@ void MessageHeader::read(std::istream& istr)
|
||||
throw MessageException("Too many header fields");
|
||||
name.clear();
|
||||
value.clear();
|
||||
while (ch != eof && ch != ':' && ch != '\n' && name.length() < MAX_NAME_LENGTH) { name += ch; ch = buf.sbumpc(); }
|
||||
while (ch != eof && ch != ':' && ch != '\n' && name.length() < _nameLengthLimit) { name += ch; ch = buf.sbumpc(); }
|
||||
if (ch == '\n') { ch = buf.sbumpc(); continue; } // ignore invalid header lines
|
||||
if (ch != ':') throw MessageException("Field name too long/no colon found");
|
||||
if (ch != eof) ch = buf.sbumpc(); // ':'
|
||||
while (ch != eof && Poco::Ascii::isSpace(ch) && ch != '\r' && ch != '\n') ch = buf.sbumpc();
|
||||
while (ch != eof && ch != '\r' && ch != '\n' && value.length() < MAX_VALUE_LENGTH) { value += ch; ch = buf.sbumpc(); }
|
||||
while (ch != eof && ch != '\r' && ch != '\n' && value.length() < _valueLengthLimit) { value += ch; ch = buf.sbumpc(); }
|
||||
if (ch == '\r') ch = buf.sbumpc();
|
||||
if (ch == '\n')
|
||||
ch = buf.sbumpc();
|
||||
@@ -93,7 +97,7 @@ void MessageHeader::read(std::istream& istr)
|
||||
throw MessageException("Field value too long/no CRLF found");
|
||||
while (ch == ' ' || ch == '\t') // folding
|
||||
{
|
||||
while (ch != eof && ch != '\r' && ch != '\n' && value.length() < MAX_VALUE_LENGTH) { value += ch; ch = buf.sbumpc(); }
|
||||
while (ch != eof && ch != '\r' && ch != '\n' && value.length() < _valueLengthLimit) { value += ch; ch = buf.sbumpc(); }
|
||||
if (ch == '\r') ch = buf.sbumpc();
|
||||
if (ch == '\n')
|
||||
ch = buf.sbumpc();
|
||||
@@ -104,7 +108,8 @@ void MessageHeader::read(std::istream& istr)
|
||||
add(name, decodeWord(value));
|
||||
++fields;
|
||||
}
|
||||
istr.putback(ch);
|
||||
if (istr.good() && ch != eof)
|
||||
istr.putback(ch);
|
||||
}
|
||||
|
||||
|
||||
@@ -113,15 +118,41 @@ int MessageHeader::getFieldLimit() const
|
||||
return _fieldLimit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MessageHeader::setFieldLimit(int limit)
|
||||
{
|
||||
poco_assert (limit >= 0);
|
||||
|
||||
|
||||
_fieldLimit = limit;
|
||||
}
|
||||
|
||||
|
||||
int MessageHeader::getNameLengthLimit() const
|
||||
{
|
||||
return _nameLengthLimit;
|
||||
}
|
||||
|
||||
void MessageHeader::setNameLengthLimit(int limit)
|
||||
{
|
||||
poco_assert(limit >= 0);
|
||||
|
||||
_nameLengthLimit = limit;
|
||||
}
|
||||
|
||||
|
||||
int MessageHeader::getValueLengthLimit() const
|
||||
{
|
||||
return _valueLengthLimit;
|
||||
}
|
||||
|
||||
void MessageHeader::setValueLengthLimit(int limit)
|
||||
{
|
||||
poco_assert(limit >= 0);
|
||||
|
||||
_valueLengthLimit = limit;
|
||||
}
|
||||
|
||||
|
||||
bool MessageHeader::hasToken(const std::string& fieldName, const std::string& token) const
|
||||
{
|
||||
std::string field = get(fieldName, "");
|
||||
@@ -257,7 +288,7 @@ void MessageHeader::quote(const std::string& value, std::string& result, bool al
|
||||
}
|
||||
|
||||
|
||||
void MessageHeader::decodeRFC2047(const std::string& ins, std::string& outs, const std::string& charset_to)
|
||||
void MessageHeader::decodeRFC2047(const std::string& ins, std::string& outs, const std::string& charset_to)
|
||||
{
|
||||
std::string tempout;
|
||||
StringTokenizer tokens(ins, "?");
|
||||
@@ -268,18 +299,18 @@ void MessageHeader::decodeRFC2047(const std::string& ins, std::string& outs, con
|
||||
|
||||
std::istringstream istr(text);
|
||||
|
||||
if (encoding == "B")
|
||||
if (encoding == "B")
|
||||
{
|
||||
// Base64 encoding.
|
||||
Base64Decoder decoder(istr);
|
||||
for (char c; decoder.get(c); tempout += c) {}
|
||||
}
|
||||
else if (encoding == "Q")
|
||||
else if (encoding == "Q")
|
||||
{
|
||||
// Quoted encoding.
|
||||
for (char c; istr.get(c);)
|
||||
// Quoted encoding.
|
||||
for (char c; istr.get(c);)
|
||||
{
|
||||
if (c == '_')
|
||||
if (c == '_')
|
||||
{
|
||||
//RFC 2047 _ is a space.
|
||||
tempout += " ";
|
||||
@@ -287,11 +318,11 @@ void MessageHeader::decodeRFC2047(const std::string& ins, std::string& outs, con
|
||||
}
|
||||
|
||||
// FIXME: check that we have enought chars-
|
||||
if (c == '=')
|
||||
if (c == '=')
|
||||
{
|
||||
// The next two chars are hex representation of the complete byte.
|
||||
std::string hex;
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
istr.get(c);
|
||||
hex += c;
|
||||
@@ -303,7 +334,7 @@ void MessageHeader::decodeRFC2047(const std::string& ins, std::string& outs, con
|
||||
tempout += c;
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
// Wrong encoding
|
||||
outs = ins;
|
||||
@@ -311,22 +342,22 @@ void MessageHeader::decodeRFC2047(const std::string& ins, std::string& outs, con
|
||||
}
|
||||
|
||||
// convert to the right charset.
|
||||
if (charset != charset_to)
|
||||
if (charset != charset_to)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
TextEncoding& enc = TextEncoding::byName(charset);
|
||||
TextEncoding& dec = TextEncoding::byName(charset_to);
|
||||
TextConverter converter(enc, dec);
|
||||
converter.convert(tempout, outs);
|
||||
}
|
||||
catch (...)
|
||||
catch (...)
|
||||
{
|
||||
// FIXME: Unsuported encoding...
|
||||
outs = tempout;
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
// Not conversion necesary.
|
||||
outs = tempout;
|
||||
@@ -339,7 +370,7 @@ std::string MessageHeader::decodeWord(const std::string& text, const std::string
|
||||
std::string outs, tmp = text;
|
||||
do {
|
||||
std::string tmp2;
|
||||
// find the begining of the next rfc2047 chunk
|
||||
// find the begining of the next rfc2047 chunk
|
||||
size_t pos = tmp.find("=?");
|
||||
if (pos == std::string::npos) {
|
||||
// No more found, return
|
||||
|
||||
+12
-13
@@ -24,10 +24,10 @@
|
||||
|
||||
#if defined(hpux) && defined(_XOPEN_SOURCE_EXTENDED) && defined(POCO_HPUX_IP_MREQ_HACK)
|
||||
// netinet/in.h does not define struct ip_mreq if
|
||||
// _XOPEN_SOURCE_EXTENDED is #define'd in HP-UX 11.x
|
||||
// _XOPEN_SOURCE_EXTENDED is #define'd in HP-UX 11.x
|
||||
// versions prior to 11.30. Compile with -DPOCO_HPUX_IP_MREQ_HACK
|
||||
// if you experience problems.
|
||||
struct ip_mreq
|
||||
struct ip_mreq
|
||||
{
|
||||
struct in_addr imr_multiaddr;
|
||||
struct in_addr imr_interface;
|
||||
@@ -97,7 +97,7 @@ void MulticastSocket::setInterface(const NetworkInterface& interfc)
|
||||
else throw UnsupportedFamilyException("Unknown or unsupported socket family.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
NetworkInterface MulticastSocket::getInterface() const
|
||||
{
|
||||
try
|
||||
@@ -118,7 +118,7 @@ NetworkInterface MulticastSocket::getInterface() const
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MulticastSocket::setLoopback(bool flag)
|
||||
{
|
||||
if (address().af() == AF_INET)
|
||||
@@ -135,7 +135,7 @@ void MulticastSocket::setLoopback(bool flag)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool MulticastSocket::getLoopback() const
|
||||
{
|
||||
bool flag = false;
|
||||
@@ -156,7 +156,7 @@ bool MulticastSocket::getLoopback() const
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MulticastSocket::setTimeToLive(unsigned value)
|
||||
{
|
||||
if (address().af() == AF_INET)
|
||||
@@ -172,7 +172,7 @@ void MulticastSocket::setTimeToLive(unsigned value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned MulticastSocket::getTimeToLive() const
|
||||
{
|
||||
unsigned ttl(0);
|
||||
@@ -191,13 +191,13 @@ unsigned MulticastSocket::getTimeToLive() const
|
||||
return ttl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MulticastSocket::joinGroup(const IPAddress& groupAddress)
|
||||
{
|
||||
joinGroup(groupAddress, findFirstInterface(groupAddress));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MulticastSocket::joinGroup(const IPAddress& groupAddress, const NetworkInterface& interfc)
|
||||
{
|
||||
if (groupAddress.af() == AF_INET)
|
||||
@@ -254,14 +254,13 @@ NetworkInterface MulticastSocket::findFirstInterface(const IPAddress& groupAddre
|
||||
throw NotFoundException("No multicast-eligible network interface found.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MulticastSocket::leaveGroup(const IPAddress& groupAddress)
|
||||
{
|
||||
NetworkInterface intf;
|
||||
leaveGroup(groupAddress, intf);
|
||||
leaveGroup(groupAddress, findFirstInterface(groupAddress));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MulticastSocket::leaveGroup(const IPAddress& groupAddress, const NetworkInterface& interfc)
|
||||
{
|
||||
if (groupAddress.af() == AF_INET)
|
||||
|
||||
+4
-3
@@ -88,7 +88,7 @@ int MultipartStreamBuf::readFromDevice(char* buffer, std::streamsize length)
|
||||
{
|
||||
buf.sbumpc(); // '\n'
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
else if (ch == '-' && buf.sgetc() == '-')
|
||||
{
|
||||
@@ -105,6 +105,7 @@ int MultipartStreamBuf::readFromDevice(char* buffer, std::streamsize length)
|
||||
*buffer++ = (char) buf.sbumpc(); ++n;
|
||||
ch = buf.sgetc();
|
||||
}
|
||||
if (ch == eof) _lastPart = true;
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -218,11 +219,11 @@ bool MultipartReader::hasNextPart()
|
||||
return (!_pMPI || !_pMPI->lastPart()) && _istr.good();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::istream& MultipartReader::stream() const
|
||||
{
|
||||
poco_check_ptr (_pMPI);
|
||||
|
||||
|
||||
return *_pMPI;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -26,7 +26,7 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
NTPClient::NTPClient(IPAddress::Family family, int timeout):
|
||||
NTPClient::NTPClient(IPAddress::Family family, int timeout):
|
||||
_family(family), _timeout(timeout)
|
||||
{
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -46,10 +46,10 @@ std::string NTPEventArgs::hostName() const
|
||||
{
|
||||
return DNS::resolve(_address.host().toString()).name();
|
||||
}
|
||||
catch (HostNotFoundException&)
|
||||
catch (HostNotFoundException&)
|
||||
{
|
||||
}
|
||||
catch (NoAddressFoundException&)
|
||||
catch (NoAddressFoundException&)
|
||||
{
|
||||
}
|
||||
catch (DNSException&)
|
||||
|
||||
Vendored
+5
-4
@@ -27,7 +27,7 @@ namespace Net {
|
||||
#else
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
struct NTPPacketData
|
||||
struct NTPPacketData
|
||||
{
|
||||
Poco::Int8 mode:3;
|
||||
Poco::Int8 vn:3;
|
||||
@@ -149,9 +149,10 @@ Poco::Timestamp NTPPacket::transmitTime() const
|
||||
Poco::Timestamp NTPPacket::convertTime(Poco::Int64 tm) const
|
||||
{
|
||||
const unsigned long seventyYears = 2208988800UL;
|
||||
Poco::UInt32 secsSince1900 = UInt32(Poco::ByteOrder::toLittleEndian(tm) >> 32);
|
||||
unsigned long epoch = secsSince1900 - seventyYears;
|
||||
return Poco::Timestamp::fromEpochTime(epoch);
|
||||
Poco::UInt64 ntpTime = Poco::ByteOrder::toLittleEndian(tm);
|
||||
Poco::UInt64 secs = ((ntpTime >> 32) - seventyYears) * 1000000;
|
||||
Poco::UInt64 frac = ((ntpTime & 0xFFFFFFFF) * 1000000) >> 32;
|
||||
return Poco::Timestamp(secs+frac);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+9
-9
@@ -63,12 +63,12 @@ NameValueCollection& NameValueCollection::operator = (NameValueCollection&& nvc)
|
||||
}
|
||||
|
||||
|
||||
void NameValueCollection::swap(NameValueCollection& nvc)
|
||||
void NameValueCollection::swap(NameValueCollection& nvc) noexcept
|
||||
{
|
||||
std::swap(_map, nvc._map);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::string& NameValueCollection::operator [] (const std::string& name) const
|
||||
{
|
||||
ConstIterator it = _map.find(name);
|
||||
@@ -78,8 +78,8 @@ const std::string& NameValueCollection::operator [] (const std::string& name) co
|
||||
throw NotFoundException(name);
|
||||
}
|
||||
|
||||
|
||||
void NameValueCollection::set(const std::string& name, const std::string& value)
|
||||
|
||||
void NameValueCollection::set(const std::string& name, const std::string& value)
|
||||
{
|
||||
Iterator it = _map.find(name);
|
||||
if (it != _map.end())
|
||||
@@ -88,13 +88,13 @@ void NameValueCollection::set(const std::string& name, const std::string& value)
|
||||
_map.insert(HeaderMap::ValueType(name, value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void NameValueCollection::add(const std::string& name, const std::string& value)
|
||||
{
|
||||
_map.insert(HeaderMap::ValueType(name, value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::string& NameValueCollection::get(const std::string& name) const
|
||||
{
|
||||
ConstIterator it = _map.find(name);
|
||||
@@ -126,19 +126,19 @@ NameValueCollection::ConstIterator NameValueCollection::find(const std::string&
|
||||
return _map.find(name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
NameValueCollection::ConstIterator NameValueCollection::begin() const
|
||||
{
|
||||
return _map.begin();
|
||||
}
|
||||
|
||||
|
||||
|
||||
NameValueCollection::ConstIterator NameValueCollection::end() const
|
||||
{
|
||||
return _map.end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool NameValueCollection::empty() const
|
||||
{
|
||||
return _map.empty();
|
||||
|
||||
+1
-1
@@ -637,7 +637,7 @@ NetworkInterface& NetworkInterface::operator = (const NetworkInterface& interfc)
|
||||
}
|
||||
|
||||
|
||||
void NetworkInterface::swap(NetworkInterface& other)
|
||||
void NetworkInterface::swap(NetworkInterface& other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(_pImpl, other._pImpl);
|
||||
|
||||
+15
-15
@@ -128,7 +128,7 @@ void OAuth10Credentials::authenticate(HTTPRequest& request, const Poco::URI& uri
|
||||
authenticate(request, uri, emptyParams, method);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OAuth10Credentials::authenticate(HTTPRequest& request, const Poco::URI& uri, const Poco::Net::HTMLForm& params, SignatureMethod method)
|
||||
{
|
||||
if (method == SIGN_PLAINTEXT)
|
||||
@@ -165,27 +165,27 @@ bool OAuth10Credentials::verify(const HTTPRequest& request, const Poco::URI& uri
|
||||
|
||||
std::string version = oauthParams.get("oauth_version", "1.0");
|
||||
if (version != "1.0") throw NotAuthenticatedException("Unsupported OAuth version", version);
|
||||
|
||||
|
||||
_consumerKey.clear();
|
||||
std::string consumerKey = oauthParams.get("oauth_consumer_key", "");
|
||||
URI::decode(consumerKey, _consumerKey);
|
||||
|
||||
|
||||
_token.clear();
|
||||
std::string token = oauthParams.get("oauth_token", "");
|
||||
URI::decode(token, _token);
|
||||
|
||||
|
||||
_callback.clear();
|
||||
std::string callback = oauthParams.get("oauth_callback", "");
|
||||
URI::decode(callback, _callback);
|
||||
|
||||
|
||||
std::string nonceEnc = oauthParams.get("oauth_nonce", "");
|
||||
std::string nonce;
|
||||
URI::decode(nonceEnc, nonce);
|
||||
|
||||
|
||||
std::string timestamp = oauthParams.get("oauth_timestamp", "");
|
||||
|
||||
|
||||
std::string method = oauthParams.get("oauth_signature_method", "");
|
||||
|
||||
|
||||
std::string signatureEnc = oauthParams.get("oauth_signature", "");
|
||||
std::string signature;
|
||||
URI::decode(signatureEnc, signature);
|
||||
@@ -205,8 +205,8 @@ bool OAuth10Credentials::verify(const HTTPRequest& request, const Poco::URI& uri
|
||||
refSignature = createSignature(request, uriWithoutQuery.toString(), params, nonce, timestamp);
|
||||
}
|
||||
else throw NotAuthenticatedException("Unsupported OAuth signature method", method);
|
||||
|
||||
return refSignature == signature;
|
||||
|
||||
return refSignature == signature;
|
||||
}
|
||||
else throw NotAuthenticatedException("No OAuth credentials found in Authorization header");
|
||||
}
|
||||
@@ -226,7 +226,7 @@ void OAuth10Credentials::signPlaintext(Poco::Net::HTTPRequest& request) const
|
||||
std::string signature(percentEncode(_consumerSecret));
|
||||
signature += '&';
|
||||
signature += percentEncode(_tokenSecret);
|
||||
|
||||
|
||||
std::string authorization(SCHEME);
|
||||
if (!_realm.empty())
|
||||
{
|
||||
@@ -322,7 +322,7 @@ std::string OAuth10Credentials::createSignature(const Poco::Net::HTTPRequest& re
|
||||
{
|
||||
paramsMap[percentEncode(p.first)] = percentEncode(p.second);
|
||||
}
|
||||
|
||||
|
||||
std::string paramsString;
|
||||
for (auto it = paramsMap.begin(); it != paramsMap.end(); ++it)
|
||||
{
|
||||
@@ -331,18 +331,18 @@ std::string OAuth10Credentials::createSignature(const Poco::Net::HTTPRequest& re
|
||||
paramsString += "=";
|
||||
paramsString += it->second;
|
||||
}
|
||||
|
||||
|
||||
std::string signatureBase = request.getMethod();
|
||||
signatureBase += '&';
|
||||
signatureBase += percentEncode(uri);
|
||||
signatureBase += '&';
|
||||
signatureBase += percentEncode(paramsString);
|
||||
|
||||
|
||||
std::string signingKey;
|
||||
signingKey += percentEncode(_consumerSecret);
|
||||
signingKey += '&';
|
||||
signingKey += percentEncode(_tokenSecret);
|
||||
|
||||
|
||||
Poco::HMACEngine<Poco::SHA1Engine> hmacEngine(signingKey);
|
||||
hmacEngine.update(signatureBase);
|
||||
Poco::DigestEngine::Digest digest = hmacEngine.digest();
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ void OAuth20Credentials::setScheme(const std::string& scheme)
|
||||
_scheme = scheme;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OAuth20Credentials::authenticate(HTTPRequest& request)
|
||||
{
|
||||
std::string auth(_scheme);
|
||||
|
||||
+8
-8
@@ -39,17 +39,17 @@ public:
|
||||
_socket(socket)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~DialogStreamBuf()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
int readFromDevice()
|
||||
{
|
||||
return _socket.get();
|
||||
}
|
||||
|
||||
|
||||
DialogSocket& _socket;
|
||||
};
|
||||
|
||||
@@ -62,11 +62,11 @@ public:
|
||||
{
|
||||
poco_ios_init(&_buf);
|
||||
}
|
||||
|
||||
|
||||
~DialogIOS()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
DialogStreamBuf* rdbuf()
|
||||
{
|
||||
return &_buf;
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
std::istream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~DialogInputStream()
|
||||
{
|
||||
}
|
||||
@@ -99,7 +99,7 @@ POP3ClientSession::POP3ClientSession(const StreamSocket& socket):
|
||||
}
|
||||
|
||||
|
||||
POP3ClientSession::POP3ClientSession(const std::string& host, Poco::UInt16 port):
|
||||
POP3ClientSession::POP3ClientSession(const std::string& host, Poco::UInt16 port):
|
||||
_socket(SocketAddress(host, port)),
|
||||
_isOpen(true)
|
||||
{
|
||||
@@ -123,7 +123,7 @@ void POP3ClientSession::setTimeout(const Poco::Timespan& timeout)
|
||||
_socket.setReceiveTimeout(timeout);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Poco::Timespan POP3ClientSession::getTimeout() const
|
||||
{
|
||||
return _socket.getReceiveTimeout();
|
||||
|
||||
Vendored
+1
-1
@@ -27,7 +27,7 @@ PartSource::PartSource():
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
PartSource::PartSource(const std::string& mediaType):
|
||||
_mediaType(mediaType)
|
||||
{
|
||||
|
||||
Vendored
+298
-179
@@ -18,23 +18,20 @@
|
||||
#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)
|
||||
#include <sys/epoll.h>
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
#include "Poco/Net/ServerSocket.h"
|
||||
#include "Poco/Net/SocketAddress.h"
|
||||
#include "wepoll.h"
|
||||
#else
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
#elif defined(POCO_HAVE_FD_POLL)
|
||||
#ifndef _WIN32
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
#include <poll.h>
|
||||
#include "Poco/Pipe.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -44,19 +41,44 @@ namespace Net {
|
||||
|
||||
#if defined(POCO_HAVE_FD_EPOLL)
|
||||
|
||||
//
|
||||
// Implementation using epoll (Linux) or wepoll (Windows)
|
||||
//
|
||||
|
||||
|
||||
#ifdef WEPOLL_H_
|
||||
|
||||
namespace {
|
||||
|
||||
int close(HANDLE h)
|
||||
{
|
||||
return epoll_close(h);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // WEPOLL_H_
|
||||
|
||||
|
||||
//
|
||||
// Linux implementation using epoll
|
||||
//
|
||||
class PollSetImpl
|
||||
{
|
||||
public:
|
||||
PollSetImpl():
|
||||
_epollfd(-1),
|
||||
_events(1024)
|
||||
using Mutex = Poco::FastMutex;
|
||||
using ScopedLock = Mutex::ScopedLock;
|
||||
using SocketMode = std::pair<Socket, int>;
|
||||
using SocketMap = std::map<void*, SocketMode>;
|
||||
|
||||
PollSetImpl(): _events(1024),
|
||||
_port(0),
|
||||
_eventfd(eventfd(_port, 0)),
|
||||
_epollfd(epoll_create(1))
|
||||
{
|
||||
_epollfd = epoll_create(1);
|
||||
if (_epollfd < 0)
|
||||
int err = addFD(_eventfd, PollSet::POLL_READ, EPOLL_CTL_ADD);
|
||||
#ifdef WEPOLL_H_
|
||||
if ((err) || !_epollfd)
|
||||
#else
|
||||
if ((err) || (_epollfd < 0))
|
||||
#endif
|
||||
{
|
||||
SocketImpl::error();
|
||||
}
|
||||
@@ -64,69 +86,204 @@ public:
|
||||
|
||||
~PollSetImpl()
|
||||
{
|
||||
if (_epollfd >= 0)
|
||||
::close(_epollfd);
|
||||
#ifdef WEPOLL_H_
|
||||
if (_eventfd >= 0) eventfd(_port, _eventfd);
|
||||
if (_epollfd) close(_epollfd);
|
||||
#else
|
||||
if (_eventfd > 0) close(_eventfd.exchange(0));
|
||||
if (_epollfd >= 0) close(_epollfd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void add(const Socket& socket, int mode)
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
SocketImpl* sockImpl = socket.impl();
|
||||
poco_socket_t fd = sockImpl->sockfd();
|
||||
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 = socket.impl();
|
||||
int err = epoll_ctl(_epollfd, EPOLL_CTL_ADD, fd, &ev);
|
||||
|
||||
int newMode = getNewMode(socket.impl(), mode);
|
||||
int err = addImpl(socket, newMode);
|
||||
if (err)
|
||||
{
|
||||
if (errno == EEXIST) update(socket, mode);
|
||||
if (errno == EEXIST) update(socket, newMode);
|
||||
else SocketImpl::error();
|
||||
}
|
||||
}
|
||||
|
||||
if (_socketMap.find(sockImpl) == _socketMap.end())
|
||||
_socketMap[sockImpl] = socket;
|
||||
void update(const Socket& socket, int mode)
|
||||
{
|
||||
int err = updateImpl(socket, mode);
|
||||
if (err) SocketImpl::error();
|
||||
}
|
||||
|
||||
void remove(const Socket& socket)
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
poco_socket_t fd = socket.impl()->sockfd();
|
||||
struct epoll_event ev;
|
||||
ev.events = 0;
|
||||
ev.data.ptr = 0;
|
||||
|
||||
int err = epoll_ctl(_epollfd, EPOLL_CTL_DEL, fd, &ev);
|
||||
if (err) SocketImpl::error();
|
||||
|
||||
ScopedLock lock(_mutex);
|
||||
_socketMap.erase(socket.impl());
|
||||
}
|
||||
|
||||
bool has(const Socket& socket) const
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
SocketImpl* sockImpl = socket.impl();
|
||||
ScopedLock lock(_mutex);
|
||||
return sockImpl &&
|
||||
(_socketMap.find(sockImpl) != _socketMap.end());
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
ScopedLock lock(_mutex);
|
||||
return _socketMap.empty();
|
||||
}
|
||||
|
||||
void update(const Socket& socket, int mode)
|
||||
void clear()
|
||||
{
|
||||
poco_socket_t fd = socket.impl()->sockfd();
|
||||
struct epoll_event ev;
|
||||
{
|
||||
ScopedLock lock(_mutex);
|
||||
|
||||
close(_epollfd);
|
||||
_socketMap.clear();
|
||||
_epollfd = epoll_create(1);
|
||||
#ifdef WEPOLL_H_
|
||||
if (!_epollfd) SocketImpl::error();
|
||||
#else
|
||||
if (_epollfd < 0) SocketImpl::error();
|
||||
#endif
|
||||
}
|
||||
#ifdef WEPOLL_H_
|
||||
eventfd(_port, _eventfd);
|
||||
_eventfd = eventfd(_port);
|
||||
#else
|
||||
close(_eventfd.exchange(0));
|
||||
_eventfd = eventfd(0, 0);
|
||||
#endif
|
||||
addFD(_eventfd, PollSet::POLL_READ, EPOLL_CTL_ADD);
|
||||
}
|
||||
|
||||
PollSet::SocketModeMap poll(const Poco::Timespan& timeout)
|
||||
{
|
||||
PollSet::SocketModeMap result;
|
||||
Poco::Timespan remainingTime(timeout);
|
||||
int rc;
|
||||
|
||||
ScopedLock lock(_mutex);
|
||||
do
|
||||
{
|
||||
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 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
|
||||
// the call enough room once we start hitting the boundary
|
||||
if (rc >= _events.size()) _events.resize(_events.size()*2);
|
||||
else if (rc < 0)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
else SocketImpl::error();
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
|
||||
for (int i = 0; i < rc; i++)
|
||||
{
|
||||
if (_events[i].data.ptr) // skip eventfd
|
||||
{
|
||||
SocketMap::iterator it = _socketMap.find(_events[i].data.ptr);
|
||||
if (it != _socketMap.end())
|
||||
{
|
||||
if (_events[i].events & EPOLLIN)
|
||||
result[it->second.first] |= PollSet::POLL_READ;
|
||||
if (_events[i].events & EPOLLOUT)
|
||||
result[it->second.first] |= PollSet::POLL_WRITE;
|
||||
if (_events[i].events & EPOLLERR)
|
||||
result[it->second.first] |= PollSet::POLL_ERROR;
|
||||
}
|
||||
}
|
||||
else if (_events[i].events & EPOLLIN) // eventfd signaled
|
||||
{
|
||||
uint64_t val;
|
||||
#ifdef WEPOLL_H_
|
||||
if (_pSocket && _pSocket->available())
|
||||
_pSocket->impl()->receiveBytes(&val, sizeof(val));
|
||||
#else
|
||||
read(_eventfd, &val, sizeof(val));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void wakeUp()
|
||||
{
|
||||
#ifdef WEPOLL_H_
|
||||
StreamSocket ss(SocketAddress("127.0.0.1", _port));
|
||||
#else
|
||||
uint64_t val = 1;
|
||||
// This is guaranteed to write into a valid fd,
|
||||
// or 0 (meaning PollSet is being destroyed).
|
||||
// Errors are ignored.
|
||||
write(_eventfd, &val, sizeof(val));
|
||||
#endif
|
||||
}
|
||||
|
||||
int count() const
|
||||
{
|
||||
ScopedLock lock(_mutex);
|
||||
return static_cast<int>(_socketMap.size());
|
||||
}
|
||||
|
||||
private:
|
||||
int getNewMode(SocketImpl* sockImpl, int mode)
|
||||
{
|
||||
ScopedLock lock(_mutex);
|
||||
auto it = _socketMap.find(sockImpl);
|
||||
if (it != _socketMap.end())
|
||||
mode |= it->second.second;
|
||||
return mode;
|
||||
}
|
||||
|
||||
void socketMapUpdate(const Socket& socket, int mode)
|
||||
{
|
||||
SocketImpl* sockImpl = socket.impl();
|
||||
ScopedLock lock(_mutex);
|
||||
_socketMap[sockImpl] = {socket, mode};
|
||||
}
|
||||
|
||||
int updateImpl(const Socket& socket, int mode)
|
||||
{
|
||||
SocketImpl* sockImpl = socket.impl();
|
||||
int ret = addFD(static_cast<int>(sockImpl->sockfd()), mode, EPOLL_CTL_MOD, sockImpl);
|
||||
if (ret == 0) socketMapUpdate(socket, mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int addImpl(const Socket& socket, int mode)
|
||||
{
|
||||
SocketImpl* sockImpl = socket.impl();
|
||||
int newMode = getNewMode(sockImpl, mode);
|
||||
int ret = addFD(static_cast<int>(sockImpl->sockfd()), newMode, EPOLL_CTL_ADD, sockImpl);
|
||||
if (ret == 0) socketMapUpdate(socket, newMode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int addFD(int fd, int mode, int op, void* ptr = 0)
|
||||
{
|
||||
struct epoll_event ev{};
|
||||
ev.events = 0;
|
||||
if (mode & PollSet::POLL_READ)
|
||||
ev.events |= EPOLLIN;
|
||||
@@ -134,79 +291,43 @@ public:
|
||||
ev.events |= EPOLLOUT;
|
||||
if (mode & PollSet::POLL_ERROR)
|
||||
ev.events |= EPOLLERR;
|
||||
ev.data.ptr = socket.impl();
|
||||
int err = epoll_ctl(_epollfd, EPOLL_CTL_MOD, fd, &ev);
|
||||
if (err)
|
||||
{
|
||||
SocketImpl::error();
|
||||
}
|
||||
ev.data.ptr = ptr;
|
||||
return epoll_ctl(_epollfd, op, fd, &ev);
|
||||
}
|
||||
|
||||
void clear()
|
||||
#ifdef WEPOLL_H_
|
||||
|
||||
int eventfd(int& port, int rmFD = 0)
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
::close(_epollfd);
|
||||
_socketMap.clear();
|
||||
_epollfd = epoll_create(1);
|
||||
if (_epollfd < 0)
|
||||
if (rmFD == 0)
|
||||
{
|
||||
SocketImpl::error();
|
||||
_pSocket = new ServerSocket(SocketAddress("127.0.0.1", 0));
|
||||
_pSocket->setBlocking(false);
|
||||
port = _pSocket->address().port();
|
||||
return static_cast<int>(_pSocket->impl()->sockfd());
|
||||
}
|
||||
else
|
||||
{
|
||||
delete _pSocket;
|
||||
_pSocket = 0;
|
||||
port = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PollSet::SocketModeMap poll(const Poco::Timespan& timeout)
|
||||
{
|
||||
PollSet::SocketModeMap result;
|
||||
#endif // WEPOLL_H_
|
||||
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
if(_socketMap.empty()) return result;
|
||||
}
|
||||
|
||||
Poco::Timespan remainingTime(timeout);
|
||||
int rc;
|
||||
do
|
||||
{
|
||||
Poco::Timestamp start;
|
||||
rc = epoll_wait(_epollfd, &_events[0], _events.size(), remainingTime.totalMilliseconds());
|
||||
if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
|
||||
{
|
||||
Poco::Timestamp end;
|
||||
Poco::Timespan waited = end - start;
|
||||
if (waited < remainingTime)
|
||||
remainingTime -= waited;
|
||||
else
|
||||
remainingTime = 0;
|
||||
}
|
||||
}
|
||||
while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
|
||||
if (rc < 0) SocketImpl::error();
|
||||
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
for (int i = 0; i < rc; i++)
|
||||
{
|
||||
std::map<void*, Socket>::iterator it = _socketMap.find(_events[i].data.ptr);
|
||||
if (it != _socketMap.end())
|
||||
{
|
||||
if (_events[i].events & EPOLLIN)
|
||||
result[it->second] |= PollSet::POLL_READ;
|
||||
if (_events[i].events & EPOLLOUT)
|
||||
result[it->second] |= PollSet::POLL_WRITE;
|
||||
if (_events[i].events & EPOLLERR)
|
||||
result[it->second] |= PollSet::POLL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable Poco::FastMutex _mutex;
|
||||
int _epollfd;
|
||||
std::map<void*, Socket> _socketMap;
|
||||
mutable Mutex _mutex;
|
||||
SocketMap _socketMap;
|
||||
std::vector<struct epoll_event> _events;
|
||||
int _port;
|
||||
std::atomic<int> _eventfd;
|
||||
#ifdef WEPOLL_H_
|
||||
std::atomic <HANDLE> _epollfd;
|
||||
ServerSocket* _pSocket;
|
||||
#else
|
||||
std::atomic<int> _epollfd;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -219,12 +340,22 @@ private:
|
||||
class PollSetImpl
|
||||
{
|
||||
public:
|
||||
PollSetImpl()
|
||||
{
|
||||
pollfd fd{_pipe.readHandle(), POLLIN, 0};
|
||||
_pollfds.push_back(fd);
|
||||
}
|
||||
|
||||
~PollSetImpl()
|
||||
{
|
||||
_pipe.close();
|
||||
}
|
||||
|
||||
void add(const Socket& socket, int mode)
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
poco_socket_t fd = socket.impl()->sockfd();
|
||||
_addMap[fd] = mode;
|
||||
_addMap[fd] |= mode;
|
||||
_removeSet.erase(fd);
|
||||
_socketMap[fd] = socket;
|
||||
}
|
||||
@@ -232,7 +363,6 @@ public:
|
||||
void remove(const Socket& socket)
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
poco_socket_t fd = socket.impl()->sockfd();
|
||||
_removeSet.insert(fd);
|
||||
_addMap.erase(fd);
|
||||
@@ -256,7 +386,6 @@ public:
|
||||
void update(const Socket& socket, int mode)
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
poco_socket_t fd = socket.impl()->sockfd();
|
||||
for (auto it = _pollfds.begin(); it != _pollfds.end(); ++it)
|
||||
{
|
||||
@@ -264,7 +393,7 @@ public:
|
||||
{
|
||||
it->events = 0;
|
||||
it->revents = 0;
|
||||
setMode(it->fd, it->events, mode);
|
||||
setMode(it->events, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,7 +405,7 @@ public:
|
||||
_socketMap.clear();
|
||||
_addMap.clear();
|
||||
_removeSet.clear();
|
||||
_pollfds.clear();
|
||||
_pollfds.reserve(1);
|
||||
}
|
||||
|
||||
PollSet::SocketModeMap poll(const Poco::Timespan& timeout)
|
||||
@@ -305,7 +434,7 @@ public:
|
||||
pfd.fd = it->first;
|
||||
pfd.events = 0;
|
||||
pfd.revents = 0;
|
||||
setMode(pfd.fd, pfd.events, it->second);
|
||||
setMode(pfd.events, it->second);
|
||||
_pollfds.push_back(pfd);
|
||||
}
|
||||
_addMap.clear();
|
||||
@@ -318,17 +447,7 @@ public:
|
||||
do
|
||||
{
|
||||
Poco::Timestamp start;
|
||||
#ifdef _WIN32
|
||||
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
|
||||
rc = ::poll(&_pollfds[0], _pollfds.size(), remainingTime.totalMilliseconds());
|
||||
#endif
|
||||
if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
|
||||
{
|
||||
Poco::Timestamp end;
|
||||
@@ -343,28 +462,26 @@ public:
|
||||
if (rc < 0) SocketImpl::error();
|
||||
|
||||
{
|
||||
if (_pollfds[0].revents & POLLIN)
|
||||
{
|
||||
char c;
|
||||
_pipe.readBytes(&c, 1);
|
||||
}
|
||||
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
if (!_socketMap.empty())
|
||||
{
|
||||
for (auto it = _pollfds.begin(); it != _pollfds.end(); ++it)
|
||||
for (auto it = _pollfds.begin() + 1; it != _pollfds.end(); ++it)
|
||||
{
|
||||
std::map<poco_socket_t, Socket>::const_iterator its = _socketMap.find(it->fd);
|
||||
if (its != _socketMap.end())
|
||||
{
|
||||
if ((it->revents & POLLIN)
|
||||
#ifdef _WIN32
|
||||
|| (it->revents & POLLHUP)
|
||||
#endif
|
||||
)
|
||||
if (it->revents & POLLIN)
|
||||
result[its->second] |= PollSet::POLL_READ;
|
||||
if ((it->revents & POLLOUT)
|
||||
#ifdef _WIN32
|
||||
&& (_wantPOLLOUT.find(it->fd) != _wantPOLLOUT.end())
|
||||
#endif
|
||||
)
|
||||
if (it->revents & POLLOUT)
|
||||
result[its->second] |= PollSet::POLL_WRITE;
|
||||
if (it->revents & POLLERR)
|
||||
if (it->revents & POLLERR || (it->revents & POLLHUP))
|
||||
result[its->second] |= PollSet::POLL_ERROR;
|
||||
}
|
||||
it->revents = 0;
|
||||
@@ -375,38 +492,21 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
void wakeUp()
|
||||
{
|
||||
char c = 1;
|
||||
_pipe.writeBytes(&c, 1);
|
||||
}
|
||||
|
||||
int count() const
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
return static_cast<int>(_socketMap.size());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
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)
|
||||
void setMode(short& target, int mode)
|
||||
{
|
||||
if (mode & PollSet::POLL_READ)
|
||||
target |= POLLIN;
|
||||
@@ -415,16 +515,12 @@ private:
|
||||
target |= POLLOUT;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
mutable Poco::FastMutex _mutex;
|
||||
std::map<poco_socket_t, Socket> _socketMap;
|
||||
#ifdef _WIN32
|
||||
std::set<poco_socket_t> _wantPOLLOUT;
|
||||
#endif
|
||||
std::map<poco_socket_t, int> _addMap;
|
||||
std::set<poco_socket_t> _removeSet;
|
||||
std::vector<pollfd> _pollfds;
|
||||
Poco::Pipe _pipe;
|
||||
};
|
||||
|
||||
|
||||
@@ -562,6 +658,17 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
void wakeUp()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
int count() const
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
return static_cast<int>(_map.size());
|
||||
}
|
||||
|
||||
private:
|
||||
mutable Poco::FastMutex _mutex;
|
||||
PollSet::SocketModeMap _map;
|
||||
@@ -625,4 +732,16 @@ PollSet::SocketModeMap PollSet::poll(const Poco::Timespan& timeout)
|
||||
}
|
||||
|
||||
|
||||
int PollSet::count() const
|
||||
{
|
||||
return _pImpl->count();
|
||||
}
|
||||
|
||||
|
||||
void PollSet::wakeUp()
|
||||
{
|
||||
_pImpl->wakeUp();
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
+3
-3
@@ -27,7 +27,7 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
QuotedPrintableDecoderBuf::QuotedPrintableDecoderBuf(std::istream& istr):
|
||||
QuotedPrintableDecoderBuf::QuotedPrintableDecoderBuf(std::istream& istr):
|
||||
_buf(*istr.rdbuf())
|
||||
{
|
||||
}
|
||||
@@ -87,8 +87,8 @@ QuotedPrintableDecoderBuf* QuotedPrintableDecoderIOS::rdbuf()
|
||||
}
|
||||
|
||||
|
||||
QuotedPrintableDecoder::QuotedPrintableDecoder(std::istream& istr):
|
||||
QuotedPrintableDecoderIOS(istr),
|
||||
QuotedPrintableDecoder::QuotedPrintableDecoder(std::istream& istr):
|
||||
QuotedPrintableDecoderIOS(istr),
|
||||
std::istream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
+3
-3
@@ -24,7 +24,7 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
QuotedPrintableEncoderBuf::QuotedPrintableEncoderBuf(std::ostream& ostr):
|
||||
QuotedPrintableEncoderBuf::QuotedPrintableEncoderBuf(std::ostream& ostr):
|
||||
_pending(-1),
|
||||
_lineLength(0),
|
||||
_ostr(ostr)
|
||||
@@ -135,8 +135,8 @@ QuotedPrintableEncoderBuf* QuotedPrintableEncoderIOS::rdbuf()
|
||||
}
|
||||
|
||||
|
||||
QuotedPrintableEncoder::QuotedPrintableEncoder(std::ostream& ostr):
|
||||
QuotedPrintableEncoderIOS(ostr),
|
||||
QuotedPrintableEncoder::QuotedPrintableEncoder(std::ostream& ostr):
|
||||
QuotedPrintableEncoderIOS(ostr),
|
||||
std::ostream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
Vendored
+45
-3
@@ -24,19 +24,19 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
RawSocket::RawSocket():
|
||||
RawSocket::RawSocket():
|
||||
Socket(new RawSocketImpl)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RawSocket::RawSocket(SocketAddress::Family family, int proto):
|
||||
RawSocket::RawSocket(SocketAddress::Family family, int proto):
|
||||
Socket(new RawSocketImpl(family, proto))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RawSocket::RawSocket(const SocketAddress& address, bool reuseAddress):
|
||||
RawSocket::RawSocket(const SocketAddress& address, bool reuseAddress):
|
||||
Socket(new RawSocketImpl(address.family()))
|
||||
{
|
||||
bind(address, reuseAddress);
|
||||
@@ -50,6 +50,18 @@ RawSocket::RawSocket(const Socket& socket): Socket(socket)
|
||||
}
|
||||
|
||||
|
||||
RawSocket::RawSocket(const RawSocket& socket): Socket(socket)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef POCO_NEW_STATE_ON_MOVE
|
||||
|
||||
RawSocket::RawSocket(RawSocket&& socket): Socket(std::move(socket))
|
||||
{
|
||||
}
|
||||
|
||||
#endif // POCO_NEW_STATE_ON_MOVE
|
||||
|
||||
RawSocket::RawSocket(SocketImpl* pImpl): Socket(pImpl)
|
||||
{
|
||||
if (!dynamic_cast<RawSocketImpl*>(impl()))
|
||||
@@ -72,6 +84,36 @@ RawSocket& RawSocket::operator = (const Socket& socket)
|
||||
}
|
||||
|
||||
|
||||
#ifdef POCO_NEW_STATE_ON_MOVE
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif // POCO_NEW_STATE_ON_MOVE
|
||||
|
||||
RawSocket& RawSocket::operator = (const RawSocket& socket)
|
||||
{
|
||||
Socket::operator = (socket);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
#ifdef POCO_NEW_STATE_ON_MOVE
|
||||
|
||||
RawSocket& RawSocket::operator = (RawSocket&& socket)
|
||||
{
|
||||
Socket::operator = (std::move(socket));
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif // POCO_NEW_STATE_ON_MOVE
|
||||
|
||||
void RawSocket::connect(const SocketAddress& address)
|
||||
{
|
||||
impl()->connect(address);
|
||||
|
||||
+2
-2
@@ -41,8 +41,8 @@ RawSocketImpl::RawSocketImpl(SocketAddress::Family family, int proto)
|
||||
|
||||
}
|
||||
|
||||
|
||||
RawSocketImpl::RawSocketImpl(poco_socket_t sockfd):
|
||||
|
||||
RawSocketImpl::RawSocketImpl(poco_socket_t sockfd):
|
||||
SocketImpl(sockfd)
|
||||
{
|
||||
}
|
||||
|
||||
+63
-6
@@ -49,7 +49,7 @@ RemoteSyslogChannel::RemoteSyslogChannel():
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
RemoteSyslogChannel::RemoteSyslogChannel(const std::string& address, const std::string& name, int facility, bool bsdFormat):
|
||||
_logHost(address),
|
||||
_name(name),
|
||||
@@ -107,7 +107,7 @@ void RemoteSyslogChannel::open()
|
||||
_open = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RemoteSyslogChannel::close()
|
||||
{
|
||||
if (_open)
|
||||
@@ -117,7 +117,7 @@ void RemoteSyslogChannel::close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RemoteSyslogChannel::log(const Message& msg)
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
@@ -163,7 +163,7 @@ void RemoteSyslogChannel::log(const Message& msg)
|
||||
_socket.sendTo(m.data(), static_cast<int>(m.size()), _socketAddress);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RemoteSyslogChannel::setProperty(const std::string& name, const std::string& value)
|
||||
{
|
||||
if (name == PROP_NAME)
|
||||
@@ -180,7 +180,7 @@ void RemoteSyslogChannel::setProperty(const std::string& name, const std::string
|
||||
facility = Poco::toUpper(value.substr(7));
|
||||
else
|
||||
facility = Poco::toUpper(value);
|
||||
|
||||
|
||||
if (facility == "KERN")
|
||||
_facility = SYSLOG_KERN;
|
||||
else if (facility == "USER")
|
||||
@@ -252,7 +252,7 @@ void RemoteSyslogChannel::setProperty(const std::string& name, const std::string
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string RemoteSyslogChannel::getProperty(const std::string& name) const
|
||||
{
|
||||
if (name == PROP_NAME)
|
||||
@@ -362,6 +362,63 @@ int RemoteSyslogChannel::getPrio(const Message& msg)
|
||||
}
|
||||
}
|
||||
|
||||
const char* RemoteSyslogChannel::facilityToString(const Facility facility)
|
||||
{
|
||||
switch(facility)
|
||||
{
|
||||
case RemoteSyslogChannel::SYSLOG_KERN:
|
||||
return "KERN";
|
||||
case RemoteSyslogChannel::SYSLOG_USER:
|
||||
return "USER";
|
||||
case RemoteSyslogChannel::SYSLOG_MAIL:
|
||||
return "MAIL";
|
||||
case RemoteSyslogChannel::SYSLOG_DAEMON:
|
||||
return "DAEMON";
|
||||
case RemoteSyslogChannel::SYSLOG_AUTH:
|
||||
return "AUTH";
|
||||
case RemoteSyslogChannel::SYSLOG_SYSLOG:
|
||||
return "SYSLOG";
|
||||
case RemoteSyslogChannel::SYSLOG_LPR:
|
||||
return "LPR";
|
||||
case RemoteSyslogChannel::SYSLOG_NEWS:
|
||||
return "NEWS";
|
||||
case RemoteSyslogChannel::SYSLOG_UUCP:
|
||||
return "UUCP";
|
||||
case RemoteSyslogChannel::SYSLOG_CRON:
|
||||
return "CRON";
|
||||
case RemoteSyslogChannel::SYSLOG_AUTHPRIV:
|
||||
return "AUTHPRIV";
|
||||
case RemoteSyslogChannel::SYSLOG_FTP:
|
||||
return "FTP";
|
||||
case RemoteSyslogChannel::SYSLOG_NTP:
|
||||
return "NTP";
|
||||
case RemoteSyslogChannel::SYSLOG_LOGAUDIT:
|
||||
return "LOGAUDIT";
|
||||
case RemoteSyslogChannel::SYSLOG_LOGALERT:
|
||||
return "LOGALERT";
|
||||
case RemoteSyslogChannel::SYSLOG_CLOCK:
|
||||
return "CLOCK";
|
||||
case RemoteSyslogChannel::SYSLOG_LOCAL0:
|
||||
return "LOCAL0";
|
||||
case RemoteSyslogChannel::SYSLOG_LOCAL1:
|
||||
return "LOCAL1";
|
||||
case RemoteSyslogChannel::SYSLOG_LOCAL2:
|
||||
return "LOCAL2";
|
||||
case RemoteSyslogChannel::SYSLOG_LOCAL3:
|
||||
return "LOCAL3";
|
||||
case RemoteSyslogChannel::SYSLOG_LOCAL4:
|
||||
return "LOCAL4";
|
||||
case RemoteSyslogChannel::SYSLOG_LOCAL5:
|
||||
return "LOCAL5";
|
||||
case RemoteSyslogChannel::SYSLOG_LOCAL6:
|
||||
return "LOCAL6";
|
||||
case RemoteSyslogChannel::SYSLOG_LOCAL7:
|
||||
return "LOCAL7";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RemoteSyslogChannel::registerChannel()
|
||||
{
|
||||
|
||||
+5
-2
@@ -96,7 +96,7 @@ public:
|
||||
private:
|
||||
Poco::NotificationQueue& _queue;
|
||||
DatagramSocket _socket;
|
||||
bool _stopped;
|
||||
std::atomic<bool> _stopped;
|
||||
};
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ private:
|
||||
|
||||
private:
|
||||
Poco::NotificationQueue& _queue;
|
||||
bool _stopped;
|
||||
std::atomic<bool> _stopped;
|
||||
RemoteSyslogListener* _pListener;
|
||||
};
|
||||
|
||||
@@ -312,6 +312,7 @@ void SyslogParser::parseNew(const std::string& line, RemoteSyslogChannel::Severi
|
||||
int tzd = 0;
|
||||
bool hasDate = Poco::DateTimeParser::tryParse(RemoteSyslogChannel::SYSLOG_TIMEFORMAT, timeStr, date, tzd);
|
||||
Poco::Message logEntry(msgId, messageText, prio);
|
||||
logEntry[RemoteSyslogListener::LOG_PROP_FACILITY] = RemoteSyslogChannel::facilityToString(fac);
|
||||
logEntry[RemoteSyslogListener::LOG_PROP_HOST] = hostName;
|
||||
logEntry[RemoteSyslogListener::LOG_PROP_APP] = appName;
|
||||
logEntry[RemoteSyslogListener::LOG_PROP_STRUCTURED_DATA] = sd;
|
||||
@@ -390,6 +391,7 @@ void SyslogParser::parseBSD(const std::string& line, RemoteSyslogChannel::Severi
|
||||
pos = line.size();
|
||||
Poco::Message logEntry(hostName, messageText, prio);
|
||||
logEntry.setTime(date.timestamp());
|
||||
logEntry[RemoteSyslogListener::LOG_PROP_FACILITY] = RemoteSyslogChannel::facilityToString(fac);
|
||||
message.swap(logEntry);
|
||||
}
|
||||
|
||||
@@ -501,6 +503,7 @@ const std::string RemoteSyslogListener::PROP_REUSE_PORT("reusePort");
|
||||
const std::string RemoteSyslogListener::PROP_THREADS("threads");
|
||||
const std::string RemoteSyslogListener::PROP_BUFFER("buffer");
|
||||
|
||||
const std::string RemoteSyslogListener::LOG_PROP_FACILITY("facility");
|
||||
const std::string RemoteSyslogListener::LOG_PROP_APP("app");
|
||||
const std::string RemoteSyslogListener::LOG_PROP_HOST("host");
|
||||
const std::string RemoteSyslogListener::LOG_PROP_STRUCTURED_DATA("structured-data");
|
||||
|
||||
Vendored
+29
-29
@@ -52,7 +52,7 @@ SMTPChannel::SMTPChannel():
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
SMTPChannel::SMTPChannel(const std::string& mailhost, const std::string& sender, const std::string& recipient):
|
||||
_mailHost(mailhost),
|
||||
_sender(sender),
|
||||
@@ -82,12 +82,12 @@ void SMTPChannel::open()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SMTPChannel::close()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SMTPChannel::log(const Message& msg)
|
||||
{
|
||||
try
|
||||
@@ -116,7 +116,7 @@ void SMTPChannel::log(const Message& msg)
|
||||
<< "Message text: " << msg.getText() << "\r\n\r\n";
|
||||
|
||||
message.addContent(new StringPartSource(content.str()));
|
||||
|
||||
|
||||
if (!_attachment.empty())
|
||||
{
|
||||
{
|
||||
@@ -132,7 +132,7 @@ void SMTPChannel::log(const Message& msg)
|
||||
fis.seekg(std::ios::beg);
|
||||
fis.read(pMem, size);
|
||||
message.addAttachment(_attachment,
|
||||
new StringPartSource(std::string(pMem, static_cast<SST>(size)),
|
||||
new StringPartSource(std::string(pMem, static_cast<SST>(size)),
|
||||
_type,
|
||||
_attachment));
|
||||
|
||||
@@ -146,54 +146,54 @@ void SMTPChannel::log(const Message& msg)
|
||||
session.login();
|
||||
session.sendMessage(message);
|
||||
session.close();
|
||||
}
|
||||
catch (Exception&)
|
||||
{
|
||||
if (_throw) throw;
|
||||
}
|
||||
catch (Exception&)
|
||||
{
|
||||
if (_throw) throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SMTPChannel::setProperty(const std::string& name, const std::string& value)
|
||||
{
|
||||
if (name == PROP_MAILHOST)
|
||||
if (name == PROP_MAILHOST)
|
||||
_mailHost = value;
|
||||
else if (name == PROP_SENDER)
|
||||
else if (name == PROP_SENDER)
|
||||
_sender = value;
|
||||
else if (name == PROP_RECIPIENT)
|
||||
else if (name == PROP_RECIPIENT)
|
||||
_recipient = value;
|
||||
else if (name == PROP_LOCAL)
|
||||
else if (name == PROP_LOCAL)
|
||||
_local = isTrue(value);
|
||||
else if (name == PROP_ATTACHMENT)
|
||||
else if (name == PROP_ATTACHMENT)
|
||||
_attachment = value;
|
||||
else if (name == PROP_TYPE)
|
||||
else if (name == PROP_TYPE)
|
||||
_type = value;
|
||||
else if (name == PROP_DELETE)
|
||||
else if (name == PROP_DELETE)
|
||||
_delete = isTrue(value);
|
||||
else if (name == PROP_THROW)
|
||||
else if (name == PROP_THROW)
|
||||
_throw = isTrue(value);
|
||||
else
|
||||
else
|
||||
Channel::setProperty(name, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string SMTPChannel::getProperty(const std::string& name) const
|
||||
{
|
||||
if (name == PROP_MAILHOST)
|
||||
if (name == PROP_MAILHOST)
|
||||
return _mailHost;
|
||||
else if (name == PROP_SENDER)
|
||||
else if (name == PROP_SENDER)
|
||||
return _sender;
|
||||
else if (name == PROP_RECIPIENT)
|
||||
else if (name == PROP_RECIPIENT)
|
||||
return _recipient;
|
||||
else if (name == PROP_LOCAL)
|
||||
else if (name == PROP_LOCAL)
|
||||
return _local ? "true" : "false";
|
||||
else if (name == PROP_ATTACHMENT)
|
||||
else if (name == PROP_ATTACHMENT)
|
||||
return _attachment;
|
||||
else if (name == PROP_TYPE)
|
||||
else if (name == PROP_TYPE)
|
||||
return _type;
|
||||
else if (name == PROP_DELETE)
|
||||
else if (name == PROP_DELETE)
|
||||
return _delete ? "true" : "false";
|
||||
else if (name == PROP_THROW)
|
||||
else if (name == PROP_THROW)
|
||||
return _throw ? "true" : "false";
|
||||
else
|
||||
return Channel::getProperty(name);
|
||||
@@ -202,7 +202,7 @@ std::string SMTPChannel::getProperty(const std::string& name) const
|
||||
|
||||
void SMTPChannel::registerChannel()
|
||||
{
|
||||
Poco::LoggingFactory::defaultFactory().registerChannelClass("SMTPChannel",
|
||||
Poco::LoggingFactory::defaultFactory().registerChannelClass("SMTPChannel",
|
||||
new Poco::Instantiator<SMTPChannel, Poco::Channel>);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -70,7 +70,7 @@ public:
|
||||
bool available()
|
||||
{
|
||||
PSecPkgInfoW pSecPkgInfo;
|
||||
SECURITY_STATUS status = _pSecFunTable->QuerySecurityPackageInfoW(L"NTLM", &pSecPkgInfo);
|
||||
SECURITY_STATUS status = _pSecFunTable->QuerySecurityPackageInfoW(const_cast< wchar_t* >(L"NTLM"), &pSecPkgInfo);
|
||||
if (status == SEC_E_OK)
|
||||
{
|
||||
_pSecFunTable->FreeContextBuffer(pSecPkgInfo);
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
Poco::SharedPtr<NTLMContext> createNTLMContext(const std::string& host, const std::string& service)
|
||||
{
|
||||
PSecPkgInfoW pSecPkgInfo;
|
||||
SECURITY_STATUS status = _pSecFunTable->QuerySecurityPackageInfoW(L"NTLM", &pSecPkgInfo);
|
||||
SECURITY_STATUS status = _pSecFunTable->QuerySecurityPackageInfoW(const_cast< wchar_t* >(L"NTLM"), &pSecPkgInfo);
|
||||
if (status != SEC_E_OK) throw Poco::SystemException("NTLM SSPI not available", status);
|
||||
|
||||
std::size_t maxTokenSize = pSecPkgInfo->cbMaxToken;
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
TimeStamp expiry;
|
||||
status = _pSecFunTable->AcquireCredentialsHandleW(
|
||||
NULL,
|
||||
L"NTLM",
|
||||
const_cast< wchar_t* >(L"NTLM"),
|
||||
SECPKG_CRED_OUTBOUND,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
Vendored
+2
-2
@@ -123,7 +123,7 @@ void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool ipV6Only)
|
||||
#endif // POCO_HAVE_IPv6
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool reusePort, bool ipV6Only)
|
||||
{
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
@@ -135,7 +135,7 @@ void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool reusePort, b
|
||||
#endif // POCO_HAVE_IPv6
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ServerSocket::listen(int backlog)
|
||||
{
|
||||
impl()->listen(backlog);
|
||||
|
||||
Vendored
+79
-138
@@ -14,14 +14,18 @@
|
||||
|
||||
#include "Poco/Net/Socket.h"
|
||||
#include "Poco/Net/StreamSocketImpl.h"
|
||||
#include "Poco/Net/PollSet.h"
|
||||
#include "Poco/Timestamp.h"
|
||||
#include "Poco/Error.h"
|
||||
#include <algorithm>
|
||||
#include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring>
|
||||
#if defined(POCO_HAVE_FD_EPOLL)
|
||||
#include <sys/epoll.h>
|
||||
#elif defined(POCO_HAVE_FD_POLL)
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include <poll.h>
|
||||
|
||||
|
||||
#if defined(POCO_HAVE_FD_POLL)
|
||||
#include "Poco/SharedPtr.h"
|
||||
#ifndef _WIN32
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -50,6 +54,30 @@ Socket::Socket(const Socket& socket):
|
||||
_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)
|
||||
{
|
||||
@@ -62,10 +90,9 @@ Socket& Socket::operator = (const Socket& socket)
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Socket::~Socket()
|
||||
{
|
||||
_pImpl->release();
|
||||
if (_pImpl) _pImpl->release();
|
||||
}
|
||||
|
||||
|
||||
@@ -73,142 +100,34 @@ int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exce
|
||||
{
|
||||
#if defined(POCO_HAVE_FD_EPOLL)
|
||||
|
||||
int epollSize = readList.size() + writeList.size() + exceptList.size();
|
||||
int epollSize = static_cast<int>(readList.size() + writeList.size() + exceptList.size());
|
||||
if (epollSize == 0) return 0;
|
||||
|
||||
int epollfd = -1;
|
||||
PollSet ps;
|
||||
for (const auto& s : readList) ps.add(s, PollSet::POLL_READ);
|
||||
for (const auto& s : writeList) ps.add(s, PollSet::POLL_WRITE);
|
||||
|
||||
readList.clear();
|
||||
writeList.clear();
|
||||
exceptList.clear();
|
||||
|
||||
PollSet::SocketModeMap sm = ps.poll(timeout);
|
||||
for (const auto& s : sm)
|
||||
{
|
||||
struct epoll_event eventsIn[epollSize];
|
||||
memset(eventsIn, 0, sizeof(eventsIn));
|
||||
struct epoll_event* eventLast = eventsIn;
|
||||
for (SocketList::iterator it = readList.begin(); it != readList.end(); ++it)
|
||||
{
|
||||
poco_socket_t sockfd = it->sockfd();
|
||||
if (sockfd != POCO_INVALID_SOCKET)
|
||||
{
|
||||
struct epoll_event* e = eventsIn;
|
||||
for (; e != eventLast; ++e)
|
||||
{
|
||||
if (reinterpret_cast<Socket*>(e->data.ptr)->sockfd() == sockfd)
|
||||
break;
|
||||
}
|
||||
if (e == eventLast)
|
||||
{
|
||||
e->data.ptr = &(*it);
|
||||
++eventLast;
|
||||
}
|
||||
e->events |= EPOLLIN;
|
||||
}
|
||||
}
|
||||
|
||||
for (SocketList::iterator it = writeList.begin(); it != writeList.end(); ++it)
|
||||
{
|
||||
poco_socket_t sockfd = it->sockfd();
|
||||
if (sockfd != POCO_INVALID_SOCKET)
|
||||
{
|
||||
struct epoll_event* e = eventsIn;
|
||||
for (; e != eventLast; ++e)
|
||||
{
|
||||
if (reinterpret_cast<Socket*>(e->data.ptr)->sockfd() == sockfd)
|
||||
break;
|
||||
}
|
||||
if (e == eventLast)
|
||||
{
|
||||
e->data.ptr = &(*it);
|
||||
++eventLast;
|
||||
}
|
||||
e->events |= EPOLLOUT;
|
||||
}
|
||||
}
|
||||
|
||||
for (SocketList::iterator it = exceptList.begin(); it != exceptList.end(); ++it)
|
||||
{
|
||||
poco_socket_t sockfd = it->sockfd();
|
||||
if (sockfd != POCO_INVALID_SOCKET)
|
||||
{
|
||||
struct epoll_event* e = eventsIn;
|
||||
for (; e != eventLast; ++e)
|
||||
{
|
||||
if (reinterpret_cast<Socket*>(e->data.ptr)->sockfd() == sockfd)
|
||||
break;
|
||||
}
|
||||
if (e == eventLast)
|
||||
{
|
||||
e->data.ptr = &(*it);
|
||||
++eventLast;
|
||||
}
|
||||
e->events |= EPOLLERR;
|
||||
}
|
||||
}
|
||||
|
||||
epollSize = eventLast - eventsIn;
|
||||
if (epollSize == 0) return 0;
|
||||
|
||||
epollfd = epoll_create(1);
|
||||
if (epollfd < 0)
|
||||
{
|
||||
SocketImpl::error("Can't create epoll queue");
|
||||
}
|
||||
|
||||
for (struct epoll_event* e = eventsIn; e != eventLast; ++e)
|
||||
{
|
||||
poco_socket_t sockfd = reinterpret_cast<Socket*>(e->data.ptr)->sockfd();
|
||||
if (sockfd != POCO_INVALID_SOCKET)
|
||||
{
|
||||
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, e) < 0)
|
||||
{
|
||||
::close(epollfd);
|
||||
SocketImpl::error("Can't insert socket to epoll queue");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s.second & PollSet::POLL_READ) readList.push_back(s.first);
|
||||
if (s.second & PollSet::POLL_WRITE) writeList.push_back(s.first);
|
||||
if (s.second & PollSet::POLL_ERROR) exceptList.push_back(s.first);
|
||||
}
|
||||
|
||||
struct epoll_event eventsOut[epollSize];
|
||||
memset(eventsOut, 0, sizeof(eventsOut));
|
||||
|
||||
Poco::Timespan remainingTime(timeout);
|
||||
int rc;
|
||||
do
|
||||
{
|
||||
Poco::Timestamp start;
|
||||
rc = epoll_wait(epollfd, eventsOut, epollSize, remainingTime.totalMilliseconds());
|
||||
if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
|
||||
{
|
||||
Poco::Timestamp end;
|
||||
Poco::Timespan waited = end - start;
|
||||
if (waited < remainingTime)
|
||||
remainingTime -= waited;
|
||||
else
|
||||
remainingTime = 0;
|
||||
}
|
||||
}
|
||||
while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
|
||||
|
||||
::close(epollfd);
|
||||
if (rc < 0) SocketImpl::error();
|
||||
|
||||
SocketList readyReadList;
|
||||
SocketList readyWriteList;
|
||||
SocketList readyExceptList;
|
||||
for (int n = 0; n < rc; ++n)
|
||||
{
|
||||
if (eventsOut[n].events & EPOLLERR)
|
||||
readyExceptList.push_back(*reinterpret_cast<Socket*>(eventsOut[n].data.ptr));
|
||||
if (eventsOut[n].events & EPOLLIN)
|
||||
readyReadList.push_back(*reinterpret_cast<Socket*>(eventsOut[n].data.ptr));
|
||||
if (eventsOut[n].events & EPOLLOUT)
|
||||
readyWriteList.push_back(*reinterpret_cast<Socket*>(eventsOut[n].data.ptr));
|
||||
}
|
||||
std::swap(readList, readyReadList);
|
||||
std::swap(writeList, readyWriteList);
|
||||
std::swap(exceptList, readyExceptList);
|
||||
return readList.size() + writeList.size() + exceptList.size();
|
||||
return static_cast<int>(readList.size() + writeList.size() + exceptList.size());
|
||||
|
||||
#elif defined(POCO_HAVE_FD_POLL)
|
||||
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;
|
||||
|
||||
SharedPollArray pPollArr = new pollfd[nfd]();
|
||||
@@ -256,7 +175,11 @@ int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exce
|
||||
do
|
||||
{
|
||||
Poco::Timestamp start;
|
||||
#ifdef _WIN32
|
||||
rc = WSAPoll(pPollArr, nfd, static_cast<INT>(remainingTime.totalMilliseconds()));
|
||||
#else
|
||||
rc = ::poll(pPollArr, nfd, remainingTime.totalMilliseconds());
|
||||
#endif
|
||||
if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
|
||||
{
|
||||
Poco::Timestamp end;
|
||||
@@ -276,17 +199,17 @@ int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exce
|
||||
SocketList::iterator endE = exceptList.end();
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
std::swap(readList, readyReadList);
|
||||
std::swap(writeList, readyWriteList);
|
||||
std::swap(exceptList, readyExceptList);
|
||||
return readList.size() + writeList.size() + exceptList.size();
|
||||
return static_cast<int>(readList.size() + writeList.size() + exceptList.size());
|
||||
|
||||
#else
|
||||
|
||||
@@ -464,4 +387,22 @@ SocketBufVec Socket::makeBufVec(const std::vector<std::string>& vec)
|
||||
}
|
||||
|
||||
|
||||
int Socket::lastError()
|
||||
{
|
||||
return SocketImpl::lastError();
|
||||
}
|
||||
|
||||
|
||||
std::string Socket::lastErrorDesc()
|
||||
{
|
||||
return Error::getMessage(SocketImpl::lastError());
|
||||
}
|
||||
|
||||
|
||||
void Socket::error()
|
||||
{
|
||||
SocketImpl::error();
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
+13
@@ -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)
|
||||
{
|
||||
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
|
||||
{
|
||||
return pImpl()->host();
|
||||
|
||||
Vendored
+64
-26
@@ -20,23 +20,17 @@
|
||||
#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)
|
||||
#include <sys/epoll.h>
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
#include "wepoll.h"
|
||||
#else
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
#elif defined(POCO_HAVE_FD_POLL)
|
||||
#ifndef _WIN32
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -63,6 +57,20 @@ using Poco::NumberFormatter;
|
||||
using Poco::Timespan;
|
||||
|
||||
|
||||
#ifdef WEPOLL_H_
|
||||
|
||||
namespace {
|
||||
|
||||
int close(HANDLE h)
|
||||
{
|
||||
return epoll_close(h);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // WEPOLL_H_
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
@@ -219,10 +227,8 @@ void SocketImpl::bind(const SocketAddress& address, bool reuseAddress, bool reus
|
||||
{
|
||||
init(address.af());
|
||||
}
|
||||
if (reuseAddress)
|
||||
setReuseAddress(true);
|
||||
if (reusePort)
|
||||
setReusePort(true);
|
||||
setReuseAddress(reuseAddress);
|
||||
setReusePort(reusePort);
|
||||
#if defined(POCO_VXWORKS)
|
||||
int rc = ::bind(_sockfd, (sockaddr*) address.addr(), address.length());
|
||||
#else
|
||||
@@ -253,10 +259,8 @@ void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reu
|
||||
#else
|
||||
if (ipV6Only) throw Poco::NotImplementedException("IPV6_V6ONLY not defined.");
|
||||
#endif
|
||||
if (reuseAddress)
|
||||
setReuseAddress(true);
|
||||
if (reusePort)
|
||||
setReusePort(true);
|
||||
setReuseAddress(reuseAddress);
|
||||
setReusePort(reusePort);
|
||||
int rc = ::bind(_sockfd, address.addr(), address.length());
|
||||
if (rc != 0) error(address.toString());
|
||||
#else
|
||||
@@ -614,6 +618,13 @@ int SocketImpl::available()
|
||||
{
|
||||
int result = 0;
|
||||
ioctl(FIONREAD, result);
|
||||
#if (POCO_OS != POCO_OS_LINUX)
|
||||
if (result && (type() == SOCKET_TYPE_DATAGRAM))
|
||||
{
|
||||
std::vector<char> buf(result);
|
||||
result = recvfrom(sockfd(), &buf[0], result, MSG_PEEK, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -630,9 +641,17 @@ bool SocketImpl::poll(const Poco::Timespan& timeout, int mode)
|
||||
if (sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
|
||||
|
||||
#if defined(POCO_HAVE_FD_EPOLL)
|
||||
|
||||
#ifdef WEPOLL_H_
|
||||
HANDLE epollfd = epoll_create(1);
|
||||
#else
|
||||
int epollfd = epoll_create(1);
|
||||
#endif
|
||||
|
||||
#ifdef WEPOLL_H_
|
||||
if (!epollfd)
|
||||
#else
|
||||
if (epollfd < 0)
|
||||
#endif
|
||||
{
|
||||
error("Can't create epoll queue");
|
||||
}
|
||||
@@ -661,7 +680,7 @@ bool SocketImpl::poll(const Poco::Timespan& timeout, int mode)
|
||||
memset(&evout, 0, sizeof(evout));
|
||||
|
||||
Poco::Timestamp start;
|
||||
rc = epoll_wait(epollfd, &evout, 1, remainingTime.totalMilliseconds());
|
||||
rc = epoll_wait(epollfd, &evout, 1, static_cast<int>(remainingTime.totalMilliseconds()));
|
||||
if (rc < 0 && lastError() == POCO_EINTR)
|
||||
{
|
||||
Poco::Timestamp end;
|
||||
@@ -759,6 +778,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)
|
||||
{
|
||||
setOption(SOL_SOCKET, SO_SNDBUF, size);
|
||||
@@ -1027,14 +1054,25 @@ void SocketImpl::setReuseAddress(bool flag)
|
||||
{
|
||||
int value = flag ? 1 : 0;
|
||||
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 ret = false;
|
||||
int value(0);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+20
-8
@@ -29,14 +29,14 @@ SocketNotification::~SocketNotification()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SocketNotification::setSocket(const Socket& socket)
|
||||
{
|
||||
_socket = socket;
|
||||
}
|
||||
|
||||
|
||||
ReadableNotification::ReadableNotification(SocketReactor* pReactor):
|
||||
ReadableNotification::ReadableNotification(SocketReactor* pReactor):
|
||||
SocketNotification(pReactor)
|
||||
{
|
||||
}
|
||||
@@ -47,7 +47,7 @@ ReadableNotification::~ReadableNotification()
|
||||
}
|
||||
|
||||
|
||||
WritableNotification::WritableNotification(SocketReactor* pReactor):
|
||||
WritableNotification::WritableNotification(SocketReactor* pReactor):
|
||||
SocketNotification(pReactor)
|
||||
{
|
||||
}
|
||||
@@ -58,18 +58,30 @@ WritableNotification::~WritableNotification()
|
||||
}
|
||||
|
||||
|
||||
ErrorNotification::ErrorNotification(SocketReactor* pReactor):
|
||||
SocketNotification(pReactor)
|
||||
ErrorNotification::ErrorNotification(SocketReactor* pReactor, int code, const std::string& description):
|
||||
SocketNotification(pReactor),
|
||||
_code(code),
|
||||
_description(description)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ErrorNotification::ErrorNotification(SocketReactor* pReactor, const Socket& socket,
|
||||
int code, const std::string& description):
|
||||
SocketNotification(pReactor),
|
||||
_code(code),
|
||||
_description(description)
|
||||
{
|
||||
setSocket(socket);
|
||||
}
|
||||
|
||||
|
||||
ErrorNotification::~ErrorNotification()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TimeoutNotification::TimeoutNotification(SocketReactor* pReactor):
|
||||
TimeoutNotification::TimeoutNotification(SocketReactor* pReactor):
|
||||
SocketNotification(pReactor)
|
||||
{
|
||||
}
|
||||
@@ -80,7 +92,7 @@ TimeoutNotification::~TimeoutNotification()
|
||||
}
|
||||
|
||||
|
||||
IdleNotification::IdleNotification(SocketReactor* pReactor):
|
||||
IdleNotification::IdleNotification(SocketReactor* pReactor):
|
||||
SocketNotification(pReactor)
|
||||
{
|
||||
}
|
||||
@@ -91,7 +103,7 @@ IdleNotification::~IdleNotification()
|
||||
}
|
||||
|
||||
|
||||
ShutdownNotification::ShutdownNotification(SocketReactor* pReactor):
|
||||
ShutdownNotification::ShutdownNotification(SocketReactor* pReactor):
|
||||
SocketNotification(pReactor)
|
||||
{
|
||||
}
|
||||
|
||||
+808
@@ -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
|
||||
+107
-96
@@ -13,10 +13,9 @@
|
||||
|
||||
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/SocketNotification.h"
|
||||
#include "Poco/Net/SocketNotifier.h"
|
||||
#include "Poco/ErrorHandler.h"
|
||||
#include "Poco/Thread.h"
|
||||
#include "Poco/Stopwatch.h"
|
||||
#include "Poco/Exception.h"
|
||||
|
||||
|
||||
@@ -30,29 +29,38 @@ namespace Net {
|
||||
|
||||
SocketReactor::SocketReactor():
|
||||
_stop(false),
|
||||
_timeout(DEFAULT_TIMEOUT),
|
||||
_pReadableNotification(new ReadableNotification(this)),
|
||||
_pWritableNotification(new WritableNotification(this)),
|
||||
_pErrorNotification(new ErrorNotification(this)),
|
||||
_pTimeoutNotification(new TimeoutNotification(this)),
|
||||
_pIdleNotification(new IdleNotification(this)),
|
||||
_pShutdownNotification(new ShutdownNotification(this)),
|
||||
_pThread(0)
|
||||
_pShutdownNotification(new ShutdownNotification(this))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SocketReactor::SocketReactor(const Poco::Timespan& timeout):
|
||||
SocketReactor::SocketReactor(const Poco::Timespan& pollTimeout, int threadAffinity):
|
||||
_threadAffinity(threadAffinity),
|
||||
_stop(false),
|
||||
_timeout(timeout),
|
||||
_pReadableNotification(new ReadableNotification(this)),
|
||||
_pWritableNotification(new WritableNotification(this)),
|
||||
_pErrorNotification(new ErrorNotification(this)),
|
||||
_pTimeoutNotification(new TimeoutNotification(this)),
|
||||
_pIdleNotification(new IdleNotification(this)),
|
||||
_pShutdownNotification(new ShutdownNotification(this)),
|
||||
_pThread(0)
|
||||
_pShutdownNotification(new ShutdownNotification(this))
|
||||
{
|
||||
_params.pollTimeout = pollTimeout;
|
||||
}
|
||||
|
||||
SocketReactor::SocketReactor(const Params& params, int threadAffinity):
|
||||
_params(params),
|
||||
_threadAffinity(threadAffinity),
|
||||
_stop(false),
|
||||
_pReadableNotification(new ReadableNotification(this)),
|
||||
_pWritableNotification(new WritableNotification(this)),
|
||||
_pErrorNotification(new ErrorNotification(this)),
|
||||
_pTimeoutNotification(new TimeoutNotification(this)),
|
||||
_pShutdownNotification(new ShutdownNotification(this))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -63,49 +71,79 @@ SocketReactor::~SocketReactor()
|
||||
|
||||
void SocketReactor::run()
|
||||
{
|
||||
_pThread = Thread::current();
|
||||
if (_threadAffinity >= 0)
|
||||
{
|
||||
Poco::Thread* pThread = Thread::current();
|
||||
if (pThread) pThread->setAffinity(_threadAffinity);
|
||||
}
|
||||
Poco::Stopwatch sw;
|
||||
if (_params.throttle) sw.start();
|
||||
PollSet::SocketModeMap sm;
|
||||
while (!_stop)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!hasSocketHandlers())
|
||||
if (hasSocketHandlers())
|
||||
{
|
||||
onIdle();
|
||||
Thread::trySleep(static_cast<long>(_timeout.totalMilliseconds()));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool readable = false;
|
||||
PollSet::SocketModeMap sm = _pollSet.poll(_timeout);
|
||||
if (sm.size() > 0)
|
||||
sm = _pollSet.poll(_params.pollTimeout);
|
||||
for (const auto& s : sm)
|
||||
{
|
||||
onBusy();
|
||||
PollSet::SocketModeMap::iterator it = sm.begin();
|
||||
PollSet::SocketModeMap::iterator end = sm.end();
|
||||
for (; it != end; ++it)
|
||||
try
|
||||
{
|
||||
if (it->second & PollSet::POLL_READ)
|
||||
if (s.second & PollSet::POLL_READ)
|
||||
{
|
||||
dispatch(it->first, _pReadableNotification);
|
||||
readable = true;
|
||||
dispatch(s.first, _pReadableNotification);
|
||||
}
|
||||
if (it->second & PollSet::POLL_WRITE) dispatch(it->first, _pWritableNotification);
|
||||
if (it->second & PollSet::POLL_ERROR) dispatch(it->first, _pErrorNotification);
|
||||
if (s.second & PollSet::POLL_WRITE)
|
||||
{
|
||||
dispatch(s.first, _pWritableNotification);
|
||||
}
|
||||
if (s.second & PollSet::POLL_ERROR)
|
||||
{
|
||||
dispatch(s.first, _pErrorNotification);
|
||||
}
|
||||
}
|
||||
catch (Exception& exc)
|
||||
{
|
||||
onError(s.first, exc.code(), exc.displayText());
|
||||
ErrorHandler::handle(exc);
|
||||
}
|
||||
catch (std::exception& exc)
|
||||
{
|
||||
onError(s.first, 0, exc.what());
|
||||
ErrorHandler::handle(exc);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
onError(s.first, 0, "unknown exception");
|
||||
ErrorHandler::handle();
|
||||
}
|
||||
}
|
||||
if (!readable) onTimeout();
|
||||
if (0 == sm.size())
|
||||
{
|
||||
onTimeout();
|
||||
if (_params.throttle && _params.pollTimeout == 0)
|
||||
{
|
||||
if ((sw.elapsed()/1000) > _params.sleepLimit) sleep();
|
||||
}
|
||||
}
|
||||
else if (_params.throttle) sw.restart();
|
||||
}
|
||||
else sleep();
|
||||
}
|
||||
catch (Exception& exc)
|
||||
{
|
||||
onError(exc.code(), exc.displayText());
|
||||
ErrorHandler::handle(exc);
|
||||
}
|
||||
catch (std::exception& exc)
|
||||
{
|
||||
onError(0, exc.what());
|
||||
ErrorHandler::handle(exc);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
onError(0, "unknown exception");
|
||||
ErrorHandler::handle();
|
||||
}
|
||||
}
|
||||
@@ -113,6 +151,27 @@ void SocketReactor::run()
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::sleep()
|
||||
{
|
||||
if (_params.sleep < _params.sleepLimit) ++_params.sleep;
|
||||
_event.tryWait(_params.sleep);
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::stop()
|
||||
{
|
||||
_stop = true;
|
||||
wakeUp();
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::wakeUp()
|
||||
{
|
||||
_pollSet.wakeUp();
|
||||
_event.set();
|
||||
}
|
||||
|
||||
|
||||
bool SocketReactor::hasSocketHandlers()
|
||||
{
|
||||
if (!_pollSet.empty())
|
||||
@@ -130,30 +189,6 @@ bool SocketReactor::hasSocketHandlers()
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::stop()
|
||||
{
|
||||
_stop = true;
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::wakeUp()
|
||||
{
|
||||
if (_pThread) _pThread->wakeUp();
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::setTimeout(const Poco::Timespan& timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
|
||||
const Poco::Timespan& SocketReactor::getTimeout() const
|
||||
{
|
||||
return _timeout;
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::addEventHandler(const Socket& socket, const Poco::AbstractObserver& observer)
|
||||
{
|
||||
NotifierPtr pNotifier = getNotifier(socket, true);
|
||||
@@ -179,11 +214,14 @@ bool SocketReactor::hasEventHandler(const Socket& socket, const Poco::AbstractOb
|
||||
|
||||
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);
|
||||
|
||||
EventHandlerMap::iterator it = _handlers.find(socket);
|
||||
EventHandlerMap::iterator it = _handlers.find(sockfd);
|
||||
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;
|
||||
}
|
||||
@@ -191,6 +229,8 @@ SocketReactor::NotifierPtr SocketReactor::getNotifier(const Socket& socket, bool
|
||||
|
||||
void SocketReactor::removeEventHandler(const Socket& socket, const Poco::AbstractObserver& observer)
|
||||
{
|
||||
const SocketImpl* pImpl = socket.impl();
|
||||
if (pImpl == nullptr) return;
|
||||
NotifierPtr pNotifier = getNotifier(socket);
|
||||
if (pNotifier && pNotifier->hasObserver(observer))
|
||||
{
|
||||
@@ -198,44 +238,36 @@ void SocketReactor::removeEventHandler(const Socket& socket, const Poco::Abstrac
|
||||
{
|
||||
{
|
||||
ScopedLock lock(_mutex);
|
||||
_handlers.erase(socket);
|
||||
_handlers.erase(pImpl->sockfd());
|
||||
}
|
||||
_pollSet.remove(socket);
|
||||
}
|
||||
pNotifier->removeObserver(this, observer);
|
||||
|
||||
if (pNotifier->countObservers() > 0 && socket.impl()->sockfd() > 0)
|
||||
{
|
||||
int mode = 0;
|
||||
if (pNotifier->accepts(_pReadableNotification)) mode |= PollSet::POLL_READ;
|
||||
if (pNotifier->accepts(_pWritableNotification)) mode |= PollSet::POLL_WRITE;
|
||||
if (pNotifier->accepts(_pErrorNotification)) mode |= PollSet::POLL_ERROR;
|
||||
_pollSet.update(socket, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SocketReactor::has(const Socket& socket) const
|
||||
{
|
||||
return _pollSet.has(socket);
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::onTimeout()
|
||||
{
|
||||
dispatch(_pTimeoutNotification);
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::onIdle()
|
||||
{
|
||||
dispatch(_pIdleNotification);
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::onShutdown()
|
||||
{
|
||||
dispatch(_pShutdownNotification);
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::onBusy()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::dispatch(const Socket& socket, SocketNotification* pNotification)
|
||||
{
|
||||
NotifierPtr pNotifier = getNotifier(socket);
|
||||
@@ -260,25 +292,4 @@ void SocketReactor::dispatch(SocketNotification* pNotification)
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::dispatch(NotifierPtr& pNotifier, SocketNotification* pNotification)
|
||||
{
|
||||
try
|
||||
{
|
||||
pNotifier->dispatch(pNotification);
|
||||
}
|
||||
catch (Exception& exc)
|
||||
{
|
||||
ErrorHandler::handle(exc);
|
||||
}
|
||||
catch (std::exception& exc)
|
||||
{
|
||||
ErrorHandler::handle(exc);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ErrorHandler::handle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
Vendored
+2
-2
@@ -30,12 +30,12 @@ namespace Net {
|
||||
//
|
||||
|
||||
|
||||
SocketStreamBuf::SocketStreamBuf(const Socket& socket):
|
||||
SocketStreamBuf::SocketStreamBuf(const Socket& socket):
|
||||
BufferedBidirectionalStreamBuf(STREAM_BUFFER_SIZE, std::ios::in | std::ios::out),
|
||||
_pImpl(dynamic_cast<StreamSocketImpl*>(socket.impl()))
|
||||
{
|
||||
if (_pImpl)
|
||||
_pImpl->duplicate();
|
||||
_pImpl->duplicate();
|
||||
else
|
||||
throw InvalidArgumentException("Invalid or null SocketImpl passed to SocketStreamBuf");
|
||||
}
|
||||
|
||||
Vendored
+50
-1
@@ -51,6 +51,11 @@ StreamSocket::StreamSocket(const Socket& socket): Socket(socket)
|
||||
}
|
||||
|
||||
|
||||
StreamSocket::StreamSocket(const StreamSocket& socket): Socket(socket)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
StreamSocket::StreamSocket(SocketImpl* pImpl): Socket(pImpl)
|
||||
{
|
||||
if (!dynamic_cast<StreamSocketImpl*>(impl()))
|
||||
@@ -73,6 +78,50 @@ 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::bind(const SocketAddress& address, bool reuseAddress, bool ipV6Only)
|
||||
{
|
||||
if (address.family() == IPAddress::IPv4)
|
||||
impl()->bind(address, reuseAddress);
|
||||
else
|
||||
impl()->bind6(address, reuseAddress, ipV6Only);
|
||||
}
|
||||
|
||||
|
||||
void StreamSocket::connect(const SocketAddress& address)
|
||||
{
|
||||
impl()->connect(address);
|
||||
@@ -96,7 +145,7 @@ void StreamSocket::shutdownReceive()
|
||||
impl()->shutdownReceive();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void StreamSocket::shutdownSend()
|
||||
{
|
||||
impl()->shutdownSend();
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ int StreamSocketImpl::sendBytes(const void* buffer, int length, int flags)
|
||||
{
|
||||
int n = SocketImpl::sendBytes(p, remaining, flags);
|
||||
poco_assert_dbg (n >= 0);
|
||||
p += n;
|
||||
p += n;
|
||||
sent += n;
|
||||
remaining -= n;
|
||||
if (blocking && remaining > 0)
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ std::istream& StringPartSource::stream()
|
||||
return _istr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::string& StringPartSource::filename() const
|
||||
{
|
||||
return _filename;
|
||||
|
||||
Vendored
+7
-7
@@ -47,7 +47,7 @@ TCPServer::TCPServer(TCPServerConnectionFactory::Ptr pFactory, Poco::UInt16 port
|
||||
_socket(ServerSocket(portNumber)),
|
||||
_thread(threadName(_socket)),
|
||||
_stopped(true)
|
||||
{
|
||||
{
|
||||
Poco::ThreadPool& pool = Poco::ThreadPool::defaultPool();
|
||||
if (pParams)
|
||||
{
|
||||
@@ -55,7 +55,7 @@ TCPServer::TCPServer(TCPServerConnectionFactory::Ptr pFactory, Poco::UInt16 port
|
||||
if (toAdd > 0) pool.addCapacity(toAdd);
|
||||
}
|
||||
_pDispatcher = new TCPServerDispatcher(pFactory, pool, pParams);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ void TCPServer::start()
|
||||
_thread.start(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TCPServer::stop()
|
||||
{
|
||||
if (!_stopped)
|
||||
@@ -135,7 +135,7 @@ void TCPServer::run()
|
||||
try
|
||||
{
|
||||
StreamSocket ss = _socket.acceptConnection();
|
||||
|
||||
|
||||
if (!_pConnectionFilter || _pConnectionFilter->accept(ss))
|
||||
{
|
||||
// enable nodelay per default: OSX really needs that
|
||||
@@ -167,7 +167,7 @@ void TCPServer::run()
|
||||
ErrorHandler::handle(exc);
|
||||
// possibly a resource issue since poll() failed;
|
||||
// give some time to recover before trying again
|
||||
Poco::Thread::sleep(50);
|
||||
Poco::Thread::sleep(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ int TCPServer::maxThreads() const
|
||||
return _pDispatcher->maxThreads();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int TCPServer::totalConnections() const
|
||||
{
|
||||
return _pDispatcher->totalConnections();
|
||||
@@ -202,7 +202,7 @@ int TCPServer::maxConcurrentConnections() const
|
||||
return _pDispatcher->maxConcurrentConnections();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int TCPServer::queuedConnections() const
|
||||
{
|
||||
return _pDispatcher->queuedConnections();
|
||||
|
||||
+26
-36
@@ -16,6 +16,7 @@
|
||||
#include "Poco/Net/TCPServerConnectionFactory.h"
|
||||
#include "Poco/Notification.h"
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/ErrorHandler.h"
|
||||
#include <memory>
|
||||
|
||||
|
||||
@@ -84,18 +85,13 @@ TCPServerDispatcher::~TCPServerDispatcher()
|
||||
|
||||
void TCPServerDispatcher::duplicate()
|
||||
{
|
||||
_mutex.lock();
|
||||
++_rc;
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
void TCPServerDispatcher::release()
|
||||
{
|
||||
_mutex.lock();
|
||||
int rc = --_rc;
|
||||
_mutex.unlock();
|
||||
if (rc == 0) delete this;
|
||||
if (--_rc == 0) delete this;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,26 +103,29 @@ void TCPServerDispatcher::run()
|
||||
|
||||
for (;;)
|
||||
{
|
||||
AutoPtr<Notification> pNf = _queue.waitDequeueNotification(idleTime);
|
||||
if (pNf)
|
||||
{
|
||||
TCPConnectionNotification* pCNf = dynamic_cast<TCPConnectionNotification*>(pNf.get());
|
||||
if (pCNf)
|
||||
ThreadCountWatcher tcw(this);
|
||||
try
|
||||
{
|
||||
std::unique_ptr<TCPServerConnection> pConnection(_pConnectionFactory->createConnection(pCNf->socket()));
|
||||
poco_check_ptr(pConnection.get());
|
||||
beginConnection();
|
||||
pConnection->start();
|
||||
endConnection();
|
||||
AutoPtr<Notification> pNf = _queue.waitDequeueNotification(idleTime);
|
||||
if (pNf)
|
||||
{
|
||||
TCPConnectionNotification* pCNf = dynamic_cast<TCPConnectionNotification*>(pNf.get());
|
||||
if (pCNf)
|
||||
{
|
||||
std::unique_ptr<TCPServerConnection> pConnection(_pConnectionFactory->createConnection(pCNf->socket()));
|
||||
poco_check_ptr(pConnection.get());
|
||||
beginConnection();
|
||||
pConnection->start();
|
||||
endConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Poco::Exception &exc) { ErrorHandler::handle(exc); }
|
||||
catch (std::exception &exc) { ErrorHandler::handle(exc); }
|
||||
catch (...) { ErrorHandler::handle(); }
|
||||
}
|
||||
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
if (_stopped || (_currentThreads > 1 && _queue.empty()))
|
||||
{
|
||||
--_currentThreads;
|
||||
break;
|
||||
}
|
||||
if (_stopped || (_currentThreads > 1 && _queue.empty())) break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,14 +173,15 @@ void TCPServerDispatcher::stop()
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
_stopped = true;
|
||||
_queue.clear();
|
||||
_queue.enqueueNotification(new StopNotification);
|
||||
for (int i = 0; i < _threadPool.allocated(); i++)
|
||||
{
|
||||
_queue.enqueueNotification(new StopNotification);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int TCPServerDispatcher::currentThreads() const
|
||||
{
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
return _currentThreads;
|
||||
}
|
||||
|
||||
@@ -195,24 +195,18 @@ int TCPServerDispatcher::maxThreads() const
|
||||
|
||||
int TCPServerDispatcher::totalConnections() const
|
||||
{
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
return _totalConnections;
|
||||
}
|
||||
|
||||
|
||||
int TCPServerDispatcher::currentConnections() const
|
||||
{
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
return _currentConnections;
|
||||
}
|
||||
|
||||
|
||||
int TCPServerDispatcher::maxConcurrentConnections() const
|
||||
{
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
return _maxConcurrentConnections;
|
||||
}
|
||||
|
||||
@@ -225,8 +219,6 @@ int TCPServerDispatcher::queuedConnections() const
|
||||
|
||||
int TCPServerDispatcher::refusedConnections() const
|
||||
{
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
return _refusedConnections;
|
||||
}
|
||||
|
||||
@@ -238,14 +230,12 @@ void TCPServerDispatcher::beginConnection()
|
||||
++_totalConnections;
|
||||
++_currentConnections;
|
||||
if (_currentConnections > _maxConcurrentConnections)
|
||||
_maxConcurrentConnections = _currentConnections;
|
||||
_maxConcurrentConnections.store(_currentConnections);
|
||||
}
|
||||
|
||||
|
||||
void TCPServerDispatcher::endConnection()
|
||||
{
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
--_currentConnections;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+52
@@ -65,6 +65,30 @@ WebSocket::WebSocket(const Socket& socket):
|
||||
}
|
||||
|
||||
|
||||
#ifdef POCO_NEW_STATE_ON_MOVE
|
||||
|
||||
WebSocket::WebSocket(Socket&& socket):
|
||||
StreamSocket(std::move(socket))
|
||||
{
|
||||
if (!dynamic_cast<WebSocketImpl*>(impl()))
|
||||
throw InvalidArgumentException("Cannot assign incompatible socket");
|
||||
}
|
||||
|
||||
|
||||
WebSocket::WebSocket(WebSocket&& socket):
|
||||
StreamSocket(std::move(socket))
|
||||
{
|
||||
}
|
||||
|
||||
#endif // POCO_NEW_STATE_ON_MOVE
|
||||
|
||||
|
||||
WebSocket::WebSocket(const WebSocket& socket):
|
||||
StreamSocket(socket)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
WebSocket::~WebSocket()
|
||||
{
|
||||
}
|
||||
@@ -80,6 +104,34 @@ WebSocket& WebSocket::operator = (const Socket& socket)
|
||||
}
|
||||
|
||||
|
||||
#ifdef POCO_NEW_STATE_ON_MOVE
|
||||
|
||||
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 = (WebSocket&& socket)
|
||||
{
|
||||
Socket::operator = (std::move(socket));
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif // POCO_NEW_STATE_ON_MOVE
|
||||
|
||||
|
||||
WebSocket& WebSocket::operator = (const WebSocket& socket)
|
||||
{
|
||||
Socket::operator = (socket);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void WebSocket::shutdown()
|
||||
{
|
||||
shutdown(WS_NORMAL_CLOSE);
|
||||
|
||||
-1
@@ -12,7 +12,6 @@
|
||||
//
|
||||
|
||||
|
||||
#define NOMINMAX
|
||||
#include "Poco/Net/WebSocketImpl.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
|
||||
Vendored
+2253
File diff suppressed because it is too large
Load Diff
Vendored
+114
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* wepoll - epoll for Windows
|
||||
* https://github.com/piscisaureus/wepoll
|
||||
*
|
||||
* Copyright 2012-2020, Bert Belder <bertbelder@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef WEPOLL_H_
|
||||
#define WEPOLL_H_
|
||||
|
||||
#ifndef WEPOLL_EXPORT
|
||||
#define WEPOLL_EXPORT
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum EPOLL_EVENTS {
|
||||
EPOLLIN = (int) (1U << 0),
|
||||
EPOLLPRI = (int) (1U << 1),
|
||||
EPOLLOUT = (int) (1U << 2),
|
||||
EPOLLERR = (int) (1U << 3),
|
||||
EPOLLHUP = (int) (1U << 4),
|
||||
EPOLLRDNORM = (int) (1U << 6),
|
||||
EPOLLRDBAND = (int) (1U << 7),
|
||||
EPOLLWRNORM = (int) (1U << 8),
|
||||
EPOLLWRBAND = (int) (1U << 9),
|
||||
EPOLLMSG = (int) (1U << 10), /* Never reported. */
|
||||
EPOLLRDHUP = (int) (1U << 13),
|
||||
EPOLLONESHOT = (int) (1U << 31)
|
||||
};
|
||||
|
||||
#define EPOLLIN (1U << 0)
|
||||
#define EPOLLPRI (1U << 1)
|
||||
#define EPOLLOUT (1U << 2)
|
||||
#define EPOLLERR (1U << 3)
|
||||
#define EPOLLHUP (1U << 4)
|
||||
#define EPOLLRDNORM (1U << 6)
|
||||
#define EPOLLRDBAND (1U << 7)
|
||||
#define EPOLLWRNORM (1U << 8)
|
||||
#define EPOLLWRBAND (1U << 9)
|
||||
#define EPOLLMSG (1U << 10)
|
||||
#define EPOLLRDHUP (1U << 13)
|
||||
#define EPOLLONESHOT (1U << 31)
|
||||
|
||||
#define EPOLL_CTL_ADD 1
|
||||
#define EPOLL_CTL_MOD 2
|
||||
#define EPOLL_CTL_DEL 3
|
||||
|
||||
typedef void* HANDLE;
|
||||
typedef uintptr_t SOCKET;
|
||||
|
||||
typedef union epoll_data {
|
||||
void* ptr;
|
||||
int fd;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
SOCKET sock; /* Windows specific */
|
||||
HANDLE hnd; /* Windows specific */
|
||||
} epoll_data_t;
|
||||
|
||||
struct epoll_event {
|
||||
uint32_t events; /* Epoll events and flags */
|
||||
epoll_data_t data; /* User data variable */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
WEPOLL_EXPORT HANDLE epoll_create(int size);
|
||||
WEPOLL_EXPORT HANDLE epoll_create1(int flags);
|
||||
|
||||
WEPOLL_EXPORT int epoll_close(HANDLE ephnd);
|
||||
|
||||
WEPOLL_EXPORT int epoll_ctl(HANDLE ephnd,
|
||||
int op,
|
||||
SOCKET sock,
|
||||
struct epoll_event* event);
|
||||
|
||||
WEPOLL_EXPORT int epoll_wait(HANDLE ephnd,
|
||||
struct epoll_event* events,
|
||||
int maxevents,
|
||||
int timeout);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* WEPOLL_H_ */
|
||||
Reference in New Issue
Block a user