Net: near complete merge to 1.4.2

This commit is contained in:
Marian Krivos
2011-09-14 18:20:11 +00:00
parent 56c6a4f758
commit b242f2c8d1
192 changed files with 15545 additions and 2277 deletions

View File

@@ -39,6 +39,8 @@
#include "Poco/Net/SocketAddress.h"
#include "Poco/Environment.h"
#include "Poco/NumberFormatter.h"
#include "Poco/AtomicCounter.h"
#include <cstring>
using Poco::FastMutex;
@@ -47,13 +49,9 @@ using Poco::NumberFormatter;
using Poco::IOException;
//
// Automatic initialization of Windows networking
//
#if defined(_WIN32) && !defined(POCO_NET_NO_AUTOMATIC_WSASTARTUP)
namespace
{
class NetworkInitializer
class NetworkInitializer
{
public:
NetworkInitializer()
@@ -63,105 +61,110 @@ namespace
~NetworkInitializer()
{
Poco::Net::uninitializeNetwork();
}
};
static NetworkInitializer networkInitializer;
Poco::Net::uninitializeNetwork();
}
};
}
#endif // _WIN32
namespace Poco {
namespace Net {
DNS::DNSCache DNS::_cache;
Poco::FastMutex DNS::_mutex;
HostEntry DNS::hostByName(const std::string& hostname)
{
FastMutex::ScopedLock lock(_mutex);
DNSCache::const_iterator it = _cache.find(hostname);
if (it != _cache.end())
{
return it->second;
}
else
{
#if defined(_WIN32) && defined(POCO_HAVE_IPv6)
struct addrinfo* pAI;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
if (getaddrinfo(hostname.c_str(), NULL, &hints, &pAI) == 0)
{
std::pair<DNSCache::iterator, bool> res = _cache.insert(std::pair<std::string, HostEntry>(hostname, HostEntry(pAI)));
freeaddrinfo(pAI);
return res.first->second;
}
NetworkInitializer networkInitializer;
#if defined(POCO_HAVE_IPv6)
struct addrinfo* pAI;
struct addrinfo hints;
std::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
int rc = getaddrinfo(hostname.c_str(), NULL, &hints, &pAI);
if (rc == 0)
{
HostEntry result(pAI);
freeaddrinfo(pAI);
return result;
}
else
{
aierror(rc, hostname);
}
#elif defined(POCO_VXWORKS)
int addr = hostGetByName(const_cast<char*>(hostname.c_str()));
if (addr != ERROR)
{
return HostEntry(hostname, IPAddress(&addr, sizeof(addr)));
}
#else
struct hostent* he = gethostbyname(hostname.c_str());
if (he)
{
std::pair<DNSCache::iterator, bool> res = _cache.insert(std::pair<std::string, HostEntry>(hostname, HostEntry(he)));
return res.first->second;
}
struct hostent* he = gethostbyname(hostname.c_str());
if (he)
{
return HostEntry(he);
}
#endif
}
error(lastError(), hostname); // will throw an appropriate exception
throw NetException(); // to silence compiler
error(lastError(), hostname); // will throw an appropriate exception
throw NetException(); // to silence compiler
}
HostEntry DNS::hostByAddress(const IPAddress& address)
{
FastMutex::ScopedLock lock(_mutex);
NetworkInitializer networkInitializer;
#if defined(_WIN32) && defined(POCO_HAVE_IPv6)
SocketAddress sa(address, 0);
static char fqname[1024];
if (getnameinfo(sa.addr(), sa.length(), fqname, sizeof(fqname), NULL, 0, 0) == 0)
{
DNSCache::const_iterator it = _cache.find(std::string(fqname));
if (it != _cache.end())
{
return it->second;
}
else
{
struct addrinfo* pAI;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
if (getaddrinfo(fqname, NULL, &hints, &pAI) == 0)
{
std::pair<DNSCache::iterator, bool> res = _cache.insert(std::pair<std::string, HostEntry>(std::string(fqname), HostEntry(pAI)));
freeaddrinfo(pAI);
return res.first->second;
}
}
}
#if defined(POCO_HAVE_IPv6)
SocketAddress sa(address, 0);
static char fqname[1024];
int rc = getnameinfo(sa.addr(), sa.length(), fqname, sizeof(fqname), NULL, 0, NI_NAMEREQD);
if (rc == 0)
{
struct addrinfo* pAI;
struct addrinfo hints;
std::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
rc = getaddrinfo(fqname, NULL, &hints, &pAI);
if (rc == 0)
{
HostEntry result(pAI);
freeaddrinfo(pAI);
return result;
}
else
{
aierror(rc, address.toString());
}
}
else
{
aierror(rc, address.toString());
}
#elif defined(POCO_VXWORKS)
char name[MAXHOSTNAMELEN + 1];
if (hostGetByAddr(*reinterpret_cast<const int*>(address.addr()), name) == OK)
{
return HostEntry(std::string(name), address);
}
#else
struct hostent* he = gethostbyaddr(reinterpret_cast<const char*>(address.addr()), address.length(), address.af());
if (he)
{
std::pair<DNSCache::iterator, bool> res = _cache.insert(std::pair<std::string, HostEntry>(std::string(he->h_name), HostEntry(he)));
return res.first->second;
}
struct hostent* he = gethostbyaddr(reinterpret_cast<const char*>(address.addr()), address.length(), address.af());
if (he)
{
return HostEntry(he);
}
#endif
error(lastError(), address.toString()); // will throw an appropriate exception
int err = lastError();
error(err, address.toString()); // will throw an appropriate exception
throw NetException(); // to silence compiler
}
HostEntry DNS::resolve(const std::string& address)
{
IPAddress ip;
if (IPAddress::tryParse(address, ip))
return hostByAddress(ip);
NetworkInitializer networkInitializer;
IPAddress ip;
if (IPAddress::tryParse(address, ip))
return hostByAddress(ip);
else
return hostByName(address);
}
@@ -169,9 +172,11 @@ HostEntry DNS::resolve(const std::string& address)
IPAddress DNS::resolveOne(const std::string& address)
{
HostEntry entry = resolve(address);
if (!entry.addresses().empty())
return entry.addresses()[0];
NetworkInitializer networkInitializer;
const HostEntry& entry = resolve(address);
if (!entry.addresses().empty())
return entry.addresses()[0];
else
throw NoAddressFoundException(address);
}
@@ -179,23 +184,22 @@ IPAddress DNS::resolveOne(const std::string& address)
HostEntry DNS::thisHost()
{
return hostByName(hostName());
return hostByName(hostName());
}
void DNS::flushCache()
{
FastMutex::ScopedLock lock(_mutex);
_cache.clear();
}
std::string DNS::hostName()
{
char buffer[256];
int rc = gethostname(buffer, sizeof(buffer));
if (rc == 0)
NetworkInitializer networkInitializer;
char buffer[256];
int rc = gethostname(buffer, sizeof(buffer));
if (rc == 0)
return std::string(buffer);
else
throw NetException("Cannot get host name");
@@ -206,6 +210,8 @@ int DNS::lastError()
{
#if defined(_WIN32)
return GetLastError();
#elif defined(POCO_VXWORKS)
return errno;
#else
return h_errno;
#endif
@@ -234,20 +240,63 @@ void DNS::error(int code, const std::string& arg)
}
void DNS::aierror(int code, const std::string& arg)
{
#if defined(POCO_HAVE_IPv6)
switch (code)
{
case EAI_AGAIN:
throw DNSException("Temporary DNS error while resolving", arg);
case EAI_FAIL:
throw DNSException("Non recoverable DNS error while resolving", arg);
#if !defined(_WIN32) // EAI_NODATA and EAI_NONAME have the same value
case EAI_NODATA:
throw NoAddressFoundException(arg);
#endif
case EAI_NONAME:
throw HostNotFoundException(arg);
#if defined(EAI_SYSTEM)
case EAI_SYSTEM:
error(lastError(), arg);
break;
#endif
#if defined(_WIN32)
case WSANO_DATA: // may happen on XP
throw HostNotFoundException(arg);
#endif
default:
throw DNSException("EAI", NumberFormatter::format(code));
}
#endif // POCO_HAVE_IPv6
}
#if defined(_WIN32)
static Poco::AtomicCounter initializeCount;
#endif
void initializeNetwork()
{
#if defined(_WIN32)
WORD version = MAKEWORD(2, 2);
WSADATA data;
WSAStartup(version, &data);
if (++initializeCount == 1)
{
WORD version = MAKEWORD(2, 2);
WSADATA data;
if (WSAStartup(version, &data) != 0)
throw NetException("Failed to initialize network subsystem");
}
#endif // _WIN32
}
void uninitializeNetwork()
{
#if defined(_WIN32)
WSACleanup();
if (--initializeCount == 0)
{
WSACleanup();
}
#endif // _WIN32
}

View File

@@ -35,8 +35,8 @@
#include "Poco/Net/DialogSocket.h"
#include "Poco/Ascii.h"
#include <cstring>
#include <cctype>
namespace Poco {
@@ -81,6 +81,17 @@ DialogSocket::~DialogSocket()
DialogSocket& DialogSocket::operator = (const Socket& socket)
{
StreamSocket::operator = (socket);
_pNext = _pBuffer;
_pEnd = _pBuffer;
return *this;
}
DialogSocket& DialogSocket::operator = (const DialogSocket& socket)
{
StreamSocket::operator = (socket);
_pNext = _pBuffer;
_pEnd = _pBuffer;
return *this;
}
@@ -256,7 +267,7 @@ int DialogSocket::receiveStatusLine(std::string& line)
int ch = get();
if (ch != EOF_CHAR) line += (char) ch;
int n = 0;
while (std::isdigit(ch) && n < 3)
while (Poco::Ascii::isDigit(ch) && n < 3)
{
status *= 10;
status += ch - '0';
@@ -275,4 +286,15 @@ int DialogSocket::receiveStatusLine(std::string& line)
}
int DialogSocket::receiveRawBytes(void* buffer, int length)
{
refill();
int n = static_cast<int>(_pEnd - _pNext);
if (n > length) n = length;
std::memcpy(buffer, _pNext, n);
_pNext += n;
return n;
}
} } // namespace Poco::Net

View File

@@ -68,6 +68,17 @@ FilePartSource::FilePartSource(const std::string& path, const std::string& media
}
FilePartSource::FilePartSource(const std::string& path, const std::string& filename, const std::string& mediaType):
PartSource(mediaType),
_filename(filename),
_istr(path)
{
Path p(path);
if (!_istr.good())
throw OpenFileException(path);
}
FilePartSource::~FilePartSource()
{
}

View File

@@ -48,7 +48,6 @@
#include "Poco/URI.h"
#include "Poco/String.h"
#include <sstream>
#include <cctype>
using Poco::NullInputStream;
@@ -125,7 +124,7 @@ void HTMLForm::addPart(const std::string& name, PartSource* pSource)
void HTMLForm::load(const HTTPRequest& request, std::istream& requestBody, PartHandler& handler)
{
clear();
if (request.getMethod() == HTTPRequest::HTTP_POST)
if (request.getMethod() == HTTPRequest::HTTP_POST || request.getMethod() == HTTPRequest::HTTP_PUT)
{
std::string mediaType;
NameValueCollection params;
@@ -176,7 +175,7 @@ void HTMLForm::read(std::istream& istr, PartHandler& handler)
void HTMLForm::prepareSubmit(HTTPRequest& request)
{
if (request.getMethod() == HTTPRequest::HTTP_POST)
if (request.getMethod() == HTTPRequest::HTTP_POST || request.getMethod() == HTTPRequest::HTTP_PUT)
{
if (_encoding == ENCODING_URL)
{
@@ -320,9 +319,9 @@ void HTMLForm::writeUrl(std::ostream& ostr)
{
if (it != begin()) ostr << "&";
std::string name;
URI::encode(it->first, "=&+", name);
URI::encode(it->first, "=&+;", name);
std::string value;
URI::encode(it->second, "=&+", value);
URI::encode(it->second, "=&+;", value);
ostr << name << "=" << value;
}
}
@@ -343,8 +342,8 @@ void HTMLForm::writeMultipart(std::ostream& ostr)
}
for (PartVec::iterator ita = _parts.begin(); ita != _parts.end(); ++ita)
{
MessageHeader header;
std::string disp("file; name=\"");
MessageHeader header(ita->pSource->headers());
std::string disp("form-data; name=\"");
disp.append(ita->name);
disp.append("\"");
std::string filename = ita->pSource->filename();

View File

@@ -116,6 +116,7 @@ void HTTPBasicCredentials::authenticate(HTTPRequest& request)
{
std::ostringstream ostr;
Base64Encoder encoder(ostr);
encoder.rdbuf()->setLineLength(0);
encoder << _username << ":" << _password;
encoder.close();
request.setCredentials(SCHEME, ostr.str());

View File

@@ -1,7 +1,7 @@
//
// HTTPChunkedStream.cpp
//
// $Id: //poco/Main/Net/src/HTTPChunkedStream.cpp#17 $
// $Id: //poco/1.4/Net/src/HTTPChunkedStream.cpp#1 $
//
// Library: Net
// Package: HTTP
@@ -38,7 +38,7 @@
#include "Poco/Net/HTTPSession.h"
#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"
#include <cctype>
#include "Poco/Ascii.h"
using Poco::NumberFormatter;
@@ -85,9 +85,9 @@ int HTTPChunkedStreamBuf::readFromDevice(char* buffer, std::streamsize length)
if (_chunk == 0)
{
int ch = _session.get();
while (std::isspace(ch)) ch = _session.get();
while (Poco::Ascii::isSpace(ch)) ch = _session.get();
std::string chunkLen;
while (std::isxdigit(ch)) { chunkLen += (char) ch; ch = _session.get(); }
while (Poco::Ascii::isHexDigit(ch)) { chunkLen += (char) ch; ch = _session.get(); }
while (ch != eof && ch != '\n') ch = _session.get();
unsigned chunk;
if (NumberParser::tryParseHex(chunkLen, chunk))

View File

@@ -44,6 +44,8 @@
#include "Poco/Net/NetException.h"
#include "Poco/NumberFormatter.h"
#include "Poco/CountingStream.h"
#include "Poco/Base64Encoder.h"
#include <sstream>
using Poco::NumberFormatter;
@@ -163,6 +165,25 @@ void HTTPClientSession::setProxyPort(Poco::UInt16 port)
}
void HTTPClientSession::setProxyCredentials(const std::string& username, const std::string& password)
{
_proxyUsername = username;
_proxyPassword = password;
}
void HTTPClientSession::setProxyUsername(const std::string& username)
{
_proxyUsername = username;
}
void HTTPClientSession::setProxyPassword(const std::string& password)
{
_proxyPassword = password;
}
void HTTPClientSession::setKeepAliveTimeout(const Poco::Timespan& timeout)
{
_keepAliveTimeout = timeout;
@@ -180,43 +201,54 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
close();
_mustReconnect = false;
}
if (!connected())
reconnect();
if (!keepAlive)
request.setKeepAlive(false);
if (!request.has(HTTPRequest::HOST))
request.setHost(_host, _port);
if (!_proxyHost.empty())
request.setURI(proxyRequestPrefix() + request.getURI());
_reconnect = keepAlive;
_expectResponseBody = request.getMethod() != HTTPRequest::HTTP_HEAD;
if (request.getChunkedTransferEncoding())
try
{
HTTPHeaderOutputStream hos(*this);
request.write(hos);
_pRequestStream = new HTTPChunkedOutputStream(*this);
if (!connected())
reconnect();
if (!keepAlive)
request.setKeepAlive(false);
if (!request.has(HTTPRequest::HOST))
request.setHost(_host, _port);
if (!_proxyHost.empty())
{
request.setURI(proxyRequestPrefix() + request.getURI());
proxyAuthenticate(request);
}
_reconnect = keepAlive;
_expectResponseBody = request.getMethod() != HTTPRequest::HTTP_HEAD;
if (request.getChunkedTransferEncoding())
{
HTTPHeaderOutputStream hos(*this);
request.write(hos);
_pRequestStream = new HTTPChunkedOutputStream(*this);
}
else if (request.getContentLength() != HTTPMessage::UNKNOWN_CONTENT_LENGTH)
{
Poco::CountingOutputStream cs;
request.write(cs);
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength() + cs.chars());
request.write(*_pRequestStream);
}
else if (request.getMethod() != HTTPRequest::HTTP_PUT && request.getMethod() != HTTPRequest::HTTP_POST)
{
Poco::CountingOutputStream cs;
request.write(cs);
_pRequestStream = new HTTPFixedLengthOutputStream(*this, cs.chars());
request.write(*_pRequestStream);
}
else
{
_pRequestStream = new HTTPOutputStream(*this);
request.write(*_pRequestStream);
}
_lastRequest.update();
return *_pRequestStream;
}
else if (request.getContentLength() != HTTPMessage::UNKNOWN_CONTENT_LENGTH)
catch (Exception&)
{
Poco::CountingOutputStream cs;
request.write(cs);
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength() + cs.chars());
request.write(*_pRequestStream);
close();
throw;
}
else if (request.getMethod() != HTTPRequest::HTTP_PUT && request.getMethod() != HTTPRequest::HTTP_POST)
{
Poco::CountingOutputStream cs;
request.write(cs);
_pRequestStream = new HTTPFixedLengthOutputStream(*this, cs.chars());
request.write(*_pRequestStream);
}
else
{
_pRequestStream = new HTTPOutputStream(*this);
request.write(*_pRequestStream);
}
_lastRequest.update();
return *_pRequestStream;
}
@@ -235,11 +267,17 @@ std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
}
catch (MessageException&)
{
close();
if (networkException())
networkException()->rethrow();
else
throw;
}
catch (Exception&)
{
close();
throw;
}
}
while (response.getStatus() == HTTPResponse::HTTP_CONTINUE);
@@ -258,6 +296,18 @@ std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
}
void HTTPClientSession::reset()
{
close();
}
bool HTTPClientSession::secure() const
{
return false;
}
int HTTPClientSession::write(const char* buffer, std::streamsize length)
{
try
@@ -322,7 +372,7 @@ void HTTPClientSession::deleteRequestStream()
void HTTPClientSession::setResponseStream(std::istream* pRespStream)
{
poco_assert( !_pResponseStream);
poco_assert (!_pResponseStream);
_pResponseStream = pRespStream;
}
@@ -345,4 +395,24 @@ bool HTTPClientSession::mustReconnect() const
}
void HTTPClientSession::proxyAuthenticate(HTTPRequest& request)
{
proxyAuthenticateImpl(request);
}
void HTTPClientSession::proxyAuthenticateImpl(HTTPRequest& request)
{
if (!_proxyUsername.empty())
{
std::ostringstream ostr;
ostr << "Basic ";
Base64Encoder encoder(ostr);
encoder << _proxyUsername << ":" << _proxyPassword;
encoder.close();
request.set("Proxy-Authorization", ostr.str());
}
}
} } // namespace Poco::Net

View File

@@ -1,7 +1,7 @@
//
// HTTPCookie.cpp
//
// $Id: //poco/Main/Net/src/HTTPCookie.cpp#9 $
// $Id: //poco/1.4/Net/src/HTTPCookie.cpp#1 $
//
// Library: Net
// Package: HTTP
@@ -44,6 +44,7 @@
#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"
#include "Poco/String.h"
#include "Poco/URI.h"
using Poco::Timestamp;
@@ -315,4 +316,26 @@ std::string HTTPCookie::toString() const
}
namespace
{
static const std::string ILLEGAL_CHARS("()[]/|\\',;");
}
std::string HTTPCookie::escape(const std::string& str)
{
std::string result;
Poco::URI::encode(str, ILLEGAL_CHARS, result);
return result;
}
std::string HTTPCookie::unescape(const std::string& str)
{
std::string result;
Poco::URI::decode(str, result);
return result;
}
} } // namespace Poco::Net

View File

@@ -88,22 +88,26 @@ void HTTPMessage::setVersion(const std::string& version)
}
void HTTPMessage::setContentLength(int length)
void HTTPMessage::setContentLength(std::streamsize length)
{
if (length != UNKNOWN_CONTENT_LENGTH)
set(CONTENT_LENGTH, NumberFormatter::format(length));
if (length != UNKNOWN_CONTENT_LENGTH)
set(CONTENT_LENGTH, NumberFormatter::format(length));
else
erase(CONTENT_LENGTH);
}
int HTTPMessage::getContentLength() const
std::streamsize HTTPMessage::getContentLength() const
{
const std::string& contentLength = get(CONTENT_LENGTH, EMPTY);
if (!contentLength.empty())
return NumberParser::parse(contentLength);
else
return UNKNOWN_CONTENT_LENGTH;
const std::string& contentLength = get(CONTENT_LENGTH, EMPTY);
if (!contentLength.empty())
{
if (sizeof(std::streamsize) == sizeof(Poco::Int64))
return static_cast<std::streamsize>(NumberParser::parse64(contentLength));
else
return static_cast<std::streamsize>(NumberParser::parse(contentLength));
}
else return UNKNOWN_CONTENT_LENGTH;
}
@@ -171,7 +175,7 @@ bool HTTPMessage::getKeepAlive() const
{
const std::string& connection = get(CONNECTION, EMPTY);
if (!connection.empty())
return icompare(connection, CONNECTION_KEEP_ALIVE) == 0;
return icompare(connection, CONNECTION_CLOSE) != 0;
else
return getVersion() == HTTP_1_1;
}

View File

@@ -1,7 +1,7 @@
//
// HTTPRequest.cpp
//
// $Id: //poco/Main/Net/src/HTTPRequest.cpp#14 $
// $Id: //poco/1.4/Net/src/HTTPRequest.cpp#1 $
//
// Library: Net
// Package: HTTP
@@ -35,11 +35,10 @@
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPSession.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/NameValueCollection.h"
#include "Poco/NumberFormatter.h"
#include <cctype>
#include "Poco/Ascii.h"
using Poco::NumberFormatter;
@@ -118,7 +117,7 @@ void HTTPRequest::setHost(const std::string& host)
void HTTPRequest::setHost(const std::string& host, Poco::UInt16 port)
{
std::string value(host);
if (port != HTTPSession::HTTP_PORT)
if (port != 80 && port != 443)
{
value.append(":");
NumberFormatter::append(value, port);
@@ -175,9 +174,9 @@ void HTTPRequest::getCredentials(std::string& scheme, std::string& authInfo) con
const std::string& auth = get(AUTHORIZATION);
std::string::const_iterator it = auth.begin();
std::string::const_iterator end = auth.end();
while (it != end && std::isspace(*it)) ++it;
while (it != end && !std::isspace(*it)) scheme += *it++;
while (it != end && std::isspace(*it)) ++it;
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && !Poco::Ascii::isSpace(*it)) scheme += *it++;
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end) authInfo += *it++;
}
else throw NotAuthenticatedException();
@@ -213,16 +212,16 @@ void HTTPRequest::read(std::istream& istr)
version.reserve(16);
int ch = istr.get();
if (ch == eof) throw NoMessageException();
while (std::isspace(ch)) ch = istr.get();
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
if (ch == eof) throw MessageException("No HTTP request header");
while (!std::isspace(ch) && ch != eof && method.length() < MAX_METHOD_LENGTH) { method += (char) ch; ch = istr.get(); }
if (!std::isspace(ch)) throw MessageException("HTTP request method invalid or too long");
while (std::isspace(ch)) ch = istr.get();
while (!std::isspace(ch) && ch != eof && uri.length() < MAX_URI_LENGTH) { uri += (char) ch; ch = istr.get(); }
if (!std::isspace(ch)) throw MessageException("HTTP request URI invalid or too long");
while (std::isspace(ch)) ch = istr.get();
while (!std::isspace(ch) && ch != eof && version.length() < MAX_VERSION_LENGTH) { version += (char) ch; ch = istr.get(); }
if (!std::isspace(ch)) throw MessageException("Invalid HTTP version string");
while (!Poco::Ascii::isSpace(ch) && ch != eof && method.length() < MAX_METHOD_LENGTH) { method += (char) ch; ch = istr.get(); }
if (!Poco::Ascii::isSpace(ch)) throw MessageException("HTTP request method invalid or too long");
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
while (!Poco::Ascii::isSpace(ch) && ch != eof && uri.length() < MAX_URI_LENGTH) { uri += (char) ch; ch = istr.get(); }
if (!Poco::Ascii::isSpace(ch)) throw MessageException("HTTP request URI invalid or too long");
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
while (!Poco::Ascii::isSpace(ch) && ch != eof && version.length() < MAX_VERSION_LENGTH) { version += (char) ch; ch = istr.get(); }
if (!Poco::Ascii::isSpace(ch)) throw MessageException("Invalid HTTP version string");
while (ch != '\n' && ch != eof) { ch = istr.get(); }
HTTPMessage::read(istr);
ch = istr.get();

View File

@@ -42,7 +42,7 @@
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTimeParser.h"
#include <cctype>
#include "Poco/Ascii.h"
using Poco::DateTime;
@@ -228,16 +228,16 @@ void HTTPResponse::read(std::istream& istr)
int ch = istr.get();
if (ch == eof) throw NoMessageException();
while (std::isspace(ch)) ch = istr.get();
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
if (ch == eof) throw MessageException("No HTTP response header");
while (!std::isspace(ch) && ch != eof && version.length() < MAX_VERSION_LENGTH) { version += (char) ch; ch = istr.get(); }
if (!std::isspace(ch)) throw MessageException("Invalid HTTP version string");
while (std::isspace(ch)) ch = istr.get();
while (!std::isspace(ch) && ch != eof && status.length() < MAX_STATUS_LENGTH) { status += (char) ch; ch = istr.get(); }
if (!std::isspace(ch)) throw MessageException("Invalid HTTP status code");
while (std::isspace(ch)) ch = istr.get();
while (!Poco::Ascii::isSpace(ch) && ch != eof && version.length() < MAX_VERSION_LENGTH) { version += (char) ch; ch = istr.get(); }
if (!Poco::Ascii::isSpace(ch)) throw MessageException("Invalid HTTP version string");
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
while (!Poco::Ascii::isSpace(ch) && ch != eof && status.length() < MAX_STATUS_LENGTH) { status += (char) ch; ch = istr.get(); }
if (!Poco::Ascii::isSpace(ch)) throw MessageException("Invalid HTTP status code");
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
while (ch != '\r' && ch != '\n' && ch != eof && reason.length() < MAX_REASON_LENGTH) { reason += (char) ch; ch = istr.get(); }
if (!std::isspace(ch)) throw MessageException("HTTP reason string too long");
if (!Poco::Ascii::isSpace(ch)) throw MessageException("HTTP reason string too long");
if (ch == '\r') ch = istr.get();
HTTPMessage::read(istr);

View File

@@ -1,93 +1,106 @@
//
// HTTPServerRequestImpl.cpp
//
// $Id: //poco/Main/Net/src/HTTPServerRequestImpl.cpp#4 $
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerRequestImpl
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Net/HTTPServerRequestImpl.h"
#include "Poco/Net/HTTPServerSession.h"
#include "Poco/Net/HTTPHeaderStream.h"
#include "Poco/Net/HTTPStream.h"
#include "Poco/Net/HTTPFixedLengthStream.h"
#include "Poco/Net/HTTPChunkedStream.h"
#include "Poco/Net/HTTPServerParams.h"
#include "Poco/String.h"
using Poco::icompare;
namespace Poco {
namespace Net {
const std::string HTTPServerRequestImpl::EXPECT("Expect");
HTTPServerRequestImpl::HTTPServerRequestImpl(HTTPServerResponse& response, HTTPServerSession& session, HTTPServerParams* pParams):
_response(response),
_pStream(0),
_pParams(pParams, true)
{
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);
else if (getContentLength() != HTTPMessage::UNKNOWN_CONTENT_LENGTH)
_pStream = new HTTPFixedLengthInputStream(session, getContentLength());
else if (getMethod() == HTTPRequest::HTTP_GET || getMethod() == HTTPRequest::HTTP_HEAD)
_pStream = new HTTPFixedLengthInputStream(session, 0);
else
_pStream = new HTTPInputStream(session);
}
HTTPServerRequestImpl::~HTTPServerRequestImpl()
{
delete _pStream;
}
bool HTTPServerRequestImpl::expectContinue() const
{
const std::string& expect = get(EXPECT, EMPTY);
return !expect.empty() && icompare(expect, "100-continue") == 0;
}
} } // namespace Poco::Net
//
// HTTPServerRequestImpl.cpp
//
// $Id: //poco/1.4/Net/src/HTTPServerRequestImpl.cpp#1 $
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerRequestImpl
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Net/HTTPServerRequestImpl.h"
#include "Poco/Net/HTTPServerSession.h"
#include "Poco/Net/HTTPHeaderStream.h"
#include "Poco/Net/HTTPStream.h"
#include "Poco/Net/HTTPFixedLengthStream.h"
#include "Poco/Net/HTTPChunkedStream.h"
#include "Poco/Net/HTTPServerParams.h"
#include "Poco/String.h"
using Poco::icompare;
namespace Poco {
namespace Net {
const std::string HTTPServerRequestImpl::EXPECT("Expect");
HTTPServerRequestImpl::HTTPServerRequestImpl(HTTPServerResponse& response, HTTPServerSession& session, HTTPServerParams* pParams):
_response(response),
_session(session),
_pStream(0),
_pParams(pParams, true)
{
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);
else if (getContentLength() != HTTPMessage::UNKNOWN_CONTENT_LENGTH)
_pStream = new HTTPFixedLengthInputStream(session, getContentLength());
else if (getMethod() == HTTPRequest::HTTP_GET || getMethod() == HTTPRequest::HTTP_HEAD)
_pStream = new HTTPFixedLengthInputStream(session, 0);
else
_pStream = new HTTPInputStream(session);
}
HTTPServerRequestImpl::~HTTPServerRequestImpl()
{
delete _pStream;
}
StreamSocket& HTTPServerRequestImpl::socket()
{
return _session.socket();
}
StreamSocket HTTPServerRequestImpl::detachSocket()
{
return _session.detachSocket();
}
bool HTTPServerRequestImpl::expectContinue() const
{
const std::string& expect = get(EXPECT, EMPTY);
return !expect.empty() && icompare(expect, "100-continue") == 0;
}
} } // namespace Poco::Net

View File

@@ -1,174 +1,177 @@
//
// HTTPServerResponseImpl.cpp
//
// $Id: //poco/Main/Net/src/HTTPServerResponseImpl.cpp#7 $
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerResponseImpl
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Net/HTTPServerResponseImpl.h"
#include "Poco/Net/HTTPServerSession.h"
#include "Poco/Net/HTTPHeaderStream.h"
#include "Poco/Net/HTTPStream.h"
#include "Poco/Net/HTTPFixedLengthStream.h"
#include "Poco/Net/HTTPChunkedStream.h"
#include "Poco/File.h"
#include "Poco/Timestamp.h"
#include "Poco/NumberFormatter.h"
#include "Poco/StreamCopier.h"
#include "Poco/CountingStream.h"
#include "Poco/Exception.h"
#include "Poco/FileStream.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
using Poco::File;
using Poco::Timestamp;
using Poco::NumberFormatter;
using Poco::StreamCopier;
using Poco::OpenFileException;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
namespace Poco {
namespace Net {
HTTPServerResponseImpl::HTTPServerResponseImpl(HTTPServerSession& session):
_session(session),
_pStream(0)
{
}
HTTPServerResponseImpl::~HTTPServerResponseImpl()
{
delete _pStream;
}
void HTTPServerResponseImpl::sendContinue()
{
HTTPHeaderOutputStream hs(_session);
hs << getVersion() << " 100 Continue\r\n\r\n";
}
std::ostream& HTTPServerResponseImpl::send()
{
poco_assert (!_pStream);
if (getChunkedTransferEncoding())
{
HTTPHeaderOutputStream hs(_session);
write(hs);
_pStream = new HTTPChunkedOutputStream(_session);
}
else if (getContentLength() != HTTPMessage::UNKNOWN_CONTENT_LENGTH)
{
Poco::CountingOutputStream cs;
write(cs);
_pStream = new HTTPFixedLengthOutputStream(_session, getContentLength() + cs.chars());
write(*_pStream);
}
else
{
_pStream = new HTTPOutputStream(_session);
setKeepAlive(false);
write(*_pStream);
}
return *_pStream;
}
void HTTPServerResponseImpl::sendFile(const std::string& path, const std::string& mediaType)
{
poco_assert (!_pStream);
File f(path);
Timestamp dateTime = f.getLastModified();
File::FileSize length = f.getSize();
set("Last-Modified", DateTimeFormatter::format(dateTime, DateTimeFormat::HTTP_FORMAT));
setContentLength(static_cast<int>(length));
setContentType(mediaType);
setChunkedTransferEncoding(false);
Poco::FileInputStream istr(path);
if (istr.good())
{
_pStream = new HTTPHeaderOutputStream(_session);
write(*_pStream);
StreamCopier::copyStream(istr, *_pStream);
}
else throw OpenFileException(path);
}
void HTTPServerResponseImpl::sendBuffer(const void* pBuffer, std::size_t length)
{
poco_assert (!_pStream);
setContentLength(static_cast<int>(length));
setChunkedTransferEncoding(false);
_pStream = new HTTPHeaderOutputStream(_session);
write(*_pStream);
_pStream->write(static_cast<const char*>(pBuffer), static_cast<std::streamsize>(length));
}
void HTTPServerResponseImpl::redirect(const std::string& uri)
{
poco_assert (!_pStream);
setStatusAndReason(HTTPResponse::HTTP_FOUND);
set("Location", uri);
_pStream = new HTTPHeaderOutputStream(_session);
write(*_pStream);
}
void HTTPServerResponseImpl::requireAuthentication(const std::string& realm)
{
poco_assert (!_pStream);
setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED);
std::string auth("Basic realm=\"");
auth.append(realm);
auth.append("\"");
set("WWW-Authenticate", auth);
}
} } // namespace Poco::Net
//
// HTTPServerResponseImpl.cpp
//
// $Id: //poco/1.4/Net/src/HTTPServerResponseImpl.cpp#1 $
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerResponseImpl
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Net/HTTPServerResponseImpl.h"
#include "Poco/Net/HTTPServerSession.h"
#include "Poco/Net/HTTPHeaderStream.h"
#include "Poco/Net/HTTPStream.h"
#include "Poco/Net/HTTPFixedLengthStream.h"
#include "Poco/Net/HTTPChunkedStream.h"
#include "Poco/File.h"
#include "Poco/Timestamp.h"
#include "Poco/NumberFormatter.h"
#include "Poco/StreamCopier.h"
#include "Poco/CountingStream.h"
#include "Poco/Exception.h"
#include "Poco/FileStream.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
using Poco::File;
using Poco::Timestamp;
using Poco::NumberFormatter;
using Poco::StreamCopier;
using Poco::OpenFileException;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
namespace Poco {
namespace Net {
HTTPServerResponseImpl::HTTPServerResponseImpl(HTTPServerSession& session):
_session(session),
_pStream(0)
{
}
HTTPServerResponseImpl::~HTTPServerResponseImpl()
{
delete _pStream;
}
void HTTPServerResponseImpl::sendContinue()
{
HTTPHeaderOutputStream hs(_session);
hs << getVersion() << " 100 Continue\r\n\r\n";
}
std::ostream& HTTPServerResponseImpl::send()
{
poco_assert (!_pStream);
if (getChunkedTransferEncoding())
{
HTTPHeaderOutputStream hs(_session);
write(hs);
_pStream = new HTTPChunkedOutputStream(_session);
}
else if (getContentLength() != HTTPMessage::UNKNOWN_CONTENT_LENGTH)
{
Poco::CountingOutputStream cs;
write(cs);
_pStream = new HTTPFixedLengthOutputStream(_session, getContentLength() + cs.chars());
write(*_pStream);
}
else
{
_pStream = new HTTPOutputStream(_session);
setKeepAlive(false);
write(*_pStream);
}
return *_pStream;
}
void HTTPServerResponseImpl::sendFile(const std::string& path, const std::string& mediaType)
{
poco_assert (!_pStream);
File f(path);
Timestamp dateTime = f.getLastModified();
File::FileSize length = f.getSize();
set("Last-Modified", DateTimeFormatter::format(dateTime, DateTimeFormat::HTTP_FORMAT));
setContentLength(static_cast<int>(length));
setContentType(mediaType);
setChunkedTransferEncoding(false);
Poco::FileInputStream istr(path);
if (istr.good())
{
_pStream = new HTTPHeaderOutputStream(_session);
write(*_pStream);
StreamCopier::copyStream(istr, *_pStream);
}
else throw OpenFileException(path);
}
void HTTPServerResponseImpl::sendBuffer(const void* pBuffer, std::size_t length)
{
poco_assert (!_pStream);
setContentLength(static_cast<int>(length));
setChunkedTransferEncoding(false);
_pStream = new HTTPHeaderOutputStream(_session);
write(*_pStream);
_pStream->write(static_cast<const char*>(pBuffer), static_cast<std::streamsize>(length));
}
void HTTPServerResponseImpl::redirect(const std::string& uri, HTTPStatus status)
{
poco_assert (!_pStream);
setContentLength(0);
setChunkedTransferEncoding(false);
setStatusAndReason(status);
set("Location", uri);
_pStream = new HTTPHeaderOutputStream(_session);
write(*_pStream);
}
void HTTPServerResponseImpl::requireAuthentication(const std::string& realm)
{
poco_assert (!_pStream);
setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED);
std::string auth("Basic realm=\"");
auth.append(realm);
auth.append("\"");
set("WWW-Authenticate", auth);
}
} } // namespace Poco::Net

View File

@@ -59,6 +59,8 @@ HTTPServerSession::~HTTPServerSession()
bool HTTPServerSession::hasMoreRequests()
{
if (!socket().impl()->initialized()) return false;
if (_firstRequest)
{
_firstRequest = false;

View File

@@ -84,9 +84,15 @@ HTTPSession::HTTPSession(const StreamSocket& socket, bool keepAlive):
HTTPSession::~HTTPSession()
{
if (_pBuffer) HTTPBufferAllocator::deallocate(_pBuffer, HTTPBufferAllocator::BUFFER_SIZE);
close();
delete _pException;
if (_pBuffer) HTTPBufferAllocator::deallocate(_pBuffer, HTTPBufferAllocator::BUFFER_SIZE);
try
{
close();
}
catch (...)
{
}
delete _pException;
}
@@ -229,4 +235,10 @@ void HTTPSession::attachSocket(const StreamSocket& socket)
}
void HTTPSession::attachSessionData(const Poco::Any& data)
{
_data = data;
}
} } // namespace Poco::Net

View File

@@ -119,12 +119,13 @@ HTTPClientSession* HTTPSessionFactory::createClientSession(const Poco::URI& uri)
if (uri.isRelative()) throw Poco::UnknownURISchemeException("Relative URIs are not supported by HTTPSessionFactory.");
Instantiators::iterator it = _instantiators.find(uri.getScheme());
if (it != _instantiators.end())
{
it->second.pIn->setProxy(_proxyHost, _proxyPort);
return it->second.pIn->createClientSession(uri);
}
else throw Poco::UnknownURISchemeException(uri.getScheme());
if (it != _instantiators.end())
{
it->second.pIn->setProxy(_proxyHost, _proxyPort);
it->second.pIn->setProxyCredentials(_proxyUsername, _proxyPassword);
return it->second.pIn->createClientSession(uri);
}
else throw Poco::UnknownURISchemeException(uri.getScheme());
}
@@ -137,10 +138,24 @@ void HTTPSessionFactory::setProxy(const std::string& host, Poco::UInt16 port)
}
void HTTPSessionFactory::setProxyCredentials(const std::string& username, const std::string& password)
{
FastMutex::ScopedLock lock(_mutex);
_proxyUsername = username;
_proxyPassword = password;
}
namespace
{
static SingletonHolder<HTTPSessionFactory> singleton;
}
HTTPSessionFactory& HTTPSessionFactory::defaultFactory()
{
static SingletonHolder<HTTPSessionFactory> singleton;
return *singleton.get();
return *singleton.get();
}

View File

@@ -62,6 +62,7 @@ HTTPClientSession* HTTPSessionInstantiator::createClientSession(const Poco::URI&
poco_assert (uri.getScheme() == "http");
HTTPClientSession* pSession = new HTTPClientSession(uri.getHost(), uri.getPort());
pSession->setProxy(proxyHost(), proxyPort());
pSession->setProxyCredentials(proxyUsername(), proxyPassword());
return pSession;
}
@@ -85,4 +86,11 @@ void HTTPSessionInstantiator::setProxy(const std::string& host, Poco::UInt16 por
}
void HTTPSessionInstantiator::setProxyCredentials(const std::string& username, const std::string& password)
{
_proxyUsername = username;
_proxyPassword = password;
}
} } // namespace Poco::Net

View File

@@ -68,6 +68,15 @@ HTTPStreamFactory::HTTPStreamFactory(const std::string& proxyHost, Poco::UInt16
}
HTTPStreamFactory::HTTPStreamFactory(const std::string& proxyHost, Poco::UInt16 proxyPort, const std::string& proxyUsername, const std::string& proxyPassword):
_proxyHost(proxyHost),
_proxyPort(proxyPort),
_proxyUsername(proxyUsername),
_proxyPassword(proxyPassword)
{
}
HTTPStreamFactory::~HTTPStreamFactory()
{
}
@@ -92,7 +101,8 @@ std::istream* HTTPStreamFactory::open(const URI& uri)
pSession->setProxy(_proxyHost, _proxyPort);
else
pSession->setProxy(proxyUri.getHost(), proxyUri.getPort());
pSession->setProxyCredentials(_proxyUsername, _proxyPassword);
std::string path = resolvedURI.getPathAndQuery();
if (path.empty()) path = "/";
HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
@@ -114,14 +124,14 @@ std::istream* HTTPStreamFactory::open(const URI& uri)
}
else if (res.getStatus() == HTTPResponse::HTTP_USEPROXY && !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
//single request via the proxy. 305 responses MUST only be generated by origin servers.
// 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; pSession = 0;
retry = true; //only allow useproxy once
retry = true; // only allow useproxy once
}
else
{

View File

@@ -43,17 +43,12 @@ namespace Poco {
namespace Net {
//
// HostEntryImpl
//
HostEntryImpl::HostEntryImpl()
HostEntry::HostEntry()
{
}
HostEntryImpl::HostEntryImpl(struct hostent* entry)
HostEntry::HostEntry(struct hostent* entry)
{
poco_check_ptr (entry);
@@ -79,10 +74,10 @@ HostEntryImpl::HostEntryImpl(struct hostent* entry)
}
#if defined(_WIN32) && defined(POCO_HAVE_IPv6)
#if defined(POCO_HAVE_IPv6)
HostEntryImpl::HostEntryImpl(struct addrinfo* ainfo)
HostEntry::HostEntry(struct addrinfo* ainfo)
{
poco_check_ptr (ainfo);
@@ -97,48 +92,59 @@ HostEntryImpl::HostEntryImpl(struct addrinfo* ainfo)
switch (ai->ai_addr->sa_family)
{
case AF_INET:
_addresses.push_back(IPAddress(&reinterpret_cast<struct sockaddr_in*>(ai->ai_addr)->sin_addr, sizeof(in_addr)));
break;
case AF_INET6:
_addresses.push_back(IPAddress(&reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr)->sin6_addr, sizeof(in6_addr)));
break;
}
}
_addresses.push_back(IPAddress(&reinterpret_cast<struct sockaddr_in*>(ai->ai_addr)->sin_addr, sizeof(in_addr)));
break;
case AF_INET6:
_addresses.push_back(IPAddress(&reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr)->sin6_addr, sizeof(in6_addr), reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr)->sin6_scope_id));
break;
}
}
}
}
#endif
#endif // POCO_HAVE_IPv6
HostEntryImpl::~HostEntryImpl()
#if defined(POCO_VXWORKS)
HostEntry::HostEntry(const std::string& name, const IPAddress& addr):
_name(name)
{
_addresses.push_back(addr);
}
#endif // POCO_VXWORKS
HostEntry::HostEntry(const HostEntry& entry):
_name(entry._name),
_aliases(entry._aliases),
_addresses(entry._addresses)
{
}
//
// HostEntry
//
HostEntry::HostEntry():
_pImpl(new HostEntryImpl)
{
}
HostEntry::HostEntry(struct hostent* entry):
_pImpl(new HostEntryImpl(entry))
HostEntry& HostEntry::operator = (const HostEntry& entry)
{
if (&entry != this)
{
_name = entry._name;
_aliases = entry._aliases;
_addresses = entry._addresses;
}
return *this;
}
#if defined(_WIN32) && defined(POCO_HAVE_IPv6)
HostEntry::HostEntry(struct addrinfo* info):
_pImpl(new HostEntryImpl(info))
void HostEntry::swap(HostEntry& hostEntry)
{
std::swap(_name, hostEntry._name);
std::swap(_aliases, hostEntry._aliases);
std::swap(_addresses, hostEntry._addresses);
}
#endif
HostEntry::~HostEntry()
@@ -146,18 +152,4 @@ HostEntry::~HostEntry()
}
HostEntry::HostEntry(const HostEntry& entry):
_pImpl(entry._pImpl)
{
}
HostEntry& HostEntry::operator = (const HostEntry& entry)
{
HostEntry tmp(entry);
tmp.swap(*this);
return *this;
}
} } // namespace Poco::Net

View File

@@ -41,6 +41,7 @@
#include "Poco/Net/DNS.h"
#include "Poco/Exception.h"
#include "Poco/Net/NetException.h"
#include <numeric>
using Poco::IOException;
@@ -56,7 +57,7 @@ ICMPEventArgs::ICMPEventArgs(const SocketAddress& address, int repetitions, int
_sent(0),
_dataSize(dataSize),
_ttl(ttl),
_rtt(0, repetitions),
_rtt(repetitions, 0),
_errors(repetitions)
{
}
@@ -97,8 +98,8 @@ std::string ICMPEventArgs::hostAddress() const
void ICMPEventArgs::setRepetitions(int repetitions)
{
_rtt.apply(&ICMPEventArgs::zeroVal);
if (_rtt.size() != repetitions) _rtt.resize(repetitions, 0);
_rtt.clear();
_rtt.resize(repetitions, 0);
_errors.assign(repetitions, "");
}
@@ -174,7 +175,7 @@ int ICMPEventArgs::avgRTT() const
{
if (0 == _rtt.size()) return 0;
return (int) (_rtt.sum() / _rtt.size());
return (int) (std::accumulate(_rtt.begin(), _rtt.end(), 0) / _rtt.size());
}
@@ -186,10 +187,4 @@ float ICMPEventArgs::percent() const
}
int ICMPEventArgs::zeroVal(int n)
{
return n*0;
}
} } // namespace Poco::Net

View File

@@ -39,7 +39,6 @@
#include "Poco/Net/NetException.h"
#include "Poco/Timestamp.h"
#include "Poco/Timespan.h"
#include "Poco/Process.h"
#include "Poco/NumberFormatter.h"
#include <sstream>
@@ -48,7 +47,6 @@ using Poco::InvalidArgumentException;
using Poco::NotImplementedException;
using Poco::Timestamp;
using Poco::Timespan;
using Poco::Process;
using Poco::NumberFormatter;
using Poco::UInt8;
using Poco::UInt16;

View File

@@ -1,7 +1,7 @@
//
// ICMPPacketImpl.cpp
//
// $Id: //poco/svn/Net/src/ICMPPacketImpl.cpp#2 $
// $Id: //poco/1.4/Net/src/ICMPPacketImpl.cpp#2 $
//
// Library: Net
// Package: ICMP
@@ -38,7 +38,6 @@
#include "Poco/Net/NetException.h"
#include "Poco/Timestamp.h"
#include "Poco/Timespan.h"
#include "Poco/Process.h"
#include "Poco/NumberFormatter.h"
#include <sstream>
@@ -46,7 +45,6 @@
using Poco::InvalidArgumentException;
using Poco::Timestamp;
using Poco::Timespan;
using Poco::Process;
using Poco::NumberFormatter;
using Poco::UInt8;
using Poco::UInt16;

View File

@@ -1,7 +1,7 @@
//
// ICMPSocketImpl.cpp
//
// $Id: //poco/svn/Net/src/ICMPSocketImpl.cpp#2 $
// $Id: //poco/1.4/Net/src/ICMPSocketImpl.cpp#1 $
//
// Library: Net
// Package: ICMP
@@ -37,6 +37,7 @@
#include "Poco/Net/ICMPSocketImpl.h"
#include "Poco/Net/NetException.h"
#include "Poco/Timespan.h"
#include "Poco/Timestamp.h"
#include "Poco/Exception.h"
@@ -51,7 +52,8 @@ namespace Net {
ICMPSocketImpl::ICMPSocketImpl(IPAddress::Family family, int dataSize, int ttl, int timeout):
RawSocketImpl(family, IPPROTO_ICMP),
_icmpPacket(family, dataSize)
_icmpPacket(family, dataSize),
_timeout(timeout)
{
setOption(IPPROTO_IP, IP_TTL, ttl);
setReceiveTimeout(Timespan(timeout));
@@ -77,21 +79,28 @@ int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags)
try
{
Poco::Timestamp ts;
do
{
if (ts.isElapsed(_timeout))
{
// This guards against a possible DoS attack, where sending
// fake ping responses will cause an endless loop.
throw TimeoutException();
}
SocketImpl::receiveFrom(buffer, maxPacketSize, address, flags);
}
while(!_icmpPacket.validReplyID(buffer, maxPacketSize));
while (!_icmpPacket.validReplyID(buffer, maxPacketSize));
}
catch (TimeoutException&)
{
delete[] buffer;
delete [] buffer;
throw;
}
catch (Exception&)
{
std::string err = _icmpPacket.errorDescription(buffer, maxPacketSize);
delete[] buffer;
delete [] buffer;
if (!err.empty())
throw ICMPException(err);
else

View File

@@ -38,8 +38,10 @@
#include "Poco/Net/NetException.h"
#include "Poco/Timestamp.h"
#include "Poco/Timespan.h"
#include "Poco/Process.h"
#include "Poco/NumberFormatter.h"
#if !defined(POCO_VXWORKS)
#include "Poco/Process.h"
#endif
#include <sstream>
@@ -57,11 +59,11 @@ namespace Poco {
namespace Net {
const UInt8 ICMPv4PacketImpl::DESTINATION_UNREACHABLE_TYPE = 3;
const UInt8 ICMPv4PacketImpl::SOURCE_QUENCH_TYPE = 4;
const UInt8 ICMPv4PacketImpl::REDIRECT_MESSAGE_TYPE = 5;
const UInt8 ICMPv4PacketImpl::TIME_EXCEEDED_TYPE = 11;
const UInt8 ICMPv4PacketImpl::PARAMETER_PROBLEM_TYPE = 12;
const UInt8 ICMPv4PacketImpl::DESTINATION_UNREACHABLE_TYPE = 3;
const Poco::UInt8 ICMPv4PacketImpl::SOURCE_QUENCH_TYPE = 4;
const Poco::UInt8 ICMPv4PacketImpl::REDIRECT_MESSAGE_TYPE = 5;
const UInt8 ICMPv4PacketImpl::TIME_EXCEEDED_TYPE = 11;
const Poco::UInt8 ICMPv4PacketImpl::PARAMETER_PROBLEM_TYPE = 12;
const std::string ICMPv4PacketImpl::MESSAGE_TYPE[] =
@@ -125,10 +127,10 @@ const std::string ICMPv4PacketImpl::PARAMETER_PROBLEM_CODE[] =
ICMPv4PacketImpl::ICMPv4PacketImpl(int dataSize):
ICMPPacketImpl(dataSize),
_seq(0)
ICMPPacketImpl(dataSize),
_seq(0)
{
initPacket();
initPacket();
}
@@ -152,8 +154,12 @@ void ICMPv4PacketImpl::initPacket()
icp->code = 0;
icp->checksum = 0;
icp->seq = ++_seq;
icp->id = static_cast<UInt16>(Process::id());
#if defined(POCO_VXWORKS)
icp->id = 0;
#else
icp->id = static_cast<UInt16>(Poco::Process::id());
#endif
struct timeval* ptp = (struct timeval *) (icp + 1);
*ptp = time();
@@ -202,7 +208,11 @@ Poco::UInt8* ICMPv4PacketImpl::data(Poco::UInt8* buffer, int length) const
bool ICMPv4PacketImpl::validReplyID(Poco::UInt8* buffer, int length) const
{
Header *icp = header(buffer, length);
return icp && (Process::id() == icp->id);
#if defined(POCO_VXWORKS)
return icp && icp->id == 0;
#else
return icp && (static_cast<Poco::UInt16>(Process::id()) == icp->id);
#endif
}

View File

@@ -7,7 +7,7 @@
// Package: NetCore
// Module: IPAddress
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// Copyright (c) 2005-2011, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
@@ -64,12 +64,13 @@ class IPAddressImpl: public RefCountedObject
public:
virtual std::string toString() const = 0;
virtual poco_socklen_t length() const = 0;
virtual const void* addr() const = 0;
virtual IPAddress::Family family() const = 0;
virtual int af() const = 0;
virtual bool isWildcard() const = 0;
virtual bool isBroadcast() const = 0;
virtual bool isLoopback() const = 0;
virtual const void* addr() const = 0;
virtual IPAddress::Family family() const = 0;
virtual int af() const = 0;
virtual Poco::UInt32 scope() const = 0;
virtual bool isWildcard() const = 0;
virtual bool isBroadcast() const = 0;
virtual bool isLoopback() const = 0;
virtual bool isMulticast() const = 0;
virtual bool isLinkLocal() const = 0;
virtual bool isSiteLocal() const = 0;
@@ -85,13 +86,19 @@ public:
virtual IPAddressImpl* clone() const = 0;
protected:
IPAddressImpl()
{
}
virtual ~IPAddressImpl()
{
}
IPAddressImpl()
{
#if defined(_WIN32)
Poco::Net::initializeNetwork();
#endif
}
virtual ~IPAddressImpl()
{
#if defined(_WIN32)
Poco::Net::uninitializeNetwork();
#endif
}
private:
IPAddressImpl(const IPAddressImpl&);
@@ -144,12 +151,17 @@ public:
int af() const
{
return AF_INET;
}
bool isWildcard() const
{
return _addr.s_addr == INADDR_ANY;
return AF_INET;
}
Poco::UInt32 scope() const
{
return 0;
}
bool isWildcard() const
{
return _addr.s_addr == INADDR_ANY;
}
bool isBroadcast() const
@@ -159,7 +171,7 @@ public:
bool isLoopback() const
{
return ntohl(_addr.s_addr) == 0x7F000001; // 127.0.0.1
return (ntohl(_addr.s_addr) & 0xFF000000) == 0x7F000000; // 127.0.0.1 to 127.255.255.255
}
bool isMulticast() const
@@ -232,9 +244,9 @@ public:
else
return new IPv4AddressImpl(&ia);
#else
#if __GNUC__ < 3
#if __GNUC__ < 3 || defined(POCO_VXWORKS)
struct in_addr ia;
ia.s_addr = inet_addr(addr.c_str());
ia.s_addr = inet_addr(const_cast<char*>(addr.c_str()));
if (ia.s_addr == INADDR_NONE && addr != "255.255.255.255")
return 0;
else
@@ -273,15 +285,23 @@ private:
class IPv6AddressImpl: public IPAddressImpl
{
public:
IPv6AddressImpl()
{
std::memset(&_addr, 0, sizeof(_addr));
}
IPv6AddressImpl():
_scope(0)
{
std::memset(&_addr, 0, sizeof(_addr));
}
IPv6AddressImpl(const void* addr)
{
std::memcpy(&_addr, addr, sizeof(_addr));
}
IPv6AddressImpl(const void* addr):
_scope(0)
{
std::memcpy(&_addr, addr, sizeof(_addr));
}
IPv6AddressImpl(const void* addr, Poco::UInt32 scope):
_scope(scope)
{
std::memcpy(&_addr, addr, sizeof(_addr));
}
std::string toString() const
{
@@ -304,13 +324,13 @@ public:
NumberFormatter::append(result, bytes[15]);
return result;
}
else
{
std::string result;
result.reserve(46);
bool zeroSequence = false;
int i = 0;
while (i < 8)
else
{
std::string result;
result.reserve(64);
bool zeroSequence = false;
int i = 0;
while (i < 8)
{
if (!zeroSequence && words[i] == 0)
{
@@ -323,12 +343,29 @@ public:
zeroSequence = true;
}
}
if (i > 0) result.append(":");
if (i < 8) NumberFormatter::appendHex(result, ntohs(words[i++]));
}
return result;
}
}
if (i > 0) result.append(":");
if (i < 8) NumberFormatter::appendHex(result, ntohs(words[i++]));
}
if (_scope > 0)
{
result.append("%");
#if defined(_WIN32)
NumberFormatter::append(result, _scope);
#else
char buffer[IFNAMSIZ];
if (if_indextoname(_scope, buffer))
{
result.append(buffer);
}
else
{
NumberFormatter::append(result, _scope);
}
#endif
}
return result;
}
}
poco_socklen_t length() const
{
@@ -347,12 +384,17 @@ public:
int af() const
{
return AF_INET6;
}
return AF_INET6;
}
Poco::UInt32 scope() const
{
return _scope;
}
bool isWildcard() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
bool isWildcard() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
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;
}
@@ -363,79 +405,79 @@ public:
}
bool isLoopback() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
words[4] == 0 && words[5] == 0 && words[6] == 0 && words[7] == 1;
}
bool isMulticast() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (words[0] & 0xFFE0) == 0xFF00;
}
bool isLinkLocal() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (words[0] & 0xFFE0) == 0xFE80;
}
bool isSiteLocal() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (words[0] & 0xFFE0) == 0xFEC0;
}
bool isIPv4Compatible() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
words[4] == 0 && words[5] == 0 && words[6] == 0 && ntohs(words[7]) == 0x0001;
}
bool isMulticast() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFE0) == 0xFF00;
}
bool isLinkLocal() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFE0) == 0xFE80;
}
bool isSiteLocal() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFE0) == 0xFEC0;
}
bool isIPv4Compatible() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && words[5] == 0;
}
bool isIPv4Mapped() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && words[5] == 0xFFFF;
}
bool isIPv4Mapped() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && ntohs(words[5]) == 0xFFFF;
}
bool isWellKnownMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (words[0] & 0xFFF0) == 0xFF00;
}
bool isNodeLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (words[0] & 0xFFEF) == 0xFF01;
}
bool isLinkLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (words[0] & 0xFFEF) == 0xFF02;
}
bool isSiteLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (words[0] & 0xFFEF) == 0xFF05;
}
bool isOrgLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (words[0] & 0xFFEF) == 0xFF08;
}
bool isGlobalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (words[0] & 0xFFEF) == 0xFF0F;
}
bool isWellKnownMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFF0) == 0xFF00;
}
bool isNodeLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFEF) == 0xFF01;
}
bool isLinkLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFEF) == 0xFF02;
}
bool isSiteLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFEF) == 0xFF05;
}
bool isOrgLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFEF) == 0xFF08;
}
bool isGlobalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ntohs(words[0]) & 0xFFEF) == 0xFF0F;
}
static IPv6AddressImpl* parse(const std::string& addr)
static IPv6AddressImpl* parse(const std::string& addr)
{
if (addr.empty()) return 0;
#if defined(_WIN32)
@@ -443,20 +485,37 @@ public:
struct addrinfo hints;
std::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
int rc = getaddrinfo(addr.c_str(), NULL, &hints, &pAI);
if (rc == 0)
{
IPv6AddressImpl* pResult = new IPv6AddressImpl(&reinterpret_cast<struct sockaddr_in6*>(pAI->ai_addr)->sin6_addr);
freeaddrinfo(pAI);
return pResult;
}
else return 0;
int rc = getaddrinfo(addr.c_str(), NULL, &hints, &pAI);
if (rc == 0)
{
IPv6AddressImpl* pResult = new IPv6AddressImpl(&reinterpret_cast<struct sockaddr_in6*>(pAI->ai_addr)->sin6_addr, static_cast<int>(reinterpret_cast<struct sockaddr_in6*>(pAI->ai_addr)->sin6_scope_id));
freeaddrinfo(pAI);
return pResult;
}
else return 0;
#else
struct in6_addr ia;
if (inet_pton(AF_INET6, addr.c_str(), &ia) == 1)
return new IPv6AddressImpl(&ia);
struct in6_addr ia;
std::string::size_type pos = addr.find('%');
if (std::string::npos != pos)
{
std::string::size_type start = ('[' == addr[0]) ? 1 : 0;
std::string unscopedAddr(addr, start, pos - start);
std::string scope(addr, pos + 1, addr.size() - start - pos);
Poco::UInt32 scopeId(0);
if (!(scopeId = if_nametoindex(scope.c_str())))
return 0;
if (inet_pton(AF_INET6, unscopedAddr.c_str(), &ia) == 1)
return new IPv6AddressImpl(&ia, scopeId);
else
return 0;
}
else
return 0;
{
if (inet_pton(AF_INET6, addr.c_str(), &ia) == 1)
return new IPv6AddressImpl(&ia);
else
return 0;
}
#endif
}
@@ -465,13 +524,14 @@ public:
throw Poco::NotImplementedException("mask() is only supported for IPv4 addresses");
}
IPAddressImpl* clone() const
{
return new IPv6AddressImpl(&_addr);
}
IPAddressImpl* clone() const
{
return new IPv6AddressImpl(&_addr, _scope);
}
private:
struct in6_addr _addr;
struct in6_addr _addr;
Poco::UInt32 _scope;
};
@@ -543,9 +603,21 @@ IPAddress::IPAddress(const void* addr, poco_socklen_t length)
}
IPAddress::IPAddress(const void* addr, poco_socklen_t length, Poco::UInt32 scope)
{
if (length == sizeof(struct in_addr))
_pImpl = new IPv4AddressImpl(addr);
#if defined(POCO_HAVE_IPv6)
else if (length == sizeof(struct in6_addr))
_pImpl = new IPv6AddressImpl(addr, scope);
#endif
else throw Poco::InvalidArgumentException("Invalid address length passed to IPAddress()");
}
IPAddress::~IPAddress()
{
_pImpl->release();
_pImpl->release();
}
@@ -572,10 +644,16 @@ IPAddress::Family IPAddress::family() const
return _pImpl->family();
}
Poco::UInt32 IPAddress::scope() const
{
return _pImpl->scope();
}
std::string IPAddress::toString() const
{
return _pImpl->toString();
return _pImpl->toString();
}
@@ -799,4 +877,18 @@ void IPAddress::mask(const IPAddress& mask, const IPAddress& set)
}
IPAddress IPAddress::wildcard(Family family)
{
return IPAddress(family);
}
IPAddress IPAddress::broadcast()
{
struct in_addr ia;
ia.s_addr = INADDR_NONE;
return IPAddress(&ia, sizeof(ia));
}
} } // namespace Poco::Net

View File

@@ -49,8 +49,9 @@
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeParser.h"
#include "Poco/String.h"
#include "Poco/StreamCopier.h"
#include "Poco/NumberFormatter.h"
#include <sstream>
#include <cctype>
using Poco::Base64Encoder;
@@ -82,12 +83,7 @@ namespace
void handlePart(const MessageHeader& header, std::istream& stream)
{
int ch = stream.get();
while (ch >= 0)
{
_str += (char) ch;
ch = stream.get();
}
Poco::StreamCopier::copyToString(stream, _str);
}
private:
@@ -320,7 +316,7 @@ void MailMessage::writeMultipart(MessageHeader& header, std::ostream& ostr) cons
void MailMessage::writePart(MultipartWriter& writer, const Part& part) const
{
MessageHeader partHeader;
MessageHeader partHeader(part.pSource->headers());
MediaType mediaType(part.pSource->mediaType());
if (!part.name.empty())
mediaType.setParameter("name", part.name);
@@ -356,12 +352,14 @@ void MailMessage::writeEncoded(std::istream& istr, std::ostream& ostr, ContentTr
{
QuotedPrintableEncoder encoder(ostr);
StreamCopier::copyStream(istr, encoder);
encoder.close();
}
break;
case ENCODING_BASE64:
{
Base64Encoder encoder(ostr);
StreamCopier::copyStream(istr, encoder);
encoder.close();
}
break;
}
@@ -458,7 +456,7 @@ const std::string& MailMessage::contentTransferEncodingToString(ContentTransferE
switch (encoding)
{
case ENCODING_7BIT:
return CTE_8BIT;
return CTE_7BIT;
case ENCODING_8BIT:
return CTE_8BIT;
case ENCODING_QUOTED_PRINTABLE:
@@ -501,4 +499,79 @@ void MailMessage::appendRecipient(const MailRecipient& recipient, std::string& s
}
std::string MailMessage::encodeWord(const std::string& text, const std::string& charset)
{
bool containsNonASCII = false;
for (std::string::const_iterator it = text.begin(); it != text.end(); ++it)
{
if (static_cast<unsigned char>(*it) > 127)
{
containsNonASCII = true;
break;
}
}
if (!containsNonASCII) return text;
std::string encodedText;
std::string::size_type lineLength = 0;
for (std::string::const_iterator it = text.begin(); it != text.end(); ++it)
{
if (lineLength == 0)
{
encodedText += "=?";
encodedText += charset;
encodedText += "?q?";
lineLength += charset.length() + 5;
}
switch (*it)
{
case ' ':
encodedText += '_';
lineLength++;
break;
case '=':
case '?':
case '_':
case '(':
case ')':
case '[':
case ']':
case '<':
case '>':
case ',':
case ';':
case ':':
case '.':
case '@':
encodedText += '=';
NumberFormatter::appendHex(encodedText, static_cast<unsigned>(static_cast<unsigned char>(*it)), 2);
lineLength += 3;
break;
default:
if (*it > 32 && *it < 127)
{
encodedText += *it;
lineLength++;
}
else
{
encodedText += '=';
NumberFormatter::appendHex(encodedText, static_cast<unsigned>(static_cast<unsigned char>(*it)), 2);
lineLength += 3;
}
}
if ((lineLength >= 64 && (*it == ' ' || *it == '\t' || *it == '\r' || *it == '\n')) || lineLength >= 72)
{
encodedText += "?=\r\n ";
lineLength = 0;
}
}
if (lineLength > 0)
{
encodedText += "?=";
}
return encodedText;
}
} } // namespace Poco::Net

View File

@@ -37,8 +37,8 @@
#include "Poco/Net/MediaType.h"
#include "Poco/Net/MessageHeader.h"
#include "Poco/String.h"
#include "Poco/Ascii.h"
#include <algorithm>
#include <cctype>
using Poco::icompare;
@@ -172,6 +172,28 @@ bool MediaType::matches(const std::string& type) const
}
bool MediaType::matchesRange(const MediaType& mediaType) const
{
return matchesRange(mediaType._type, mediaType._subType);
}
bool MediaType::matchesRange(const std::string& type, const std::string& subType) const
{
if (_type == "*" || type == "*" || icompare(_type, type) == 0)
{
return _subType == "*" || subType == "*" || icompare(_subType, subType) == 0;
}
else return false;
}
bool MediaType::matchesRange(const std::string& type) const
{
return _type == "*" || type == "*" || matches(type);
}
void MediaType::parse(const std::string& mediaType)
{
_type.clear();
@@ -179,10 +201,10 @@ void MediaType::parse(const std::string& mediaType)
_parameters.clear();
std::string::const_iterator it = mediaType.begin();
std::string::const_iterator end = mediaType.end();
while (it != end && std::isspace(*it)) ++it;
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && *it != '/') _type += *it++;
if (it != end) ++it;
while (it != end && *it != ';' && !std::isspace(*it)) _subType += *it++;
while (it != end && *it != ';' && !Poco::Ascii::isSpace(*it)) _subType += *it++;
while (it != end && *it != ';') ++it;
MessageHeader::splitParameters(it, end, _parameters);
}

View File

@@ -1,7 +1,7 @@
//
// MessageHeader.cpp
//
// $Id: //poco/Main/Net/src/MessageHeader.cpp#13 $
// $Id: //poco/1.4/Net/src/MessageHeader.cpp#3 $
//
// Library: Net
// Package: Messages
@@ -37,7 +37,7 @@
#include "Poco/Net/MessageHeader.h"
#include "Poco/Net/NetException.h"
#include "Poco/String.h"
#include <cctype>
#include "Poco/Ascii.h"
namespace Poco {
@@ -81,35 +81,38 @@ void MessageHeader::write(std::ostream& ostr) const
void MessageHeader::read(std::istream& istr)
{
static const int eof = std::char_traits<char>::eof();
std::streambuf& buf = *istr.rdbuf();
std::string name;
std::string value;
name.reserve(32);
value.reserve(64);
int ch = istr.get();
int ch = buf.sbumpc();
while (ch != eof && ch != '\r' && ch != '\n')
{
name.clear();
value.clear();
while (ch != eof && ch != ':' && ch != '\n' && name.length() < MAX_NAME_LENGTH) { name += ch; ch = istr.get(); }
if (ch == '\n') { ch = istr.get(); continue; } // ignore invalid header lines
while (ch != eof && ch != ':' && ch != '\n' && name.length() < MAX_NAME_LENGTH) { 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 = istr.get(); // ':'
while (std::isspace(ch)) ch = istr.get();
while (ch != eof && ch != '\r' && ch != '\n' && value.length() < MAX_VALUE_LENGTH) { value += ch; ch = istr.get(); }
if (ch == '\r') ch = istr.get();
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(); }
if (ch == '\r') ch = buf.sbumpc();
if (ch == '\n')
ch = istr.get();
ch = buf.sbumpc();
else if (ch != eof)
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 = istr.get(); }
if (ch == '\r') ch = istr.get();
while (ch != eof && ch != '\r' && ch != '\n' && value.length() < MAX_VALUE_LENGTH) { value += ch; ch = buf.sbumpc(); }
if (ch == '\r') ch = buf.sbumpc();
if (ch == '\n')
ch = istr.get();
ch = buf.sbumpc();
else if (ch != eof)
throw MessageException("Folded field value too long/no CRLF found");
}
Poco::trimRightInPlace(value);
add(name, value);
}
istr.putback(ch);
@@ -169,7 +172,7 @@ void MessageHeader::splitParameters(const std::string& s, std::string& value, Na
parameters.clear();
std::string::const_iterator it = s.begin();
std::string::const_iterator end = s.end();
while (it != end && std::isspace(*it)) ++it;
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && *it != ';') value += *it++;
Poco::trimRightInPlace(value);
if (it != end) ++it;
@@ -188,11 +191,11 @@ void MessageHeader::splitParameters(const std::string::const_iterator& begin, co
{
pname.clear();
pvalue.clear();
while (it != end && std::isspace(*it)) ++it;
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && *it != '=' && *it != ';') pname += *it++;
Poco::trimRightInPlace(pname);
if (it != end && *it != ';') ++it;
while (it != end && std::isspace(*it)) ++it;
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && *it != ';')
{
if (*it == '"')
@@ -228,7 +231,7 @@ void MessageHeader::quote(const std::string& value, std::string& result, bool al
bool mustQuote = false;
for (std::string::const_iterator it = value.begin(); !mustQuote && it != value.end(); ++it)
{
if (!std::isalnum(*it) && *it != '.' && *it != '_' && *it != '-' && !(std::isspace(*it) && allowSpace))
if (!Poco::Ascii::isAlphaNumeric(*it) && *it != '.' && *it != '_' && *it != '-' && !(Poco::Ascii::isSpace(*it) && allowSpace))
mustQuote = true;
}
if (mustQuote) result += '"';

View File

@@ -99,16 +99,16 @@ MulticastSocket& MulticastSocket::operator = (const Socket& socket)
}
void MulticastSocket::setInterface(const NetworkInterface& interface)
void MulticastSocket::setInterface(const NetworkInterface& interfc)
{
if (!interface.supportsIPv6())
if (!interfc.supportsIPv6())
{
impl()->setOption(IPPROTO_IP, IP_MULTICAST_IF, interface.address());
impl()->setOption(IPPROTO_IP, IP_MULTICAST_IF, interfc.address());
}
else
{
#if defined(POCO_HAVE_IPv6)
impl()->setOption(IPPROTO_IPV6, IPV6_MULTICAST_IF, interface.index());
impl()->setOption(IPPROTO_IPV6, IPV6_MULTICAST_IF, interfc.index());
#endif
}
}
@@ -215,13 +215,13 @@ void MulticastSocket::joinGroup(const IPAddress& groupAddress)
}
void MulticastSocket::joinGroup(const IPAddress& groupAddress, const NetworkInterface& interface)
void MulticastSocket::joinGroup(const IPAddress& groupAddress, const NetworkInterface& interfc)
{
if (groupAddress.af() == AF_INET)
{
struct ip_mreq mr;
std::memcpy(&mr.imr_multiaddr, groupAddress.addr(), groupAddress.length());
std::memcpy(&mr.imr_interface, interface.address().addr(), interface.address().length());
std::memcpy(&mr.imr_interface, interfc.address().addr(), interfc.address().length());
impl()->setRawOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr));
}
else
@@ -229,7 +229,7 @@ void MulticastSocket::joinGroup(const IPAddress& groupAddress, const NetworkInte
#if defined(POCO_HAVE_IPv6)
struct ipv6_mreq mr;
std::memcpy(&mr.ipv6mr_multiaddr, groupAddress.addr(), groupAddress.length());
mr.ipv6mr_interface = interface.index();
mr.ipv6mr_interface = interfc.index();
impl()->setRawOption(IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(mr));
#endif
}
@@ -243,13 +243,13 @@ void MulticastSocket::leaveGroup(const IPAddress& groupAddress)
}
void MulticastSocket::leaveGroup(const IPAddress& groupAddress, const NetworkInterface& interface)
void MulticastSocket::leaveGroup(const IPAddress& groupAddress, const NetworkInterface& interfc)
{
if (groupAddress.af() == AF_INET)
{
struct ip_mreq mr;
std::memcpy(&mr.imr_multiaddr, groupAddress.addr(), groupAddress.length());
std::memcpy(&mr.imr_interface, interface.address().addr(), interface.address().length());
std::memcpy(&mr.imr_interface, interfc.address().addr(), interfc.address().length());
impl()->setRawOption(IPPROTO_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr));
}
else
@@ -257,7 +257,7 @@ void MulticastSocket::leaveGroup(const IPAddress& groupAddress, const NetworkInt
#if defined(POCO_HAVE_IPv6)
struct ipv6_mreq mr;
std::memcpy(&mr.ipv6mr_multiaddr, groupAddress.addr(), groupAddress.length());
mr.ipv6mr_interface = interface.index();
mr.ipv6mr_interface = interfc.index();
impl()->setRawOption(IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mr, sizeof(mr));
#endif
}

View File

@@ -1,7 +1,7 @@
//
// MultipartReader.cpp
//
// $Id: //poco/Main/Net/src/MultipartReader.cpp#13 $
// $Id: //poco/1.4/Net/src/MultipartReader.cpp#2 $
//
// Library: Net
// Package: Messages
@@ -37,7 +37,7 @@
#include "Poco/Net/MultipartReader.h"
#include "Poco/Net/MessageHeader.h"
#include "Poco/Net/NetException.h"
#include <cctype>
#include "Poco/Ascii.h"
using Poco::BufferedStreamBuf;
@@ -72,58 +72,60 @@ int MultipartStreamBuf::readFromDevice(char* buffer, std::streamsize length)
poco_assert_dbg (length >= _boundary.length() + 6);
static const int eof = std::char_traits<char>::eof();
std::streambuf& buf = *_istr.rdbuf();
int n = 0;
int ch = _istr.get();
int ch = buf.sbumpc();
if (ch == eof) return -1;
*buffer++ = (char) ch; ++n;
if (ch == '\n' || (ch == '\r' && _istr.peek() == '\n'))
if (ch == '\n' || (ch == '\r' && buf.sgetc() == '\n'))
{
if (ch == '\r')
{
ch = _istr.get(); // '\n'
ch = buf.sbumpc(); // '\n'
*buffer++ = (char) ch; ++n;
}
ch = _istr.peek();
ch = buf.sgetc();
if (ch == '\r' || ch == '\n') return n;
*buffer++ = (char) _istr.get(); ++n;
if (ch == '-' && _istr.peek() == '-')
*buffer++ = (char) buf.sbumpc(); ++n;
if (ch == '-' && buf.sgetc() == '-')
{
ch = _istr.get(); // '-'
ch = buf.sbumpc(); // '-'
*buffer++ = (char) ch; ++n;
std::string::const_iterator it = _boundary.begin();
std::string::const_iterator end = _boundary.end();
ch = _istr.get();
ch = buf.sbumpc();
*buffer++ = (char) ch; ++n;
while (it != end && ch == *it)
{
++it;
ch = _istr.get();
ch = buf.sbumpc();
*buffer++ = (char) ch; ++n;
}
if (it == end)
{
if (ch == '\n' || (ch == '\r' && _istr.peek() == '\n'))
if (ch == '\n' || (ch == '\r' && buf.sgetc() == '\n'))
{
if (ch == '\r')
{
ch = _istr.get(); // '\n'
ch = buf.sbumpc(); // '\n'
}
return 0;
}
else if (ch == '-' && _istr.peek() == '-')
else if (ch == '-' && buf.sgetc() == '-')
{
ch = _istr.get(); // '-'
ch = buf.sbumpc(); // '-'
_lastPart = true;
return 0;
}
}
}
}
ch = _istr.peek();
ch = buf.sgetc();
while (ch != eof && ch != '\r' && ch != '\n' && n < length)
{
*buffer++ = (char) _istr.get(); ++n;
ch = _istr.peek();
*buffer++ = (char) buf.sbumpc(); ++n;
ch = buf.sgetc();
}
return n;
}
@@ -268,7 +270,7 @@ void MultipartReader::guessBoundary()
{
static const int eof = std::char_traits<char>::eof();
int ch = _istr.get();
while (std::isspace(ch))
while (Poco::Ascii::isSpace(ch))
ch = _istr.get();
if (ch == '-' && _istr.peek() == '-')
{

View File

@@ -47,6 +47,7 @@ namespace Net {
POCO_IMPLEMENT_EXCEPTION(NetException, IOException, "Net Exception")
POCO_IMPLEMENT_EXCEPTION(InvalidAddressException, NetException, "Invalid address")
POCO_IMPLEMENT_EXCEPTION(InvalidSocketException, NetException, "Invalid socket")
POCO_IMPLEMENT_EXCEPTION(ServiceNotFoundException, NetException, "Service not found")
POCO_IMPLEMENT_EXCEPTION(ConnectionAbortedException, NetException, "Software caused connection abort")
POCO_IMPLEMENT_EXCEPTION(ConnectionResetException, NetException, "Connection reset by peer")

View File

@@ -1,7 +1,7 @@
//
// NetworkInterface.cpp
//
// $Id: //poco/Main/Net/src/NetworkInterface.cpp#24 $
// $Id: //poco/1.4/Net/src/NetworkInterface.cpp#3 $
//
// Library: Net
// Package: Sockets
@@ -12,7 +12,7 @@
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// this license (the "Software") to use, reproduce, display, distribute ,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
@@ -97,7 +97,7 @@ NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, const std::s
_address(address),
_index(index)
{
#ifndef _WIN32
#if !defined(_WIN32) && !defined(POCO_VXWORKS)
if (index == -1) // IPv4
{
struct ifreq ifr;

View File

@@ -42,8 +42,8 @@
#include "Poco/StreamCopier.h"
#include "Poco/NumberFormatter.h"
#include "Poco/UnbufferedStreamBuf.h"
#include "Poco/Ascii.h"
#include <istream>
#include <cctype>
using Poco::NumberFormatter;
@@ -156,7 +156,7 @@ void POP3ClientSession::login(const std::string& username, const std::string& pa
{
std::string response;
_socket.receiveMessage(response);
if (!isPositive(response)) throw SMTPException("The POP3 service is unavailable", response);
if (!isPositive(response)) throw POP3Exception("The POP3 service is unavailable", response);
sendCommand("USER", username, response);
if (!isPositive(response)) throw POP3Exception("Login rejected for user", response);
sendCommand("PASS", password, response);
@@ -184,9 +184,9 @@ int POP3ClientSession::messageCount()
std::string::const_iterator it = response.begin();
std::string::const_iterator end = response.end();
int count = 0;
while (it != end && !std::isspace(*it)) ++it;
while (it != end && std::isspace(*it)) ++it;
while (it != end && std::isdigit(*it)) count = count*10 + *it++ - '0';
while (it != end && !Poco::Ascii::isSpace(*it)) ++it;
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && Poco::Ascii::isDigit(*it)) count = count*10 + *it++ - '0';
return count;
}
@@ -203,9 +203,9 @@ void POP3ClientSession::listMessages(MessageInfoVec& messages)
MessageInfo info = {0, 0};
std::string::const_iterator it = response.begin();
std::string::const_iterator end = response.end();
while (it != end && std::isdigit(*it)) info.id = info.id*10 + *it++ - '0';
while (it != end && std::isspace(*it)) ++it;
while (it != end && std::isdigit(*it)) info.size = info.size*10 + *it++ - '0';
while (it != end && Poco::Ascii::isDigit(*it)) info.id = info.id*10 + *it++ - '0';
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && Poco::Ascii::isDigit(*it)) info.size = info.size*10 + *it++ - '0';
messages.push_back(info);
_socket.receiveMessage(response);
}

View File

@@ -58,10 +58,15 @@ PartSource::~PartSource()
}
namespace
{
static const std::string EMPTY;
}
const std::string& PartSource::filename()
{
static const std::string empty;
return empty;
return EMPTY;
}

View File

@@ -1,7 +1,7 @@
//
// QuotedPrintableDecoder.cpp
//
// $Id: //poco/svn/Net/src/QuotedPrintableDecoder.cpp#2 $
// $Id: //poco/1.4/Net/src/QuotedPrintableDecoder.cpp#2 $
//
// Library: Net
// Package: Messages
@@ -37,7 +37,7 @@
#include "Poco/Net/QuotedPrintableDecoder.h"
#include "Poco/NumberParser.h"
#include "Poco/Exception.h"
#include <cctype>
#include "Poco/Ascii.h"
using Poco::UnbufferedStreamBuf;
@@ -50,7 +50,7 @@ namespace Net {
QuotedPrintableDecoderBuf::QuotedPrintableDecoderBuf(std::istream& istr):
_istr(istr)
_buf(*istr.rdbuf())
{
}
@@ -62,20 +62,20 @@ QuotedPrintableDecoderBuf::~QuotedPrintableDecoderBuf()
int QuotedPrintableDecoderBuf::readFromDevice()
{
int ch = _istr.get();
int ch = _buf.sbumpc();
while (ch == '=')
{
ch = _istr.get();
ch = _buf.sbumpc();
if (ch == '\r')
{
ch = _istr.get(); // read \n
ch = _buf.sbumpc(); // read \n
}
else if (std::isxdigit(ch))
else if (Poco::Ascii::isHexDigit(ch))
{
std::string hex;
hex += (char) ch;
ch = _istr.get();
if (std::isxdigit(ch))
ch = _buf.sbumpc();
if (Poco::Ascii::isHexDigit(ch))
{
hex += (char) ch;
return NumberParser::parseHex(hex);
@@ -86,7 +86,7 @@ int QuotedPrintableDecoderBuf::readFromDevice()
{
throw DataFormatException("Invalid occurrence of '=' in quoted-printable encoded stream");
}
ch = _istr.get();
ch = _buf.sbumpc();
}
return ch;
}

View File

@@ -1,355 +1,355 @@
//
// RemoteSyslogChannel.cpp
//
// $Id: //poco/Main/Net/src/RemoteSyslogChannel.cpp#4 $
//
// Library: Net
// Package: Logging
// Module: RemoteSyslogChannel
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Net/RemoteSyslogChannel.h"
#include "Poco/Message.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/DNS.h"
#include "Poco/LoggingFactory.h"
#include "Poco/Instantiator.h"
#include "Poco/String.h"
namespace Poco {
namespace Net {
const std::string RemoteSyslogChannel::BSD_TIMEFORMAT("%b %f %H:%M:%S");
const std::string RemoteSyslogChannel::SYSLOG_TIMEFORMAT("%Y-%m-%dT%H:%M:%S.%i%z");
const std::string RemoteSyslogChannel::PROP_NAME("name");
const std::string RemoteSyslogChannel::PROP_FACILITY("facility");
const std::string RemoteSyslogChannel::PROP_FORMAT("format");
const std::string RemoteSyslogChannel::PROP_LOGHOST("loghost");
const std::string RemoteSyslogChannel::PROP_HOST("host");
RemoteSyslogChannel::RemoteSyslogChannel():
_logHost("localhost"),
_name("-"),
_facility(SYSLOG_USER),
_bsdFormat(false),
_open(false)
{
}
RemoteSyslogChannel::RemoteSyslogChannel(const std::string& address, const std::string& name, int facility, bool bsdFormat):
_logHost(address),
_name(name),
_facility(facility),
_bsdFormat(bsdFormat),
_open(false)
{
if (_name.empty()) _name = "-";
}
RemoteSyslogChannel::~RemoteSyslogChannel()
{
close();
}
void RemoteSyslogChannel::open()
{
if (_open) return;
SocketAddress sa;
if (_logHost.find(':') != std::string::npos)
sa = SocketAddress(_logHost);
else
sa = SocketAddress(_logHost, SYSLOG_PORT);
_socket.connect(sa);
if (_host.empty())
{
try
{
_host = DNS::thisHost().name();
}
catch (Poco::Exception&)
{
_host = _socket.address().host().toString();
}
}
}
void RemoteSyslogChannel::close()
{
if (_open)
{
_socket.close();
_open = false;
}
}
void RemoteSyslogChannel::log(const Message& msg)
{
if (!_open) open();
std::string m;
m.reserve(1024);
m += '<';
Poco::NumberFormatter::append(m, getPrio(msg) + _facility);
m += '>';
if (_bsdFormat)
{
Poco::DateTimeFormatter::append(m, msg.getTime(), BSD_TIMEFORMAT);
m += ' ';
m += _host;
}
else
{
m += "1 "; // version
Poco::DateTimeFormatter::append(m, msg.getTime(), SYSLOG_TIMEFORMAT);
m += ' ';
m += _host;
m += ' ';
m += _name;
m += ' ';
Poco::NumberFormatter::append(m, msg.getPid());
m += ' ';
m += msg.getSource();
}
m += ' ';
m += msg.getText();
_socket.sendBytes(m.data(), (int) m.size());
}
void RemoteSyslogChannel::setProperty(const std::string& name, const std::string& value)
{
if (name == PROP_NAME)
{
_name = value;
if (_name.empty()) _name = "-";
}
else if (name == PROP_FACILITY)
{
std::string facility;
if (Poco::icompare(value, 4, "LOG_") == 0)
facility = Poco::toUpper(value.substr(4));
else if (Poco::icompare(value, 4, "SYSLOG_") == 0)
facility = Poco::toUpper(value.substr(7));
else
facility = Poco::toUpper(value);
if (facility == "KERN")
_facility = SYSLOG_KERN;
else if (facility == "USER")
_facility = SYSLOG_USER;
else if (facility == "MAIL")
_facility = SYSLOG_MAIL;
else if (facility == "DAEMON")
_facility = SYSLOG_DAEMON;
else if (facility == "AUTH")
_facility = SYSLOG_AUTH;
else if (facility == "AUTHPRIV")
_facility = SYSLOG_AUTHPRIV;
else if (facility == "SYSLOG")
_facility = SYSLOG_SYSLOG;
else if (facility == "LPR")
_facility = SYSLOG_LPR;
else if (facility == "NEWS")
_facility = SYSLOG_NEWS;
else if (facility == "UUCP")
_facility = SYSLOG_UUCP;
else if (facility == "CRON")
_facility = SYSLOG_CRON;
else if (facility == "FTP")
_facility = SYSLOG_FTP;
else if (facility == "NTP")
_facility = SYSLOG_NTP;
else if (facility == "LOGAUDIT")
_facility = SYSLOG_LOGAUDIT;
else if (facility == "LOGALERT")
_facility = SYSLOG_LOGALERT;
else if (facility == "CLOCK")
_facility = SYSLOG_CLOCK;
else if (facility == "LOCAL0")
_facility = SYSLOG_LOCAL0;
else if (facility == "LOCAL1")
_facility = SYSLOG_LOCAL1;
else if (facility == "LOCAL2")
_facility = SYSLOG_LOCAL2;
else if (facility == "LOCAL3")
_facility = SYSLOG_LOCAL3;
else if (facility == "LOCAL4")
_facility = SYSLOG_LOCAL4;
else if (facility == "LOCAL5")
_facility = SYSLOG_LOCAL5;
else if (facility == "LOCAL6")
_facility = SYSLOG_LOCAL6;
else if (facility == "LOCAL7")
_facility = SYSLOG_LOCAL7;
}
else if (name == PROP_LOGHOST)
{
_logHost = value;
}
else if (name == PROP_HOST)
{
_host = value;
}
else if (name == PROP_FORMAT)
{
_bsdFormat = (value == "bsd");
}
else
{
Channel::setProperty(name, value);
}
}
std::string RemoteSyslogChannel::getProperty(const std::string& name) const
{
if (name == PROP_NAME)
{
if (_name != "-")
return _name;
else
return "";
}
else if (name == PROP_FACILITY)
{
if (_facility == SYSLOG_KERN)
return "KERN";
else if (_facility == SYSLOG_USER)
return "USER";
else if (_facility == SYSLOG_MAIL)
return "MAIL";
else if (_facility == SYSLOG_DAEMON)
return "DAEMON";
else if (_facility == SYSLOG_AUTH)
return "AUTH";
else if (_facility == SYSLOG_AUTHPRIV)
return "AUTHPRIV";
else if (_facility == SYSLOG_SYSLOG)
return "SYSLOG";
else if (_facility == SYSLOG_LPR)
return "LPR";
else if (_facility == SYSLOG_NEWS)
return "NEWS";
else if (_facility == SYSLOG_UUCP)
return "UUCP";
else if (_facility == SYSLOG_CRON)
return "CRON";
else if (_facility == SYSLOG_FTP)
return "FTP";
else if (_facility == SYSLOG_NTP)
return "NTP";
else if (_facility == SYSLOG_LOGAUDIT)
return "LOGAUDIT";
else if (_facility == SYSLOG_LOGALERT)
return "LOGALERT";
else if (_facility == SYSLOG_CLOCK)
return "CLOCK";
else if (_facility == SYSLOG_LOCAL0)
return "LOCAL0";
else if (_facility == SYSLOG_LOCAL1)
return "LOCAL1";
else if (_facility == SYSLOG_LOCAL2)
return "LOCAL2";
else if (_facility == SYSLOG_LOCAL3)
return "LOCAL3";
else if (_facility == SYSLOG_LOCAL4)
return "LOCAL4";
else if (_facility == SYSLOG_LOCAL5)
return "LOCAL5";
else if (_facility == SYSLOG_LOCAL6)
return "LOCAL6";
else if (_facility == SYSLOG_LOCAL7)
return "LOCAL7";
else
return "";
}
else if (name == PROP_LOGHOST)
{
return _logHost;
}
else if (name == PROP_HOST)
{
return _host;
}
else if (name == PROP_FORMAT)
{
return _bsdFormat ? "bsd" : "new";
}
else
{
return Channel::getProperty(name);
}
}
int RemoteSyslogChannel::getPrio(const Message& msg)
{
switch (msg.getPriority())
{
case Message::PRIO_TRACE:
case Message::PRIO_DEBUG:
return SYSLOG_DEBUG;
case Message::PRIO_INFORMATION:
return SYSLOG_INFORMATIONAL;
case Message::PRIO_NOTICE:
return SYSLOG_NOTICE;
case Message::PRIO_WARNING:
return SYSLOG_WARNING;
case Message::PRIO_ERROR:
return SYSLOG_ERROR;
case Message::PRIO_CRITICAL:
return SYSLOG_CRITICAL;
case Message::PRIO_FATAL:
return SYSLOG_ALERT;
default:
return 0;
}
}
void RemoteSyslogChannel::registerChannel()
{
Poco::LoggingFactory::defaultFactory().registerChannelClass("RemoteSyslogChannel", new Poco::Instantiator<RemoteSyslogChannel, Poco::Channel>);
}
} } // namespace Poco::Net
//
// RemoteSyslogChannel.cpp
//
// $Id: //poco/1.4/Net/src/RemoteSyslogChannel.cpp#2 $
//
// Library: Net
// Package: Logging
// Module: RemoteSyslogChannel
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Net/RemoteSyslogChannel.h"
#include "Poco/Message.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/DNS.h"
#include "Poco/LoggingFactory.h"
#include "Poco/Instantiator.h"
#include "Poco/String.h"
namespace Poco {
namespace Net {
const std::string RemoteSyslogChannel::BSD_TIMEFORMAT("%b %f %H:%M:%S");
const std::string RemoteSyslogChannel::SYSLOG_TIMEFORMAT("%Y-%m-%dT%H:%M:%S.%i%z");
const std::string RemoteSyslogChannel::PROP_NAME("name");
const std::string RemoteSyslogChannel::PROP_FACILITY("facility");
const std::string RemoteSyslogChannel::PROP_FORMAT("format");
const std::string RemoteSyslogChannel::PROP_LOGHOST("loghost");
const std::string RemoteSyslogChannel::PROP_HOST("host");
RemoteSyslogChannel::RemoteSyslogChannel():
_logHost("localhost"),
_name("-"),
_facility(SYSLOG_USER),
_bsdFormat(false),
_open(false)
{
}
RemoteSyslogChannel::RemoteSyslogChannel(const std::string& address, const std::string& name, int facility, bool bsdFormat):
_logHost(address),
_name(name),
_facility(facility),
_bsdFormat(bsdFormat),
_open(false)
{
if (_name.empty()) _name = "-";
}
RemoteSyslogChannel::~RemoteSyslogChannel()
{
close();
}
void RemoteSyslogChannel::open()
{
if (_open) return;
if (_logHost.find(':') != std::string::npos)
_socketAddress = SocketAddress(_logHost);
else
_socketAddress = SocketAddress(_logHost, SYSLOG_PORT);
if (_host.empty())
{
try
{
_host = DNS::thisHost().name();
}
catch (Poco::Exception&)
{
_host = _socket.address().host().toString();
}
}
}
void RemoteSyslogChannel::close()
{
if (_open)
{
_socket.close();
_open = false;
}
}
void RemoteSyslogChannel::log(const Message& msg)
{
Poco::FastMutex::ScopedLock lock(_mutex);
if (!_open) open();
std::string m;
m.reserve(1024);
m += '<';
Poco::NumberFormatter::append(m, getPrio(msg) + _facility);
m += '>';
if (_bsdFormat)
{
Poco::DateTimeFormatter::append(m, msg.getTime(), BSD_TIMEFORMAT);
m += ' ';
m += _host;
}
else
{
m += "1 "; // version
Poco::DateTimeFormatter::append(m, msg.getTime(), SYSLOG_TIMEFORMAT);
m += ' ';
m += _host;
m += ' ';
m += _name;
m += ' ';
Poco::NumberFormatter::append(m, msg.getPid());
m += ' ';
m += msg.getSource();
}
m += ' ';
m += msg.getText();
_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)
{
_name = value;
if (_name.empty()) _name = "-";
}
else if (name == PROP_FACILITY)
{
std::string facility;
if (Poco::icompare(value, 4, "LOG_") == 0)
facility = Poco::toUpper(value.substr(4));
else if (Poco::icompare(value, 4, "SYSLOG_") == 0)
facility = Poco::toUpper(value.substr(7));
else
facility = Poco::toUpper(value);
if (facility == "KERN")
_facility = SYSLOG_KERN;
else if (facility == "USER")
_facility = SYSLOG_USER;
else if (facility == "MAIL")
_facility = SYSLOG_MAIL;
else if (facility == "DAEMON")
_facility = SYSLOG_DAEMON;
else if (facility == "AUTH")
_facility = SYSLOG_AUTH;
else if (facility == "AUTHPRIV")
_facility = SYSLOG_AUTHPRIV;
else if (facility == "SYSLOG")
_facility = SYSLOG_SYSLOG;
else if (facility == "LPR")
_facility = SYSLOG_LPR;
else if (facility == "NEWS")
_facility = SYSLOG_NEWS;
else if (facility == "UUCP")
_facility = SYSLOG_UUCP;
else if (facility == "CRON")
_facility = SYSLOG_CRON;
else if (facility == "FTP")
_facility = SYSLOG_FTP;
else if (facility == "NTP")
_facility = SYSLOG_NTP;
else if (facility == "LOGAUDIT")
_facility = SYSLOG_LOGAUDIT;
else if (facility == "LOGALERT")
_facility = SYSLOG_LOGALERT;
else if (facility == "CLOCK")
_facility = SYSLOG_CLOCK;
else if (facility == "LOCAL0")
_facility = SYSLOG_LOCAL0;
else if (facility == "LOCAL1")
_facility = SYSLOG_LOCAL1;
else if (facility == "LOCAL2")
_facility = SYSLOG_LOCAL2;
else if (facility == "LOCAL3")
_facility = SYSLOG_LOCAL3;
else if (facility == "LOCAL4")
_facility = SYSLOG_LOCAL4;
else if (facility == "LOCAL5")
_facility = SYSLOG_LOCAL5;
else if (facility == "LOCAL6")
_facility = SYSLOG_LOCAL6;
else if (facility == "LOCAL7")
_facility = SYSLOG_LOCAL7;
}
else if (name == PROP_LOGHOST)
{
_logHost = value;
}
else if (name == PROP_HOST)
{
_host = value;
}
else if (name == PROP_FORMAT)
{
_bsdFormat = (value == "bsd" || value == "rfc3164");
}
else
{
Channel::setProperty(name, value);
}
}
std::string RemoteSyslogChannel::getProperty(const std::string& name) const
{
if (name == PROP_NAME)
{
if (_name != "-")
return _name;
else
return "";
}
else if (name == PROP_FACILITY)
{
if (_facility == SYSLOG_KERN)
return "KERN";
else if (_facility == SYSLOG_USER)
return "USER";
else if (_facility == SYSLOG_MAIL)
return "MAIL";
else if (_facility == SYSLOG_DAEMON)
return "DAEMON";
else if (_facility == SYSLOG_AUTH)
return "AUTH";
else if (_facility == SYSLOG_AUTHPRIV)
return "AUTHPRIV";
else if (_facility == SYSLOG_SYSLOG)
return "SYSLOG";
else if (_facility == SYSLOG_LPR)
return "LPR";
else if (_facility == SYSLOG_NEWS)
return "NEWS";
else if (_facility == SYSLOG_UUCP)
return "UUCP";
else if (_facility == SYSLOG_CRON)
return "CRON";
else if (_facility == SYSLOG_FTP)
return "FTP";
else if (_facility == SYSLOG_NTP)
return "NTP";
else if (_facility == SYSLOG_LOGAUDIT)
return "LOGAUDIT";
else if (_facility == SYSLOG_LOGALERT)
return "LOGALERT";
else if (_facility == SYSLOG_CLOCK)
return "CLOCK";
else if (_facility == SYSLOG_LOCAL0)
return "LOCAL0";
else if (_facility == SYSLOG_LOCAL1)
return "LOCAL1";
else if (_facility == SYSLOG_LOCAL2)
return "LOCAL2";
else if (_facility == SYSLOG_LOCAL3)
return "LOCAL3";
else if (_facility == SYSLOG_LOCAL4)
return "LOCAL4";
else if (_facility == SYSLOG_LOCAL5)
return "LOCAL5";
else if (_facility == SYSLOG_LOCAL6)
return "LOCAL6";
else if (_facility == SYSLOG_LOCAL7)
return "LOCAL7";
else
return "";
}
else if (name == PROP_LOGHOST)
{
return _logHost;
}
else if (name == PROP_HOST)
{
return _host;
}
else if (name == PROP_FORMAT)
{
return _bsdFormat ? "rfc3164" : "rfc5424";
}
else
{
return Channel::getProperty(name);
}
}
int RemoteSyslogChannel::getPrio(const Message& msg)
{
switch (msg.getPriority())
{
case Message::PRIO_TRACE:
case Message::PRIO_DEBUG:
return SYSLOG_DEBUG;
case Message::PRIO_INFORMATION:
return SYSLOG_INFORMATIONAL;
case Message::PRIO_NOTICE:
return SYSLOG_NOTICE;
case Message::PRIO_WARNING:
return SYSLOG_WARNING;
case Message::PRIO_ERROR:
return SYSLOG_ERROR;
case Message::PRIO_CRITICAL:
return SYSLOG_CRITICAL;
case Message::PRIO_FATAL:
return SYSLOG_ALERT;
default:
return 0;
}
}
void RemoteSyslogChannel::registerChannel()
{
Poco::LoggingFactory::defaultFactory().registerChannelClass("RemoteSyslogChannel", new Poco::Instantiator<RemoteSyslogChannel, Poco::Channel>);
}
} } // namespace Poco::Net

View File

@@ -37,6 +37,7 @@
#include "Poco/Net/RemoteSyslogListener.h"
#include "Poco/Net/RemoteSyslogChannel.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Runnable.h"
#include "Poco/Notification.h"
#include "Poco/AutoPtr.h"
@@ -46,7 +47,7 @@
#include "Poco/Message.h"
#include "Poco/LoggingFactory.h"
#include "Poco/Buffer.h"
#include <cctype>
#include "Poco/Ascii.h"
#include <cstddef>
@@ -62,22 +63,35 @@ namespace Net {
class MessageNotification: public Poco::Notification
{
public:
MessageNotification(const std::string& msg)
MessageNotification(const char* buffer, std::size_t length, const Poco::Net::SocketAddress& sourceAddress):
_message(buffer, length),
_sourceAddress(sourceAddress)
{
_msg = msg;
}
MessageNotification(const std::string& message, const Poco::Net::SocketAddress& sourceAddress):
_message(message),
_sourceAddress(sourceAddress)
{
}
~MessageNotification()
{
}
const std::string& message() const
{
return _msg;
return _message;
}
const Poco::Net::SocketAddress& sourceAddress() const
{
return _sourceAddress;
}
private:
std::string _msg;
std::string _message;
Poco::Net::SocketAddress _sourceAddress;
};
@@ -111,7 +125,7 @@ private:
RemoteUDPListener::RemoteUDPListener(Poco::NotificationQueue& queue, Poco::UInt16 port):
_queue(queue),
_socket(Poco::Net::SocketAddress(Poco::Net::IPAddress(), port)),
_stopped(true)
_stopped(false)
{
}
@@ -123,10 +137,7 @@ RemoteUDPListener::~RemoteUDPListener()
void RemoteUDPListener::run()
{
poco_assert (_stopped);
Poco::Buffer<char> buffer(BUFFER_SIZE);
_stopped = false;
Poco::Timespan waitTime(WAITTIME_MILLISEC* 1000);
while (!_stopped)
{
@@ -134,10 +145,11 @@ void RemoteUDPListener::run()
{
if (_socket.poll(waitTime, Socket::SELECT_READ))
{
int byteCnt = _socket.receiveBytes(buffer.begin(), BUFFER_SIZE);
if (byteCnt > 0)
Poco::Net::SocketAddress sourceAddress;
int n = _socket.receiveFrom(buffer.begin(), BUFFER_SIZE, sourceAddress);
if (n > 0)
{
_queue.enqueueNotification(new MessageNotification(std::string(buffer.begin(), byteCnt)));
_queue.enqueueNotification(new MessageNotification(buffer.begin(), n, sourceAddress));
}
}
}
@@ -173,18 +185,18 @@ public:
SyslogParser(Poco::NotificationQueue& queue, RemoteSyslogListener* pListener);
~SyslogParser();
void parse(const std::string& line, Poco::Message& message);
void run();
void safeStop();
static Poco::Message::Priority convert(RemoteSyslogChannel::Severity severity);
private:
void parse(const std::string& msg);
void parsePrio(const std::string& msg, std::size_t& pos, RemoteSyslogChannel::Severity& severity, RemoteSyslogChannel::Facility& fac);
void parseNew(const std::string& msg, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos);
void parseBSD(const std::string& msg, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos);
void parsePrio(const std::string& line, std::size_t& pos, RemoteSyslogChannel::Severity& severity, RemoteSyslogChannel::Facility& fac);
void parseNew(const std::string& line, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos, Poco::Message& message);
void parseBSD(const std::string& line, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos, Poco::Message& message);
static std::string parseUntilSpace(const std::string& msg, std::size_t& pos);
static std::string parseUntilSpace(const std::string& line, std::size_t& pos);
/// Parses until it encounters the next space char, returns the string from pos, excluding space
/// pos will point past the space char
@@ -200,7 +212,7 @@ const std::string SyslogParser::NILVALUE("-");
SyslogParser::SyslogParser(Poco::NotificationQueue& queue, RemoteSyslogListener* pListener):
_queue(queue),
_stopped(true),
_stopped(false),
_pListener(pListener)
{
poco_check_ptr (_pListener);
@@ -214,8 +226,6 @@ SyslogParser::~SyslogParser()
void SyslogParser::run()
{
poco_assert (_stopped);
_stopped = false;
while (!_stopped)
{
try
@@ -224,7 +234,10 @@ void SyslogParser::run()
if (pNf)
{
Poco::AutoPtr<MessageNotification> pMsgNf = pNf.cast<MessageNotification>();
parse(pMsgNf->message());
Poco::Message message;
parse(pMsgNf->message(), message);
message["addr"] =pMsgNf->sourceAddress().host().toString();
_pListener->log(message);
}
}
catch (Poco::Exception&)
@@ -244,43 +257,43 @@ void SyslogParser::safeStop()
}
void SyslogParser::parse(const std::string& msg)
void SyslogParser::parse(const std::string& line, Poco::Message& message)
{
// <int> -> int: lower 3 bits severity, upper bits: facility
std::size_t pos = 0;
RemoteSyslogChannel::Severity severity;
RemoteSyslogChannel::Facility fac;
parsePrio(msg, pos, severity, fac);
parsePrio(line, pos, severity, fac);
// the next field decide if we parse an old BSD message or a new syslog message
// BSD: expects a month value in string form: Jan, Feb...
// SYSLOG expects a version number: 1
if (std::isdigit(msg[pos]))
if (Poco::Ascii::isDigit(line[pos]))
{
parseNew(msg, severity, fac, pos);
parseNew(line, severity, fac, pos, message);
}
else
{
parseBSD(msg, severity, fac, pos);
parseBSD(line, severity, fac, pos, message);
}
poco_assert (pos == msg.size());
poco_assert (pos == line.size());
}
void SyslogParser::parsePrio(const std::string& msg, std::size_t& pos, RemoteSyslogChannel::Severity& severity, RemoteSyslogChannel::Facility& fac)
void SyslogParser::parsePrio(const std::string& line, std::size_t& pos, RemoteSyslogChannel::Severity& severity, RemoteSyslogChannel::Facility& fac)
{
poco_assert (pos < msg.size());
poco_assert (msg[pos] == '<');
poco_assert (pos < line.size());
poco_assert (line[pos] == '<');
++pos;
std::size_t start = pos;
while (pos < msg.size() && std::isdigit(msg[pos]))
while (pos < line.size() && Poco::Ascii::isDigit(line[pos]))
++pos;
poco_assert (msg[pos] == '>');
poco_assert (line[pos] == '>');
poco_assert (pos - start > 0);
std::string valStr = msg.substr(start, pos - start);
std::string valStr = line.substr(start, pos - start);
++pos; // skip the >
int val = Poco::NumberParser::parse(valStr);
@@ -293,23 +306,23 @@ void SyslogParser::parsePrio(const std::string& msg, std::size_t& pos, RemoteSys
}
void SyslogParser::parseNew(const std::string& msg, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos)
void SyslogParser::parseNew(const std::string& line, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos, Poco::Message& message)
{
Poco::Message::Priority prio = convert(severity);
// rest of the unparsed header is:
// VERSION SP TIMESTAMP SP HOSTNAME SP APP-NAME SP PROCID SP MSGID
std::string versionStr(parseUntilSpace(msg, pos));
std::string timeStr(parseUntilSpace(msg, pos)); // can be the nilvalue!
std::string hostName(parseUntilSpace(msg, pos));
std::string appName(parseUntilSpace(msg, pos));
std::string procId(parseUntilSpace(msg, pos));
std::string msgId(parseUntilSpace(msg, pos));
std::string message(msg.substr(pos));
pos = msg.size();
std::string versionStr(parseUntilSpace(line, pos));
std::string timeStr(parseUntilSpace(line, pos)); // can be the nilvalue!
std::string hostName(parseUntilSpace(line, pos));
std::string appName(parseUntilSpace(line, pos));
std::string procId(parseUntilSpace(line, pos));
std::string msgId(parseUntilSpace(line, pos));
std::string messageText(line.substr(pos));
pos = line.size();
Poco::DateTime date;
int tzd = 0;
bool hasDate = Poco::DateTimeParser::tryParse(RemoteSyslogChannel::SYSLOG_TIMEFORMAT, timeStr, date, tzd);
Poco::Message logEntry(msgId, message, prio);
Poco::Message logEntry(msgId, messageText, prio);
logEntry["host"] = hostName;
logEntry["app"] = appName;
@@ -318,11 +331,11 @@ void SyslogParser::parseNew(const std::string& msg, RemoteSyslogChannel::Severit
int lval(0);
Poco::NumberParser::tryParse(procId, lval);
logEntry.setPid(lval);
_pListener->log(logEntry);
message.swap(logEntry);
}
void SyslogParser::parseBSD(const std::string& msg, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos)
void SyslogParser::parseBSD(const std::string& line, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos, Poco::Message& message)
{
Poco::Message::Priority prio = convert(severity);
// rest of the unparsed header is:
@@ -330,9 +343,9 @@ void SyslogParser::parseBSD(const std::string& msg, RemoteSyslogChannel::Severit
// detect three spaces
int spaceCnt = 0;
std::size_t start = pos;
while (spaceCnt < 3 && pos < msg.size())
while (spaceCnt < 3 && pos < line.size())
{
if (msg[pos] == ' ')
if (line[pos] == ' ')
{
spaceCnt++;
if (spaceCnt == 1)
@@ -342,21 +355,21 @@ void SyslogParser::parseBSD(const std::string& msg, RemoteSyslogChannel::Severit
{
// probably a shortened time value, or the hostname
// assume hostName
Poco::Message logEntry(msg.substr(start, pos-start), msg.substr(pos+1), prio);
_pListener->log(logEntry);
Poco::Message logEntry(line.substr(start, pos-start), line.substr(pos+1), prio);
message.swap(logEntry);
return;
}
}
else if (spaceCnt == 2)
{
// a day value!
if (!(std::isdigit(msg[pos-1]) && (std::isdigit(msg[pos-2]) || std::isspace(msg[pos-2]))))
if (!(Poco::Ascii::isDigit(line[pos-1]) && (Poco::Ascii::isDigit(line[pos-2]) || Poco::Ascii::isSpace(line[pos-2]))))
{
// assume the next field is a hostname
spaceCnt = 3;
}
}
if (pos + 1 < msg.size() && msg[pos+1] == ' ')
if (pos + 1 < line.size() && line[pos+1] == ' ')
{
// we have two spaces when the day value is smaller than 10!
++pos; // skip one
@@ -364,7 +377,7 @@ void SyslogParser::parseBSD(const std::string& msg, RemoteSyslogChannel::Severit
}
++pos;
}
std::string timeStr(msg.substr(start, pos-start-1));
std::string timeStr(line.substr(start, pos-start-1));
int tzd(0);
Poco::DateTime date;
int year = date.year(); // year is not included, use the current one
@@ -379,26 +392,26 @@ void SyslogParser::parseBSD(const std::string& msg, RemoteSyslogChannel::Severit
date = Poco::DateTime(year, m, d, h, min, sec);
}
// next entry is host SP
std::string hostName(parseUntilSpace(msg, pos));
std::string hostName(parseUntilSpace(line, pos));
// TAG: at most 32 alphanumeric chars, ANY non alphannumeric indicates start of message content
// ignore: treat everything as content
std::string message(msg.substr(pos));
pos = msg.size();
Poco::Message logEntry(hostName, message, prio);
std::string messageText(line.substr(pos));
pos = line.size();
Poco::Message logEntry(hostName, messageText, prio);
logEntry.setTime(date.timestamp());
_pListener->log(logEntry);
message.swap(logEntry);
}
std::string SyslogParser::parseUntilSpace(const std::string& msg, std::size_t& pos)
std::string SyslogParser::parseUntilSpace(const std::string& line, std::size_t& pos)
{
std::size_t start = pos;
while (pos < msg.size() && !std::isspace(msg[pos]))
while (pos < line.size() && !Poco::Ascii::isSpace(line[pos]))
++pos;
// skip space
++pos;
return msg.substr(start, pos-start-1);
return line.substr(start, pos-start-1);
}
@@ -433,15 +446,14 @@ Poco::Message::Priority SyslogParser::convert(RemoteSyslogChannel::Severity seve
const std::string RemoteSyslogListener::PROP_PORT("port");
const std::string RemoteSyslogListener::PROP_THREADS("threads");
RemoteSyslogListener::RemoteSyslogListener():
_pListener(0),
_pParser(0),
_listener(),
_parser(),
_queue(),
_port(RemoteSyslogChannel::SYSLOG_PORT)
_port(RemoteSyslogChannel::SYSLOG_PORT),
_threads(1)
{
}
@@ -449,10 +461,17 @@ RemoteSyslogListener::RemoteSyslogListener():
RemoteSyslogListener::RemoteSyslogListener(Poco::UInt16 port):
_pListener(0),
_pParser(0),
_listener(),
_parser(),
_queue(),
_port(port)
_port(port),
_threads(1)
{
}
RemoteSyslogListener::RemoteSyslogListener(Poco::UInt16 port, int threads):
_pListener(0),
_pParser(0),
_port(port),
_threads(threads)
{
}
@@ -462,16 +481,38 @@ RemoteSyslogListener::~RemoteSyslogListener()
}
void RemoteSyslogListener::processMessage(const std::string& messageText)
{
Poco::Message message;
_pParser->parse(messageText, message);
log(message);
}
void RemoteSyslogListener::enqueueMessage(const std::string& messageText, const Poco::Net::SocketAddress& senderAddress)
{
_queue.enqueueNotification(new MessageNotification(messageText, senderAddress));
}
void RemoteSyslogListener::setProperty(const std::string& name, const std::string& value)
{
if (name == PROP_PORT)
{
int val = Poco::NumberParser::parse(value);
if (val > 0 && val < 65536)
if (val >= 0 && val < 65536)
_port = static_cast<Poco::UInt16>(val);
else
throw Poco::InvalidArgumentException("Not a valid port number", value);
}
else if (name == PROP_THREADS)
{
int val = Poco::NumberParser::parse(value);
if (val > 0 && val < 16)
_threads = val;
else
throw Poco::InvalidArgumentException("Invalid number of threads", value);
}
else
{
SplitterChannel::setProperty(name, value);
@@ -483,6 +524,8 @@ std::string RemoteSyslogListener::getProperty(const std::string& name) const
{
if (name == PROP_PORT)
return Poco::NumberFormatter::format(_port);
else if (name == PROP_THREADS)
return Poco::NumberFormatter::format(_threads);
else
return SplitterChannel::getProperty(name);
}
@@ -492,26 +535,37 @@ void RemoteSyslogListener::open()
{
SplitterChannel::open();
_pParser = new SyslogParser(_queue, this);
_pListener = new RemoteUDPListener(_queue, _port);
_parser.start(*_pParser);
_listener.start(*_pListener);
if (_port > 0)
{
_pListener = new RemoteUDPListener(_queue, _port);
}
for (int i = 0; i < _threads; i++)
{
_threadPool.start(*_pParser);
}
if (_pListener)
{
_threadPool.start(*_pListener);
}
}
void RemoteSyslogListener::close()
{
if (_pListener && _pParser)
if (_pListener)
{
_pListener->safeStop();
_pParser->safeStop();
_queue.clear();
_listener.join();
_parser.join();
delete _pListener;
delete _pParser;
_pListener = 0;
_pParser = 0;
}
if (_pParser)
{
_pParser->safeStop();
}
_queue.clear();
_threadPool.joinAll();
delete _pListener;
delete _pParser;
_pListener = 0;
_pParser = 0;
SplitterChannel::close();
}

View File

@@ -45,10 +45,12 @@
#include "Poco/Net/NetworkInterface.h"
#include "Poco/HMACEngine.h"
#include "Poco/MD5Engine.h"
#include "Poco/SHA1Engine.h"
#include "Poco/DigestStream.h"
#include "Poco/StreamCopier.h"
#include "Poco/Base64Encoder.h"
#include "Poco/Base64Decoder.h"
#include "Poco/String.h"
#include <sstream>
#include <fstream>
#include <iostream>
@@ -57,6 +59,7 @@
using Poco::DigestEngine;
using Poco::HMACEngine;
using Poco::MD5Engine;
using Poco::SHA1Engine;
using Poco::DigestOutputStream;
using Poco::StreamCopier;
using Poco::Base64Encoder;
@@ -112,7 +115,7 @@ void SMTPClientSession::login(const std::string& hostname, std::string& response
int status = sendCommand("EHLO", hostname, response);
if (isPermanentNegative(status))
status = sendCommand("HELO", hostname, response);
if (!isPositiveCompletion(status)) throw SMTPException("Login failed", response);
if (!isPositiveCompletion(status)) throw SMTPException("Login failed", response, status);
}
@@ -129,21 +132,34 @@ void SMTPClientSession::login()
}
void SMTPClientSession::loginUsingCRAM_MD5(const std::string& username, const std::string& password)
void SMTPClientSession::loginUsingCRAMMD5(const std::string& username, const std::string& password)
{
HMACEngine<MD5Engine> hmac(password);
loginUsingCRAM(username, "CRAM-MD5", hmac);
}
void SMTPClientSession::loginUsingCRAMSHA1(const std::string& username, const std::string& password)
{
HMACEngine<SHA1Engine> hmac(password);
loginUsingCRAM(username, "CRAM-SHA1", hmac);
}
void SMTPClientSession::loginUsingCRAM(const std::string& username, const std::string& method, Poco::DigestEngine& hmac)
{
int status = 0;
std::string response;
status = sendCommand("AUTH CRAM-MD5", response);
if (!isPositiveIntermediate(status)) throw SMTPException("Cannot authenticate CRAM-MD5", response);
status = sendCommand(std::string("AUTH ") + method, response);
if (!isPositiveIntermediate(status)) throw SMTPException(std::string("Cannot authenticate using ") + method, response, status);
std::string challengeBase64 = response.substr(4);
std::istringstream istr(challengeBase64);
Base64Decoder decoder(istr);
std::string challenge;
decoder >> challenge;
StreamCopier::copyToString(decoder, challenge);
HMACEngine<MD5Engine> hmac(password);
hmac.update(challenge);
const DigestEngine::Digest& digest = hmac.digest();
@@ -157,7 +173,7 @@ void SMTPClientSession::loginUsingCRAM_MD5(const std::string& username, const st
encoder.close();
status = sendCommand(challengeResponseBase64.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException("Login using CRAM-MD5 failed", response);
if (!isPositiveCompletion(status)) throw SMTPException(std::string("Login using ") + method + " failed", response, status);
}
@@ -167,7 +183,7 @@ void SMTPClientSession::loginUsingLogin(const std::string& username, const std::
std::string response;
status = sendCommand("AUTH LOGIN", response);
if (!isPositiveIntermediate(status)) throw SMTPException("Cannot authenticate LOGIN", response);
if (!isPositiveIntermediate(status)) throw SMTPException("Cannot authenticate using LOGIN", response, status);
std::ostringstream usernameBase64;
Base64Encoder usernameEncoder(usernameBase64);
@@ -189,39 +205,72 @@ void SMTPClientSession::loginUsingLogin(const std::string& username, const std::
//C: user_password
//S: login:
//C: user_login
if (response == "334 VXNlcm5hbWU6") // username first (md5("Username:"))
std::string decodedResponse;
std::istringstream responseStream(response.substr(4));
Base64Decoder responseDecoder(responseStream);
StreamCopier::copyToString(responseDecoder, decodedResponse);
if (Poco::icompare(decodedResponse, 0, 8, "username") == 0) // username first (md5("Username:"))
{
status = sendCommand(usernameBase64.str(), response);
if (!isPositiveIntermediate(status)) throw SMTPException("Login using LOGIN user name failed", response);
if (!isPositiveIntermediate(status)) throw SMTPException("Login using LOGIN username failed", response, status);
status = sendCommand(passwordBase64.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException("Login using LOGIN password failed", response);
if (!isPositiveCompletion(status)) throw SMTPException("Login using LOGIN password failed", response, status);
}
else if (response == "334 UGFzc3dvcmQ6") // password first (md5("Password:"))
else if (Poco::icompare(decodedResponse, 0, 8, "password") == 0) // password first (md5("Password:"))
{
status = sendCommand(passwordBase64.str(), response);
if (!isPositiveIntermediate(status)) throw SMTPException("Login using LOGIN password failed", response);
if (!isPositiveIntermediate(status)) throw SMTPException("Login using LOGIN password failed", response, status);
status = sendCommand(usernameBase64.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException("Login using LOGIN user name failed", response);
if (!isPositiveCompletion(status)) throw SMTPException("Login using LOGIN username failed", response, status);
}
}
void SMTPClientSession::loginUsingPlain(const std::string& username, const std::string& password)
{
int status = 0;
std::string response;
std::ostringstream credentialsBase64;
Base64Encoder credentialsEncoder(credentialsBase64);
credentialsEncoder << username << '\0' << password;
credentialsEncoder.close();
status = sendCommand("AUTH PLAIN", credentialsBase64.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException("Login using PLAIN failed", response, status);
}
void SMTPClientSession::login(LoginMethod loginMethod, const std::string& username, const std::string& password)
{
login(Environment::nodeName(), loginMethod, username, password);
}
void SMTPClientSession::login(const std::string& hostname, LoginMethod loginMethod, const std::string& username, const std::string& password)
{
std::string response;
login(Environment::nodeName(), response);
login(hostname, response);
if (loginMethod == AUTH_CRAM_MD5)
{
if (response.find("CRAM-MD5", 0) != std::string::npos)
{
loginUsingCRAM_MD5(username, password);
loginUsingCRAMMD5(username, password);
}
else throw SMTPException("The mail service does not support CRAM-MD5 authentication", response);
}
else if (loginMethod == AUTH_CRAM_SHA1)
{
if (response.find("CRAM-SHA1", 0) != std::string::npos)
{
loginUsingCRAMSHA1(username, password);
}
else throw SMTPException("The mail service does not support CRAM-SHA1 authentication", response);
}
else if (loginMethod == AUTH_LOGIN)
{
if (response.find("LOGIN", 0) != std::string::npos)
@@ -230,6 +279,14 @@ void SMTPClientSession::login(LoginMethod loginMethod, const std::string& userna
}
else throw SMTPException("The mail service does not support LOGIN authentication", response);
}
else if (loginMethod == AUTH_PLAIN)
{
if (response.find("PLAIN", 0) != std::string::npos)
{
loginUsingPlain(username, password);
}
else throw SMTPException("The mail service does not support PLAIN authentication", response);
}
else if (loginMethod != AUTH_NONE)
{
throw SMTPException("The autentication method is not supported");
@@ -243,7 +300,7 @@ void SMTPClientSession::open()
{
std::string response;
int status = _socket.receiveStatusMessage(response);
if (!isPositiveCompletion(status)) throw SMTPException("The mail service is unavailable", response);
if (!isPositiveCompletion(status)) throw SMTPException("The mail service is unavailable", response, status);
_isOpen = true;
}
}
@@ -278,24 +335,24 @@ void SMTPClientSession::sendMessage(const MailMessage& message)
{
status = sendCommand("MAIL FROM:", fromField.substr(emailPos, fromField.size() - emailPos), response);
}
if (!isPositiveCompletion(status)) throw SMTPException("Cannot send message", response);
if (!isPositiveCompletion(status)) throw SMTPException("Cannot send message", response, status);
for (MailMessage::Recipients::const_iterator it = message.recipients().begin(); it != message.recipients().end(); ++it)
{
std::string recipient("<");
recipient.append(it->getAddress());
recipient.append(">");
int status = sendCommand("RCPT TO:", recipient, response);
if (!isPositiveCompletion(status)) throw SMTPException(std::string("Recipient rejected: ") + recipient, response);
if (!isPositiveCompletion(status)) throw SMTPException(std::string("Recipient rejected: ") + recipient, response, status);
}
status = sendCommand("DATA", response);
if (!isPositiveIntermediate(status)) throw SMTPException("Cannot send message data", response);
if (!isPositiveIntermediate(status)) throw SMTPException("Cannot send message data", response, status);
SocketOutputStream socketStream(_socket);
MailOutputStream mailStream(socketStream);
message.write(mailStream);
mailStream.close();
socketStream.flush();
status = _socket.receiveStatusMessage(response);
if (!isPositiveCompletion(status)) throw SMTPException("The server rejected the message", response);
if (!isPositiveCompletion(status)) throw SMTPException("The server rejected the message", response, status);
}

View File

@@ -107,10 +107,24 @@ void ServerSocket::bind(Poco::UInt16 port, bool reuseAddress)
impl()->bind(address, reuseAddress);
}
void ServerSocket::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only)
{
impl()->bind6(address, reuseAddress, ipV6Only);
}
void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool ipV6Only)
{
IPAddress wildcardAddr;
SocketAddress address(wildcardAddr, port);
impl()->bind6(address, reuseAddress, ipV6Only);
}
void ServerSocket::listen(int backlog)
{
impl()->listen(backlog);
impl()->listen(backlog);
}

View File

@@ -7,7 +7,7 @@
// Package: NetCore
// Module: SocketAddress
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// Copyright (c) 2005-2011, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
@@ -56,6 +56,15 @@ namespace Poco {
namespace Net {
struct AFLT
{
bool operator () (const IPAddress& a1, const IPAddress& a2)
{
return a1.af() < a2.af();
}
};
//
// SocketAddressImpl
//
@@ -71,14 +80,20 @@ public:
virtual int af() const = 0;
protected:
SocketAddressImpl()
{
}
virtual ~SocketAddressImpl()
{
}
SocketAddressImpl()
{
#if defined(_WIN32)
Poco::Net::initializeNetwork();
#endif
}
virtual ~SocketAddressImpl()
{
#if defined(_WIN32)
Poco::Net::uninitializeNetwork();
#endif
}
private:
SocketAddressImpl(const SocketAddressImpl&);
SocketAddressImpl& operator = (const SocketAddressImpl&);
@@ -155,15 +170,25 @@ public:
_addr.sin6_family = AF_INET6;
poco_set_sin6_len(&_addr);
std::memcpy(&_addr.sin6_addr, addr, sizeof(_addr.sin6_addr));
_addr.sin6_port = port;
}
_addr.sin6_port = port;
}
IPAddress host() const
{
return IPAddress(&_addr.sin6_addr, sizeof(_addr.sin6_addr));
}
UInt16 port() const
IPv6SocketAddressImpl(const void* addr, UInt16 port, UInt32 scope)
{
std::memset(&_addr, 0, sizeof(_addr));
_addr.sin6_family = AF_INET6;
poco_set_sin6_len(&_addr);
std::memcpy(&_addr.sin6_addr, addr, sizeof(_addr.sin6_addr));
_addr.sin6_port = port;
_addr.sin6_scope_id = scope;
}
IPAddress host() const
{
return IPAddress(&_addr.sin6_addr, sizeof(_addr.sin6_addr), _addr.sin6_scope_id);
}
UInt16 port() const
{
return _addr.sin6_port;
}
@@ -339,29 +364,36 @@ std::string SocketAddress::toString() const
void SocketAddress::init(const IPAddress& host, Poco::UInt16 port)
{
if (host.family() == IPAddress::IPv4)
_pImpl = new IPv4SocketAddressImpl(host.addr(), htons(port));
_pImpl = new IPv4SocketAddressImpl(host.addr(), htons(port));
#if defined(POCO_HAVE_IPv6)
else if (host.family() == IPAddress::IPv6)
_pImpl = new IPv6SocketAddressImpl(host.addr(), htons(port));
else if (host.family() == IPAddress::IPv6)
_pImpl = new IPv6SocketAddressImpl(host.addr(), htons(port), host.scope());
#endif
else throw Poco::NotImplementedException("unsupported IP address family");
else throw Poco::NotImplementedException("unsupported IP address family");
}
void SocketAddress::init(const std::string& host, Poco::UInt16 port)
{
IPAddress ip;
if (IPAddress::tryParse(host, ip))
{
init(ip, port);
}
else
{
HostEntry he = DNS::hostByName(host);
if (he.addresses().size() > 0)
init(he.addresses()[0], port);
else throw HostNotFoundException("No address found for host", host);
}
if (IPAddress::tryParse(host, ip))
{
init(ip, port);
}
else
{
HostEntry he = DNS::hostByName(host);
HostEntry::AddressList addresses = he.addresses();
if (addresses.size() > 0)
{
#if defined(POCO_HAVE_IPv6)
// if we get both IPv4 and IPv6 addresses, prefer IPv4
std::sort(addresses.begin(), addresses.end(), AFLT());
#endif
init(addresses[0], port);
}
else throw HostNotFoundException("No address found for host", host);
}
}
@@ -374,11 +406,15 @@ Poco::UInt16 SocketAddress::resolveService(const std::string& service)
}
else
{
#if defined(POCO_VXWORKS)
throw ServiceNotFoundException(service);
#else
struct servent* se = getservbyname(service.c_str(), NULL);
if (se)
return ntohs(se->s_port);
else
throw ServiceNotFoundException(service);
#endif
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -85,10 +85,14 @@ void SocketNotifier::removeObserver(SocketReactor* pReactor, const Poco::Abstrac
}
void SocketNotifier::dispatch(SocketNotification* pNotification)
namespace
{
static Socket nullSocket;
}
void SocketNotifier::dispatch(SocketNotification* pNotification)
{
pNotification->setSocket(_socket);
pNotification->duplicate();
try

View File

@@ -123,6 +123,8 @@ void SocketReactor::run()
}
else if (Socket::select(readable, writable, except, _timeout))
{
onBusy();
for (Socket::SocketList::iterator it = readable.begin(); it != readable.end(); ++it)
dispatch(*it, _pReadableNotification);
for (Socket::SocketList::iterator it = writable.begin(); it != writable.end(); ++it)
@@ -169,31 +171,41 @@ const Poco::Timespan& SocketReactor::getTimeout() const
void SocketReactor::addEventHandler(const Socket& socket, const Poco::AbstractObserver& observer)
{
FastMutex::ScopedLock lock(_mutex);
NotifierPtr pNotifier;
EventHandlerMap::iterator it = _handlers.find(socket);
if (it == _handlers.end())
{
pNotifier = new SocketNotifier(socket);
_handlers[socket] = pNotifier;
FastMutex::ScopedLock lock(_mutex);
EventHandlerMap::iterator it = _handlers.find(socket);
if (it == _handlers.end())
{
pNotifier = new SocketNotifier(socket);
_handlers[socket] = pNotifier;
}
else pNotifier = it->second;
}
else pNotifier = it->second;
pNotifier->addObserver(this, observer);
}
void SocketReactor::removeEventHandler(const Socket& socket, const Poco::AbstractObserver& observer)
{
FastMutex::ScopedLock lock(_mutex);
EventHandlerMap::iterator it = _handlers.find(socket);
if (it != _handlers.end())
NotifierPtr pNotifier;
{
FastMutex::ScopedLock lock(_mutex);
EventHandlerMap::iterator it = _handlers.find(socket);
if (it != _handlers.end())
{
pNotifier = it->second;
if (pNotifier->countObservers() == 1)
{
_handlers.erase(it);
}
}
}
if (pNotifier)
{
NotifierPtr pNotifier = it->second;
pNotifier->removeObserver(this, observer);
if (!pNotifier->hasObservers())
_handlers.erase(it);
}
}
@@ -216,6 +228,11 @@ void SocketReactor::onShutdown()
}
void SocketReactor::onBusy()
{
}
void SocketReactor::dispatch(const Socket& socket, SocketNotification* pNotification)
{
NotifierPtr pNotifier;

View File

@@ -36,6 +36,7 @@
#include "Poco/Net/StreamSocketImpl.h"
#include "Poco/Exception.h"
#include "Poco/Thread.h"
namespace Poco {
@@ -73,14 +74,21 @@ int StreamSocketImpl::sendBytes(const void* buffer, int length, int flags)
{
const char* p = reinterpret_cast<const char*>(buffer);
int remaining = length;
int sent = 0;
bool blocking = getBlocking();
while (remaining > 0)
{
int n = SocketImpl::sendBytes(p, remaining, flags);
if (n <= 0) return n;
poco_assert_dbg (n >= 0);
p += n;
sent += n;
remaining -= n;
if (blocking && remaining > 0)
Poco::Thread::yield();
else
break;
}
return length;
return sent;
}

View File

@@ -147,6 +147,12 @@ void TCPServerDispatcher::run()
}
}
namespace
{
static const std::string threadName("TCPServerConnection");
}
void TCPServerDispatcher::enqueue(const StreamSocket& socket)
{
@@ -159,7 +165,6 @@ void TCPServerDispatcher::enqueue(const StreamSocket& socket)
{
try
{
static const std::string threadName("TCPServerConnection");
_threadPool.startWithPriority(_pParams->getThreadPriority(), *this, threadName);
++_currentThreads;
}