mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-23 00:07:59 +02:00
merge Unix Domain Sockets support and other changes from develop
This commit is contained in:
@@ -29,7 +29,7 @@ DatagramSocket::DatagramSocket(): Socket(new DatagramSocketImpl)
|
||||
}
|
||||
|
||||
|
||||
DatagramSocket::DatagramSocket(IPAddress::Family family): Socket(new DatagramSocketImpl(family))
|
||||
DatagramSocket::DatagramSocket(SocketAddress::Family family): Socket(new DatagramSocketImpl(family))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -81,6 +81,12 @@ void DatagramSocket::bind(const SocketAddress& address, bool reuseAddress)
|
||||
}
|
||||
|
||||
|
||||
void DatagramSocket::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
|
||||
{
|
||||
impl()->bind(address, reuseAddress, reusePort);
|
||||
}
|
||||
|
||||
|
||||
int DatagramSocket::sendBytes(const void* buffer, int length, int flags)
|
||||
{
|
||||
return impl()->sendBytes(buffer, length, flags);
|
||||
|
@@ -25,17 +25,20 @@ namespace Net {
|
||||
|
||||
DatagramSocketImpl::DatagramSocketImpl()
|
||||
{
|
||||
init(AF_INET);
|
||||
}
|
||||
|
||||
|
||||
DatagramSocketImpl::DatagramSocketImpl(IPAddress::Family family)
|
||||
DatagramSocketImpl::DatagramSocketImpl(SocketAddress::Family family)
|
||||
{
|
||||
if (family == IPAddress::IPv4)
|
||||
if (family == SocketAddress::IPv4)
|
||||
init(AF_INET);
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
else if (family == IPAddress::IPv6)
|
||||
else if (family == SocketAddress::IPv6)
|
||||
init(AF_INET6);
|
||||
#endif
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
else if (family == SocketAddress::UNIX_LOCAL)
|
||||
init(AF_UNIX);
|
||||
#endif
|
||||
else throw InvalidArgumentException("Invalid or unsupported address family passed to DatagramSocketImpl");
|
||||
}
|
||||
|
@@ -44,7 +44,8 @@ HTTPClientSession::HTTPClientSession():
|
||||
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
|
||||
_reconnect(false),
|
||||
_mustReconnect(false),
|
||||
_expectResponseBody(false)
|
||||
_expectResponseBody(false),
|
||||
_responseReceived(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,7 +57,8 @@ HTTPClientSession::HTTPClientSession(const StreamSocket& socket):
|
||||
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
|
||||
_reconnect(false),
|
||||
_mustReconnect(false),
|
||||
_expectResponseBody(false)
|
||||
_expectResponseBody(false),
|
||||
_responseReceived(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -68,7 +70,8 @@ HTTPClientSession::HTTPClientSession(const SocketAddress& address):
|
||||
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
|
||||
_reconnect(false),
|
||||
_mustReconnect(false),
|
||||
_expectResponseBody(false)
|
||||
_expectResponseBody(false),
|
||||
_responseReceived(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -80,7 +83,8 @@ HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port)
|
||||
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
|
||||
_reconnect(false),
|
||||
_mustReconnect(false),
|
||||
_expectResponseBody(false)
|
||||
_expectResponseBody(false),
|
||||
_responseReceived(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -92,7 +96,8 @@ HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port,
|
||||
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
|
||||
_reconnect(false),
|
||||
_mustReconnect(false),
|
||||
_expectResponseBody(false)
|
||||
_expectResponseBody(false),
|
||||
_responseReceived(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -190,9 +195,10 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
|
||||
{
|
||||
clearException();
|
||||
_pResponseStream = 0;
|
||||
_responseReceived = false;
|
||||
|
||||
bool keepAlive = getKeepAlive();
|
||||
if ((connected() && !keepAlive) || mustReconnect())
|
||||
if (((connected() && !keepAlive) || mustReconnect()) && !_host.empty())
|
||||
{
|
||||
close();
|
||||
_mustReconnect = false;
|
||||
@@ -203,7 +209,7 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
|
||||
reconnect();
|
||||
if (!keepAlive)
|
||||
request.setKeepAlive(false);
|
||||
if (!request.has(HTTPRequest::HOST))
|
||||
if (!request.has(HTTPRequest::HOST) && !_host.empty())
|
||||
request.setHost(_host, _port);
|
||||
if (!_proxyConfig.host.empty() && !bypassProxy())
|
||||
{
|
||||
@@ -258,25 +264,28 @@ std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
|
||||
_pRequestStream = 0;
|
||||
if (networkException()) networkException()->rethrow();
|
||||
|
||||
do
|
||||
if (!_responseReceived)
|
||||
{
|
||||
response.clear();
|
||||
HTTPHeaderInputStream his(*this);
|
||||
try
|
||||
do
|
||||
{
|
||||
response.read(his);
|
||||
}
|
||||
catch (Exception&)
|
||||
{
|
||||
close();
|
||||
if (networkException())
|
||||
networkException()->rethrow();
|
||||
else
|
||||
response.clear();
|
||||
HTTPHeaderInputStream his(*this);
|
||||
try
|
||||
{
|
||||
response.read(his);
|
||||
}
|
||||
catch (Exception&)
|
||||
{
|
||||
close();
|
||||
if (networkException())
|
||||
networkException()->rethrow();
|
||||
else
|
||||
throw;
|
||||
throw;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
while (response.getStatus() == HTTPResponse::HTTP_CONTINUE);
|
||||
}
|
||||
while (response.getStatus() == HTTPResponse::HTTP_CONTINUE);
|
||||
|
||||
_mustReconnect = getKeepAlive() && !response.getKeepAlive();
|
||||
|
||||
@@ -297,6 +306,34 @@ std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
|
||||
}
|
||||
|
||||
|
||||
bool HTTPClientSession::peekResponse(HTTPResponse& response)
|
||||
{
|
||||
poco_assert (!_responseReceived);
|
||||
|
||||
_pRequestStream->flush();
|
||||
|
||||
if (networkException()) networkException()->rethrow();
|
||||
|
||||
response.clear();
|
||||
HTTPHeaderInputStream his(*this);
|
||||
try
|
||||
{
|
||||
response.read(his);
|
||||
}
|
||||
catch (Exception&)
|
||||
{
|
||||
close();
|
||||
if (networkException())
|
||||
networkException()->rethrow();
|
||||
else
|
||||
throw;
|
||||
throw;
|
||||
}
|
||||
_responseReceived = response.getStatus() != HTTPResponse::HTTP_CONTINUE;
|
||||
return !_responseReceived;
|
||||
}
|
||||
|
||||
|
||||
void HTTPClientSession::reset()
|
||||
{
|
||||
close();
|
||||
|
@@ -41,6 +41,7 @@ const std::string HTTPRequest::COOKIE = "Cookie";
|
||||
const std::string HTTPRequest::AUTHORIZATION = "Authorization";
|
||||
const std::string HTTPRequest::PROXY_AUTHORIZATION = "Proxy-Authorization";
|
||||
const std::string HTTPRequest::UPGRADE = "Upgrade";
|
||||
const std::string HTTPRequest::EXPECT = "Expect";
|
||||
|
||||
|
||||
HTTPRequest::HTTPRequest():
|
||||
@@ -257,4 +258,20 @@ void HTTPRequest::setCredentials(const std::string& header, const std::string& s
|
||||
}
|
||||
|
||||
|
||||
bool HTTPRequest::getExpectContinue() const
|
||||
{
|
||||
const std::string& expect = get(EXPECT, EMPTY);
|
||||
return !expect.empty() && icompare(expect, "100-continue") == 0;
|
||||
}
|
||||
|
||||
|
||||
void HTTPRequest::setExpectContinue(bool expectContinue)
|
||||
{
|
||||
if (expectContinue)
|
||||
set(EXPECT, "100-continue");
|
||||
else
|
||||
erase(EXPECT);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
@@ -38,6 +38,7 @@ namespace Net {
|
||||
|
||||
const std::string HTTPResponse::HTTP_REASON_CONTINUE = "Continue";
|
||||
const std::string HTTPResponse::HTTP_REASON_SWITCHING_PROTOCOLS = "Switching Protocols";
|
||||
const std::string HTTPResponse::HTTP_REASON_PROCESSING = "Processing";
|
||||
const std::string HTTPResponse::HTTP_REASON_OK = "OK";
|
||||
const std::string HTTPResponse::HTTP_REASON_CREATED = "Created";
|
||||
const std::string HTTPResponse::HTTP_REASON_ACCEPTED = "Accepted";
|
||||
@@ -45,13 +46,17 @@ const std::string HTTPResponse::HTTP_REASON_NONAUTHORITATIVE = "N
|
||||
const std::string HTTPResponse::HTTP_REASON_NO_CONTENT = "No Content";
|
||||
const std::string HTTPResponse::HTTP_REASON_RESET_CONTENT = "Reset Content";
|
||||
const std::string HTTPResponse::HTTP_REASON_PARTIAL_CONTENT = "Partial Content";
|
||||
const std::string HTTPResponse::HTTP_REASON_MULTI_STATUS = "Multi Status";
|
||||
const std::string HTTPResponse::HTTP_REASON_ALREADY_REPORTED = "Already Reported";
|
||||
const std::string HTTPResponse::HTTP_REASON_IM_USED = "IM Used";
|
||||
const std::string HTTPResponse::HTTP_REASON_MULTIPLE_CHOICES = "Multiple Choices";
|
||||
const std::string HTTPResponse::HTTP_REASON_MOVED_PERMANENTLY = "Moved Permanently";
|
||||
const std::string HTTPResponse::HTTP_REASON_FOUND = "Found";
|
||||
const std::string HTTPResponse::HTTP_REASON_SEE_OTHER = "See Other";
|
||||
const std::string HTTPResponse::HTTP_REASON_NOT_MODIFIED = "Not Modified";
|
||||
const std::string HTTPResponse::HTTP_REASON_USEPROXY = "Use Proxy";
|
||||
const std::string HTTPResponse::HTTP_REASON_USE_PROXY = "Use Proxy";
|
||||
const std::string HTTPResponse::HTTP_REASON_TEMPORARY_REDIRECT = "Temporary Redirect";
|
||||
const std::string HTTPResponse::HTTP_REASON_PERMANENT_REDIRECT = "Permanent Redirect";
|
||||
const std::string HTTPResponse::HTTP_REASON_BAD_REQUEST = "Bad Request";
|
||||
const std::string HTTPResponse::HTTP_REASON_UNAUTHORIZED = "Unauthorized";
|
||||
const std::string HTTPResponse::HTTP_REASON_PAYMENT_REQUIRED = "Payment Required";
|
||||
@@ -65,17 +70,33 @@ const std::string HTTPResponse::HTTP_REASON_CONFLICT = "C
|
||||
const std::string HTTPResponse::HTTP_REASON_GONE = "Gone";
|
||||
const std::string HTTPResponse::HTTP_REASON_LENGTH_REQUIRED = "Length Required";
|
||||
const std::string HTTPResponse::HTTP_REASON_PRECONDITION_FAILED = "Precondition Failed";
|
||||
const std::string HTTPResponse::HTTP_REASON_REQUESTENTITYTOOLARGE = "Request Entity Too Large";
|
||||
const std::string HTTPResponse::HTTP_REASON_REQUESTURITOOLONG = "Request-URI Too Large";
|
||||
const std::string HTTPResponse::HTTP_REASON_UNSUPPORTEDMEDIATYPE = "Unsupported Media Type";
|
||||
const std::string HTTPResponse::HTTP_REASON_REQUEST_ENTITY_TOO_LARGE = "Request Entity Too Large";
|
||||
const std::string HTTPResponse::HTTP_REASON_REQUEST_URI_TOO_LONG = "Request-URI Too Large";
|
||||
const std::string HTTPResponse::HTTP_REASON_UNSUPPORTED_MEDIA_TYPE = "Unsupported Media Type";
|
||||
const std::string HTTPResponse::HTTP_REASON_REQUESTED_RANGE_NOT_SATISFIABLE = "Requested Range Not Satisfiable";
|
||||
const std::string HTTPResponse::HTTP_REASON_EXPECTATION_FAILED = "Expectation Failed";
|
||||
const std::string HTTPResponse::HTTP_REASON_IM_A_TEAPOT = "I'm a Teapot";
|
||||
const std::string HTTPResponse::HTTP_REASON_ENCHANCE_YOUR_CALM = "Enchance Your Calm";
|
||||
const std::string HTTPResponse::HTTP_REASON_MISDIRECTED_REQUEST = "Misdirected Request";
|
||||
const std::string HTTPResponse::HTTP_REASON_UNPROCESSABLE_ENTITY = "Unprocessable Entity";
|
||||
const std::string HTTPResponse::HTTP_REASON_LOCKED = "Locked";
|
||||
const std::string HTTPResponse::HTTP_REASON_FAILED_DEPENDENCY = "Failed Dependency";
|
||||
const std::string HTTPResponse::HTTP_REASON_UPGRADE_REQUIRED = "Upgrade Required";
|
||||
const std::string HTTPResponse::HTTP_REASON_PRECONDITION_REQUIRED = "Precondition Required";
|
||||
const std::string HTTPResponse::HTTP_REASON_TOO_MANY_REQUESTS = "Too Many Requests";
|
||||
const std::string HTTPResponse::HTTP_REASON_REQUEST_HEADER_FIELDS_TOO_LARGE = "Request Header Fields Too Large";
|
||||
const std::string HTTPResponse::HTTP_REASON_UNAVAILABLE_FOR_LEGAL_REASONS = "Unavailable For Legal Reasons";
|
||||
const std::string HTTPResponse::HTTP_REASON_INTERNAL_SERVER_ERROR = "Internal Server Error";
|
||||
const std::string HTTPResponse::HTTP_REASON_NOT_IMPLEMENTED = "Not Implemented";
|
||||
const std::string HTTPResponse::HTTP_REASON_BAD_GATEWAY = "Bad Gateway";
|
||||
const std::string HTTPResponse::HTTP_REASON_SERVICE_UNAVAILABLE = "Service Unavailable";
|
||||
const std::string HTTPResponse::HTTP_REASON_GATEWAY_TIMEOUT = "Gateway Time-out";
|
||||
const std::string HTTPResponse::HTTP_REASON_VERSION_NOT_SUPPORTED = "HTTP Version not supported";
|
||||
const std::string HTTPResponse::HTTP_REASON_GATEWAY_TIMEOUT = "Gateway Time-Out";
|
||||
const std::string HTTPResponse::HTTP_REASON_VERSION_NOT_SUPPORTED = "HTTP Version Not Supported";
|
||||
const std::string HTTPResponse::HTTP_REASON_VARIANT_ALSO_NEGOTIATES = "Variant Also Negotiates";
|
||||
const std::string HTTPResponse::HTTP_REASON_INSUFFICIENT_STORAGE = "Insufficient Storage";
|
||||
const std::string HTTPResponse::HTTP_REASON_LOOP_DETECTED = "Loop Detected";
|
||||
const std::string HTTPResponse::HTTP_REASON_NOT_EXTENDED = "Not Extended";
|
||||
const std::string HTTPResponse::HTTP_REASON_NETWORK_AUTHENTICATION_REQUIRED = "Network Authentication Required";
|
||||
const std::string HTTPResponse::HTTP_REASON_UNKNOWN = "???";
|
||||
const std::string HTTPResponse::DATE = "Date";
|
||||
const std::string HTTPResponse::SET_COOKIE = "Set-Cookie";
|
||||
@@ -238,6 +259,8 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
|
||||
return HTTP_REASON_CONTINUE;
|
||||
case HTTP_SWITCHING_PROTOCOLS:
|
||||
return HTTP_REASON_SWITCHING_PROTOCOLS;
|
||||
case HTTP_PROCESSING:
|
||||
return HTTP_REASON_PROCESSING;
|
||||
case HTTP_OK:
|
||||
return HTTP_REASON_OK;
|
||||
case HTTP_CREATED:
|
||||
@@ -252,6 +275,12 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
|
||||
return HTTP_REASON_RESET_CONTENT;
|
||||
case HTTP_PARTIAL_CONTENT:
|
||||
return HTTP_REASON_PARTIAL_CONTENT;
|
||||
case HTTP_MULTI_STATUS:
|
||||
return HTTP_REASON_MULTI_STATUS;
|
||||
case HTTP_ALREADY_REPORTED:
|
||||
return HTTP_REASON_ALREADY_REPORTED;
|
||||
case HTTP_IM_USED:
|
||||
return HTTP_REASON_IM_USED;
|
||||
case HTTP_MULTIPLE_CHOICES:
|
||||
return HTTP_REASON_MULTIPLE_CHOICES;
|
||||
case HTTP_MOVED_PERMANENTLY:
|
||||
@@ -262,8 +291,8 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
|
||||
return HTTP_REASON_SEE_OTHER;
|
||||
case HTTP_NOT_MODIFIED:
|
||||
return HTTP_REASON_NOT_MODIFIED;
|
||||
case HTTP_USEPROXY:
|
||||
return HTTP_REASON_USEPROXY;
|
||||
case HTTP_USE_PROXY:
|
||||
return HTTP_REASON_USE_PROXY;
|
||||
case HTTP_TEMPORARY_REDIRECT:
|
||||
return HTTP_REASON_TEMPORARY_REDIRECT;
|
||||
case HTTP_BAD_REQUEST:
|
||||
@@ -292,16 +321,38 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
|
||||
return HTTP_REASON_LENGTH_REQUIRED;
|
||||
case HTTP_PRECONDITION_FAILED:
|
||||
return HTTP_REASON_PRECONDITION_FAILED;
|
||||
case HTTP_REQUESTENTITYTOOLARGE:
|
||||
return HTTP_REASON_REQUESTENTITYTOOLARGE;
|
||||
case HTTP_REQUESTURITOOLONG:
|
||||
return HTTP_REASON_REQUESTURITOOLONG;
|
||||
case HTTP_UNSUPPORTEDMEDIATYPE:
|
||||
return HTTP_REASON_UNSUPPORTEDMEDIATYPE;
|
||||
case HTTP_REQUEST_ENTITY_TOO_LARGE:
|
||||
return HTTP_REASON_REQUEST_ENTITY_TOO_LARGE;
|
||||
case HTTP_REQUEST_URI_TOO_LONG:
|
||||
return HTTP_REASON_REQUEST_URI_TOO_LONG;
|
||||
case HTTP_UNSUPPORTED_MEDIA_TYPE:
|
||||
return HTTP_REASON_UNSUPPORTED_MEDIA_TYPE;
|
||||
case HTTP_REQUESTED_RANGE_NOT_SATISFIABLE:
|
||||
return HTTP_REASON_REQUESTED_RANGE_NOT_SATISFIABLE;
|
||||
case HTTP_EXPECTATION_FAILED:
|
||||
return HTTP_REASON_EXPECTATION_FAILED;
|
||||
case HTTP_IM_A_TEAPOT:
|
||||
return HTTP_REASON_IM_A_TEAPOT;
|
||||
case HTTP_ENCHANCE_YOUR_CALM:
|
||||
return HTTP_REASON_ENCHANCE_YOUR_CALM;
|
||||
case HTTP_MISDIRECTED_REQUEST:
|
||||
return HTTP_REASON_MISDIRECTED_REQUEST;
|
||||
case HTTP_UNPROCESSABLE_ENTITY:
|
||||
return HTTP_REASON_UNPROCESSABLE_ENTITY;
|
||||
case HTTP_LOCKED:
|
||||
return HTTP_REASON_LOCKED;
|
||||
case HTTP_FAILED_DEPENDENCY:
|
||||
return HTTP_REASON_FAILED_DEPENDENCY;
|
||||
case HTTP_UPGRADE_REQUIRED:
|
||||
return HTTP_REASON_UPGRADE_REQUIRED;
|
||||
case HTTP_PRECONDITION_REQUIRED:
|
||||
return HTTP_REASON_PRECONDITION_REQUIRED;
|
||||
case HTTP_TOO_MANY_REQUESTS:
|
||||
return HTTP_REASON_TOO_MANY_REQUESTS;
|
||||
case HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE:
|
||||
return HTTP_REASON_REQUEST_HEADER_FIELDS_TOO_LARGE;
|
||||
case HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
|
||||
return HTTP_REASON_UNAVAILABLE_FOR_LEGAL_REASONS;
|
||||
case HTTP_INTERNAL_SERVER_ERROR:
|
||||
return HTTP_REASON_INTERNAL_SERVER_ERROR;
|
||||
case HTTP_NOT_IMPLEMENTED:
|
||||
@@ -314,6 +365,16 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
|
||||
return HTTP_REASON_GATEWAY_TIMEOUT;
|
||||
case HTTP_VERSION_NOT_SUPPORTED:
|
||||
return HTTP_REASON_VERSION_NOT_SUPPORTED;
|
||||
case HTTP_VARIANT_ALSO_NEGOTIATES:
|
||||
return HTTP_REASON_VARIANT_ALSO_NEGOTIATES;
|
||||
case HTTP_INSUFFICIENT_STORAGE:
|
||||
return HTTP_REASON_INSUFFICIENT_STORAGE;
|
||||
case HTTP_LOOP_DETECTED:
|
||||
return HTTP_REASON_LOOP_DETECTED;
|
||||
case HTTP_NOT_EXTENDED:
|
||||
return HTTP_REASON_NOT_EXTENDED;
|
||||
case HTTP_NETWORK_AUTHENTICATION_REQUIRED:
|
||||
return HTTP_REASON_NETWORK_AUTHENTICATION_REQUIRED;
|
||||
default:
|
||||
return HTTP_REASON_UNKNOWN;
|
||||
}
|
||||
|
@@ -83,7 +83,7 @@ void HTTPServerConnection::run()
|
||||
#endif
|
||||
if (pHandler.get())
|
||||
{
|
||||
if (request.expectContinue())
|
||||
if (request.getExpectContinue() && response.getStatus() == HTTPResponse::HTTP_OK)
|
||||
response.sendContinue();
|
||||
|
||||
pHandler->handleRequest(request, response);
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include "Poco/Net/HTTPFixedLengthStream.h"
|
||||
#include "Poco/Net/HTTPChunkedStream.h"
|
||||
#include "Poco/Net/HTTPServerParams.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
#include "Poco/String.h"
|
||||
|
||||
|
||||
@@ -30,9 +31,6 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
const std::string HTTPServerRequestImpl::EXPECT("Expect");
|
||||
|
||||
|
||||
HTTPServerRequestImpl::HTTPServerRequestImpl(HTTPServerResponseImpl& response, HTTPServerSession& session, HTTPServerParams* pParams):
|
||||
_response(response),
|
||||
_session(session),
|
||||
@@ -69,6 +67,12 @@ HTTPServerRequestImpl::~HTTPServerRequestImpl()
|
||||
}
|
||||
|
||||
|
||||
bool HTTPServerRequestImpl::secure() const
|
||||
{
|
||||
return _session.socket().secure();
|
||||
}
|
||||
|
||||
|
||||
StreamSocket& HTTPServerRequestImpl::socket()
|
||||
{
|
||||
return _session.socket();
|
||||
@@ -81,11 +85,4 @@ StreamSocket HTTPServerRequestImpl::detachSocket()
|
||||
}
|
||||
|
||||
|
||||
bool HTTPServerRequestImpl::expectContinue() const
|
||||
{
|
||||
const std::string& expect = get(EXPECT, EMPTY);
|
||||
return !expect.empty() && icompare(expect, "100-continue") == 0;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
@@ -30,7 +30,9 @@ HTTPSession::HTTPSession():
|
||||
_pCurrent(0),
|
||||
_pEnd(0),
|
||||
_keepAlive(false),
|
||||
_timeout(HTTP_DEFAULT_TIMEOUT),
|
||||
_connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT),
|
||||
_receiveTimeout(HTTP_DEFAULT_TIMEOUT),
|
||||
_sendTimeout(HTTP_DEFAULT_TIMEOUT),
|
||||
_pException(0)
|
||||
{
|
||||
}
|
||||
@@ -42,7 +44,9 @@ HTTPSession::HTTPSession(const StreamSocket& socket):
|
||||
_pCurrent(0),
|
||||
_pEnd(0),
|
||||
_keepAlive(false),
|
||||
_timeout(HTTP_DEFAULT_TIMEOUT),
|
||||
_connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT),
|
||||
_receiveTimeout(HTTP_DEFAULT_TIMEOUT),
|
||||
_sendTimeout(HTTP_DEFAULT_TIMEOUT),
|
||||
_pException(0)
|
||||
{
|
||||
}
|
||||
@@ -54,7 +58,9 @@ HTTPSession::HTTPSession(const StreamSocket& socket, bool keepAlive):
|
||||
_pCurrent(0),
|
||||
_pEnd(0),
|
||||
_keepAlive(keepAlive),
|
||||
_timeout(HTTP_DEFAULT_TIMEOUT),
|
||||
_connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT),
|
||||
_receiveTimeout(HTTP_DEFAULT_TIMEOUT),
|
||||
_sendTimeout(HTTP_DEFAULT_TIMEOUT),
|
||||
_pException(0)
|
||||
{
|
||||
}
|
||||
@@ -89,7 +95,15 @@ void HTTPSession::setKeepAlive(bool keepAlive)
|
||||
|
||||
void HTTPSession::setTimeout(const Poco::Timespan& timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
setTimeout(timeout, timeout, timeout);
|
||||
}
|
||||
|
||||
|
||||
void HTTPSession::setTimeout(const Poco::Timespan& connectionTimeout, const Poco::Timespan& sendTimeout, const Poco::Timespan& receiveTimeout)
|
||||
{
|
||||
_connectionTimeout = connectionTimeout;
|
||||
_sendTimeout = sendTimeout;
|
||||
_receiveTimeout = receiveTimeout;
|
||||
}
|
||||
|
||||
|
||||
@@ -179,8 +193,9 @@ bool HTTPSession::connected() const
|
||||
|
||||
void HTTPSession::connect(const SocketAddress& address)
|
||||
{
|
||||
_socket.connect(address, _timeout);
|
||||
_socket.setReceiveTimeout(_timeout);
|
||||
_socket.connect(address, _connectionTimeout);
|
||||
_socket.setReceiveTimeout(_receiveTimeout);
|
||||
_socket.setSendTimeout(_sendTimeout);
|
||||
_socket.setNoDelay(true);
|
||||
// There may be leftover data from a previous (failed) request in the buffer,
|
||||
// so we clear it.
|
||||
|
@@ -140,7 +140,7 @@ std::istream* HTTPStreamFactory::open(const URI& uri)
|
||||
{
|
||||
return new HTTPResponseStream(rs, pSession);
|
||||
}
|
||||
else if (res.getStatus() == HTTPResponse::HTTP_USEPROXY && !retry)
|
||||
else if (res.getStatus() == HTTPResponse::HTTP_USE_PROXY && !retry)
|
||||
{
|
||||
// The requested resource MUST be accessed through the proxy
|
||||
// given by the Location field. The Location field gives the
|
||||
|
@@ -34,7 +34,7 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
ICMPClient::ICMPClient(IPAddress::Family family):
|
||||
ICMPClient::ICMPClient(SocketAddress::Family family):
|
||||
_family(family)
|
||||
{
|
||||
}
|
||||
|
@@ -33,13 +33,25 @@ using Poco::UInt16;
|
||||
using Poco::UInt32;
|
||||
using Poco::Net::Impl::IPAddressImpl;
|
||||
using Poco::Net::Impl::IPv4AddressImpl;
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
using Poco::Net::Impl::IPv6AddressImpl;
|
||||
#endif
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
#if !defined(_MSC_VER) || defined(__STDC__)
|
||||
// Go home MSVC, you're drunk...
|
||||
// See http://stackoverflow.com/questions/5899857/multiple-definition-error-for-static-const-class-members
|
||||
const IPAddress::Family IPAddress::IPv4;
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
const IPAddress::Family IPAddress::IPv6;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
IPAddress::IPAddress()
|
||||
{
|
||||
newIPv4();
|
||||
@@ -50,8 +62,10 @@ IPAddress::IPAddress(const IPAddress& addr)
|
||||
{
|
||||
if (addr.family() == IPv4)
|
||||
newIPv4(addr.addr());
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
else
|
||||
newIPv6(addr.addr(), addr.scope());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -63,8 +77,7 @@ IPAddress::IPAddress(Family family)
|
||||
else if (family == IPv6)
|
||||
newIPv6();
|
||||
#endif
|
||||
else
|
||||
throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
|
||||
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
|
||||
}
|
||||
|
||||
|
||||
@@ -219,8 +232,12 @@ IPAddress& IPAddress::operator = (const IPAddress& addr)
|
||||
destruct();
|
||||
if (addr.family() == IPAddress::IPv4)
|
||||
newIPv4(addr.addr());
|
||||
else
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
else if (addr.family() == IPAddress::IPv6)
|
||||
newIPv6(addr.addr(), addr.scope());
|
||||
#endif
|
||||
else
|
||||
throw Poco::InvalidArgumentException("Invalid or unsupported address family");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -228,7 +245,7 @@ IPAddress& IPAddress::operator = (const IPAddress& addr)
|
||||
|
||||
IPAddress::Family IPAddress::family() const
|
||||
{
|
||||
return static_cast<IPAddress::Family>(pImpl()->family());
|
||||
return pImpl()->family();
|
||||
}
|
||||
|
||||
|
||||
@@ -561,19 +578,30 @@ IPAddress IPAddress::broadcast()
|
||||
}
|
||||
|
||||
|
||||
BinaryWriter& operator << (BinaryWriter& writer, const IPAddress& value)
|
||||
} } // namespace Poco::Net
|
||||
|
||||
|
||||
Poco::BinaryWriter& operator << (Poco::BinaryWriter& writer, const Poco::Net::IPAddress& value)
|
||||
{
|
||||
writer.stream().write((const char*) value.addr(), value.length());
|
||||
writer << static_cast<Poco::UInt8>(value.length());
|
||||
writer.writeRaw(reinterpret_cast<const char*>(value.addr()), value.length());
|
||||
return writer;
|
||||
}
|
||||
|
||||
BinaryReader& operator >> (BinaryReader& reader, IPAddress& value)
|
||||
|
||||
Poco::BinaryReader& operator >> (Poco::BinaryReader& reader, Poco::Net::IPAddress& value)
|
||||
{
|
||||
char buf[sizeof(struct in6_addr)];
|
||||
reader.stream().read(buf, value.length());
|
||||
value = IPAddress(buf, value.length());
|
||||
Poco::UInt8 length;
|
||||
reader >> length;
|
||||
reader.readRaw(buf, length);
|
||||
value = Poco::Net::IPAddress(buf, length);
|
||||
return reader;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
std::ostream& operator << (std::ostream& ostr, const Poco::Net::IPAddress& addr)
|
||||
{
|
||||
ostr << addr.toString();
|
||||
return ostr;
|
||||
}
|
||||
|
@@ -143,7 +143,7 @@ const void* IPv4AddressImpl::addr() const
|
||||
|
||||
IPAddressImpl::Family IPv4AddressImpl::family() const
|
||||
{
|
||||
return IPAddressImpl::IPv4;
|
||||
return AddressFamily::IPv4;
|
||||
}
|
||||
|
||||
|
||||
@@ -500,7 +500,7 @@ const void* IPv6AddressImpl::addr() const
|
||||
|
||||
IPAddressImpl::Family IPv6AddressImpl::family() const
|
||||
{
|
||||
return IPAddressImpl::IPv6;
|
||||
return AddressFamily::IPv6;
|
||||
}
|
||||
|
||||
|
||||
@@ -535,6 +535,8 @@ unsigned IPv6AddressImpl::prefixLength() const
|
||||
throw NotImplementedException("prefixLength() not implemented");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Poco::UInt32 IPv6AddressImpl::scope() const
|
||||
{
|
||||
return _scope;
|
||||
|
@@ -16,6 +16,11 @@
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/Ascii.h"
|
||||
#include "Poco/TextConverter.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
#include "Poco/Base64Decoder.h"
|
||||
#include "Poco/UTF8Encoding.h"
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@@ -96,7 +101,7 @@ void MessageHeader::read(std::istream& istr)
|
||||
throw MessageException("Folded field value too long/no CRLF found");
|
||||
}
|
||||
Poco::trimRightInPlace(value);
|
||||
add(name, value);
|
||||
add(name, decodeWord(value));
|
||||
++fields;
|
||||
}
|
||||
istr.putback(ch);
|
||||
@@ -252,4 +257,138 @@ void MessageHeader::quote(const std::string& value, std::string& result, bool al
|
||||
}
|
||||
|
||||
|
||||
void MessageHeader::decodeRFC2047(const std::string& ins, std::string& outs, const std::string& charset_to)
|
||||
{
|
||||
std::string tempout;
|
||||
StringTokenizer tokens(ins, "?");
|
||||
|
||||
std::string charset = toUpper(tokens[0]);
|
||||
std::string encoding = toUpper(tokens[1]);
|
||||
std::string text = tokens[2];
|
||||
|
||||
std::istringstream istr(text);
|
||||
|
||||
if (encoding == "B")
|
||||
{
|
||||
// Base64 encoding.
|
||||
Base64Decoder decoder(istr);
|
||||
for (char c; decoder.get(c); tempout += c) {}
|
||||
}
|
||||
else if (encoding == "Q")
|
||||
{
|
||||
// Quoted encoding.
|
||||
for (char c; istr.get(c);)
|
||||
{
|
||||
if (c == '_')
|
||||
{
|
||||
//RFC 2047 _ is a space.
|
||||
tempout += " ";
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME: check that we have enought chars-
|
||||
if (c == '=')
|
||||
{
|
||||
// The next two chars are hex representation of the complete byte.
|
||||
std::string hex;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
istr.get(c);
|
||||
hex += c;
|
||||
}
|
||||
hex = toUpper(hex);
|
||||
tempout += (char)(int)strtol(hex.c_str(), 0, 16);
|
||||
continue;
|
||||
}
|
||||
tempout += c;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wrong encoding
|
||||
outs = ins;
|
||||
return;
|
||||
}
|
||||
|
||||
// convert to the right charset.
|
||||
if (charset != charset_to)
|
||||
{
|
||||
try
|
||||
{
|
||||
TextEncoding& enc = TextEncoding::byName(charset);
|
||||
TextEncoding& dec = TextEncoding::byName(charset_to);
|
||||
TextConverter converter(enc, dec);
|
||||
converter.convert(tempout, outs);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// FIXME: Unsuported encoding...
|
||||
outs = tempout;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not conversion necesary.
|
||||
outs = tempout;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string MessageHeader::decodeWord(const std::string& text, const std::string& charset)
|
||||
{
|
||||
std::string outs, tmp = text;
|
||||
do {
|
||||
std::string tmp2;
|
||||
// find the begining of the next rfc2047 chunk
|
||||
size_t pos = tmp.find("=?");
|
||||
if (pos == std::string::npos) {
|
||||
// No more found, return
|
||||
outs += tmp;
|
||||
break;
|
||||
}
|
||||
|
||||
// check if there are standar text before the rfc2047 chunk, and if so, copy it.
|
||||
if (pos > 0) {
|
||||
outs += tmp.substr(0, pos);
|
||||
}
|
||||
|
||||
// remove text already copied.
|
||||
tmp = tmp.substr(pos + 2);
|
||||
|
||||
// find the first separator
|
||||
size_t pos1 = tmp.find("?");
|
||||
if (pos1 == std::string::npos) {
|
||||
// not found.
|
||||
outs += tmp;
|
||||
break;
|
||||
}
|
||||
|
||||
// find the second separator
|
||||
size_t pos2 = tmp.find("?", pos1 + 1);
|
||||
if (pos2 == std::string::npos) {
|
||||
// not found
|
||||
outs += tmp;
|
||||
break;
|
||||
}
|
||||
|
||||
// find the end of the actual rfc2047 chunk
|
||||
size_t pos3 = tmp.find("?=", pos2 + 1);
|
||||
if (pos3 == std::string::npos) {
|
||||
// not found.
|
||||
outs += tmp;
|
||||
break;
|
||||
|
||||
}
|
||||
// At this place, there are a valid rfc2047 chunk, so decode and copy the result.
|
||||
decodeRFC2047(tmp.substr(0, pos3), tmp2, charset);
|
||||
outs += tmp2;
|
||||
|
||||
// Jump at the rest of the string and repeat the whole process.
|
||||
tmp = tmp.substr(pos3 + 2);
|
||||
} while (true);
|
||||
|
||||
return outs;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
@@ -51,8 +51,12 @@ MulticastSocket::MulticastSocket()
|
||||
}
|
||||
|
||||
|
||||
MulticastSocket::MulticastSocket(IPAddress::Family family): DatagramSocket(family)
|
||||
MulticastSocket::MulticastSocket(SocketAddress::Family family): DatagramSocket(family)
|
||||
{
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
if (family == SocketAddress::UNIX_LOCAL)
|
||||
throw Poco::InvalidArgumentException("Cannot create a MulticastSocket with UNIX_LOCAL socket");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -80,18 +84,17 @@ MulticastSocket& MulticastSocket::operator = (const Socket& socket)
|
||||
|
||||
void MulticastSocket::setInterface(const NetworkInterface& interfc)
|
||||
{
|
||||
if (address().family() == IPAddress::IPv4)
|
||||
if (address().family() == SocketAddress::IPv4)
|
||||
{
|
||||
impl()->setOption(IPPROTO_IP, IP_MULTICAST_IF, interfc.firstAddress(IPAddress::IPv4));
|
||||
}
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
else if (address().family() == IPAddress::IPv6)
|
||||
else if (address().family() == SocketAddress::IPv6)
|
||||
{
|
||||
impl()->setOption(IPPROTO_IPV6, IPV6_MULTICAST_IF, interfc.index());
|
||||
}
|
||||
#endif
|
||||
else
|
||||
throw UnsupportedFamilyException("Unknown or unsupported socket family.");
|
||||
else throw UnsupportedFamilyException("Unknown or unsupported socket family.");
|
||||
}
|
||||
|
||||
|
||||
|
@@ -47,7 +47,8 @@ POCO_IMPLEMENT_EXCEPTION(ICMPException, NetException, "ICMP Exception")
|
||||
POCO_IMPLEMENT_EXCEPTION(NTPException, NetException, "NTP Exception")
|
||||
POCO_IMPLEMENT_EXCEPTION(HTMLFormException, NetException, "HTML Form Exception")
|
||||
POCO_IMPLEMENT_EXCEPTION(WebSocketException, NetException, "WebSocket Exception")
|
||||
POCO_IMPLEMENT_EXCEPTION(UnsupportedFamilyException, NetException, "Unknown or unsupported socket family.")
|
||||
POCO_IMPLEMENT_EXCEPTION(UnsupportedFamilyException, NetException, "Unknown or unsupported socket family")
|
||||
POCO_IMPLEMENT_EXCEPTION(AddressFamilyMismatchException, NetException, "Address family mismatch")
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
@@ -242,7 +242,7 @@ void NetworkInterfaceImpl::setPhyParams()
|
||||
#if !defined(POCO_OS_FAMILY_WINDOWS) && !defined(POCO_VXWORKS)
|
||||
struct ifreq ifr;
|
||||
std::strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ);
|
||||
DatagramSocket ds;
|
||||
DatagramSocket ds(SocketAddress::IPv4);
|
||||
|
||||
ds.impl()->ioctl(SIOCGIFFLAGS, &ifr);
|
||||
setFlags(ifr.ifr_flags);
|
||||
@@ -796,16 +796,10 @@ bool NetworkInterface::isUp() const
|
||||
|
||||
NetworkInterface NetworkInterface::forName(const std::string& name, bool requireIPv6)
|
||||
{
|
||||
Map map = NetworkInterface::map(false, false);
|
||||
Map::const_iterator it = map.begin();
|
||||
Map::const_iterator end = map.end();
|
||||
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (it->second.name() == name && ((requireIPv6 && it->second.supportsIPv6()) || !requireIPv6))
|
||||
return it->second;
|
||||
}
|
||||
throw InterfaceNotFoundException(name);
|
||||
if (requireIPv6)
|
||||
return forName(name, IPv6_ONLY);
|
||||
else
|
||||
return forName(name, IPv4_OR_IPv6);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -30,7 +30,7 @@ RawSocket::RawSocket():
|
||||
}
|
||||
|
||||
|
||||
RawSocket::RawSocket(IPAddress::Family family, int proto):
|
||||
RawSocket::RawSocket(SocketAddress::Family family, int proto):
|
||||
Socket(new RawSocketImpl(family, proto))
|
||||
{
|
||||
}
|
||||
@@ -84,6 +84,12 @@ void RawSocket::bind(const SocketAddress& address, bool reuseAddress)
|
||||
}
|
||||
|
||||
|
||||
void RawSocket::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
|
||||
{
|
||||
impl()->bind(address, reuseAddress, reusePort);
|
||||
}
|
||||
|
||||
|
||||
int RawSocket::sendBytes(const void* buffer, int length, int flags)
|
||||
{
|
||||
return impl()->sendBytes(buffer, length, flags);
|
||||
|
@@ -29,12 +29,12 @@ RawSocketImpl::RawSocketImpl()
|
||||
}
|
||||
|
||||
|
||||
RawSocketImpl::RawSocketImpl(IPAddress::Family family, int proto)
|
||||
RawSocketImpl::RawSocketImpl(SocketAddress::Family family, int proto)
|
||||
{
|
||||
if (family == IPAddress::IPv4)
|
||||
if (family == SocketAddress::IPv4)
|
||||
init2(AF_INET, proto);
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
else if (family == IPAddress::IPv6)
|
||||
else if (family == SocketAddress::IPv6)
|
||||
init2(AF_INET6, proto);
|
||||
#endif
|
||||
else throw InvalidArgumentException("Invalid or unsupported address family passed to RawSocketImpl");
|
||||
|
@@ -78,6 +78,12 @@ void ServerSocket::bind(const SocketAddress& address, bool reuseAddress)
|
||||
}
|
||||
|
||||
|
||||
void ServerSocket::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
|
||||
{
|
||||
impl()->bind(address, reuseAddress, reusePort);
|
||||
}
|
||||
|
||||
|
||||
void ServerSocket::bind(Poco::UInt16 port, bool reuseAddress)
|
||||
{
|
||||
IPAddress wildcardAddr;
|
||||
@@ -86,17 +92,47 @@ void ServerSocket::bind(Poco::UInt16 port, bool reuseAddress)
|
||||
}
|
||||
|
||||
|
||||
void ServerSocket::bind(Poco::UInt16 port, bool reuseAddress, bool reusePort)
|
||||
{
|
||||
IPAddress wildcardAddr;
|
||||
SocketAddress address(wildcardAddr, port);
|
||||
impl()->bind(address, reuseAddress, reusePort);
|
||||
}
|
||||
|
||||
|
||||
void ServerSocket::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only)
|
||||
{
|
||||
impl()->bind6(address, reuseAddress, ipV6Only);
|
||||
}
|
||||
|
||||
|
||||
void ServerSocket::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only)
|
||||
{
|
||||
impl()->bind6(address, reuseAddress, reusePort, ipV6Only);
|
||||
}
|
||||
|
||||
|
||||
void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool ipV6Only)
|
||||
{
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
IPAddress wildcardAddr(IPAddress::IPv6);
|
||||
SocketAddress address(wildcardAddr, port);
|
||||
impl()->bind6(address, reuseAddress, ipV6Only);
|
||||
#else
|
||||
throw Poco::NotImplementedException("No IPv6 support available");
|
||||
#endif // POCO_HAVE_IPv6
|
||||
}
|
||||
|
||||
|
||||
void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool reusePort, bool ipV6Only)
|
||||
{
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
IPAddress wildcardAddr(IPAddress::IPv6);
|
||||
SocketAddress address(wildcardAddr, port);
|
||||
impl()->bind6(address, reuseAddress, reusePort, ipV6Only);
|
||||
#else
|
||||
throw Poco::NotImplementedException("No IPv6 support available");
|
||||
#endif // POCO_HAVE_IPv6
|
||||
}
|
||||
|
||||
|
||||
|
@@ -22,9 +22,6 @@
|
||||
#elif defined(POCO_HAVE_FD_POLL)
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include <poll.h>
|
||||
typedef Poco::SharedPtr<pollfd,
|
||||
Poco::ReferenceCounter,
|
||||
Poco::ReleaseArrayPolicy<pollfd> > SharedPollArray;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -209,6 +206,7 @@ int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exce
|
||||
return readList.size() + writeList.size() + exceptList.size();
|
||||
|
||||
#elif defined(POCO_HAVE_FD_POLL)
|
||||
typedef Poco::SharedPtr<pollfd, Poco::ReferenceCounter, Poco::ReleaseArrayPolicy<pollfd> > SharedPollArray;
|
||||
|
||||
nfds_t nfd = readList.size() + writeList.size() + exceptList.size();
|
||||
if (0 == nfd) return 0;
|
||||
|
@@ -18,19 +18,24 @@
|
||||
#include "Poco/Net/DNS.h"
|
||||
#include "Poco/RefCountedObject.h"
|
||||
#include "Poco/NumberParser.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include "Poco/BinaryReader.h"
|
||||
#include "Poco/BinaryWriter.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
using Poco::RefCountedObject;
|
||||
using Poco::NumberParser;
|
||||
using Poco::NumberFormatter;
|
||||
using Poco::UInt16;
|
||||
using Poco::InvalidArgumentException;
|
||||
using Poco::Net::Impl::SocketAddressImpl;
|
||||
using Poco::Net::Impl::IPv4SocketAddressImpl;
|
||||
#ifdef POCO_HAVE_IPv6
|
||||
using Poco::Net::Impl::IPv6SocketAddressImpl;
|
||||
#endif
|
||||
#ifdef POCO_OS_FAMILY_UNIX
|
||||
using Poco::Net::Impl::LocalSocketAddressImpl;
|
||||
#endif
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@@ -51,12 +56,31 @@ struct AFLT
|
||||
//
|
||||
|
||||
|
||||
#if !defined(_MSC_VER) || defined(__STDC__)
|
||||
// Go home MSVC, you're drunk...
|
||||
// See http://stackoverflow.com/questions/5899857/multiple-definition-error-for-static-const-class-members
|
||||
const SocketAddress::Family SocketAddress::IPv4;
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
const SocketAddress::Family SocketAddress::IPv6;
|
||||
#endif
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
const SocketAddress::Family SocketAddress::UNIX_LOCAL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
SocketAddress::SocketAddress()
|
||||
{
|
||||
newIPv4();
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(Family fam)
|
||||
{
|
||||
init(IPAddress(fam), 0);
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(const IPAddress& hostAddress, Poco::UInt16 portNumber)
|
||||
{
|
||||
init(hostAddress, portNumber);
|
||||
@@ -69,65 +93,76 @@ SocketAddress::SocketAddress(Poco::UInt16 portNumber)
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(Family fam, Poco::UInt16 portNumber)
|
||||
{
|
||||
init(IPAddress(fam), portNumber);
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(const std::string& hostAddress, Poco::UInt16 portNumber)
|
||||
{
|
||||
init(hostAddress, portNumber);
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(Family fam, const std::string& hostAddress, Poco::UInt16 portNumber)
|
||||
{
|
||||
init(fam, hostAddress, portNumber);
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(const std::string& hostAddress, const std::string& portNumber)
|
||||
{
|
||||
init(hostAddress, resolveService(portNumber));
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(Family fam, const std::string& hostAddress, const std::string& portNumber)
|
||||
{
|
||||
init(fam, hostAddress, resolveService(portNumber));
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(Family fam, const std::string& addr)
|
||||
{
|
||||
init(fam, addr);
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(const std::string& hostAndPort)
|
||||
{
|
||||
poco_assert (!hostAndPort.empty());
|
||||
|
||||
std::string host;
|
||||
std::string port;
|
||||
std::string::const_iterator it = hostAndPort.begin();
|
||||
std::string::const_iterator end = hostAndPort.end();
|
||||
if (*it == '[')
|
||||
{
|
||||
++it;
|
||||
while (it != end && *it != ']') host += *it++;
|
||||
if (it == end) throw InvalidArgumentException("Malformed IPv6 address");
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (it != end && *it != ':') host += *it++;
|
||||
}
|
||||
if (it != end && *it == ':')
|
||||
{
|
||||
++it;
|
||||
while (it != end) port += *it++;
|
||||
}
|
||||
else throw InvalidArgumentException("Missing port number");
|
||||
init(host, resolveService(port));
|
||||
init(hostAndPort);
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(const SocketAddress& socketAddress)
|
||||
{
|
||||
if (socketAddress.family() == IPAddress::IPv4)
|
||||
if (socketAddress.family() == IPv4)
|
||||
newIPv4(reinterpret_cast<const sockaddr_in*>(socketAddress.addr()));
|
||||
else
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
else if (socketAddress.family() == IPv6)
|
||||
newIPv6(reinterpret_cast<const sockaddr_in6*>(socketAddress.addr()));
|
||||
#endif
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
else if (socketAddress.family() == UNIX_LOCAL)
|
||||
newLocal(reinterpret_cast<const sockaddr_un*>(socketAddress.addr()));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(const struct sockaddr* sockAddr, poco_socklen_t length)
|
||||
{
|
||||
if (length == sizeof(struct sockaddr_in))
|
||||
if (length == sizeof(struct sockaddr_in) && sockAddr->sa_family == AF_INET)
|
||||
newIPv4(reinterpret_cast<const struct sockaddr_in*>(sockAddr));
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
else if (length == sizeof(struct sockaddr_in6))
|
||||
else if (length == sizeof(struct sockaddr_in6) && sockAddr->sa_family == AF_INET6)
|
||||
newIPv6(reinterpret_cast<const struct sockaddr_in6*>(sockAddr));
|
||||
#endif
|
||||
else throw Poco::InvalidArgumentException("Invalid address length passed to SocketAddress()");
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
else if (length > 0 && length <= sizeof(struct sockaddr_un) && sockAddr->sa_family == AF_UNIX)
|
||||
newLocal(reinterpret_cast<const sockaddr_un*>(sockAddr));
|
||||
#endif
|
||||
else throw Poco::InvalidArgumentException("Invalid address length or family passed to SocketAddress()");
|
||||
}
|
||||
|
||||
|
||||
@@ -141,6 +176,9 @@ bool SocketAddress::operator < (const SocketAddress& socketAddress) const
|
||||
{
|
||||
if (family() < socketAddress.family()) return true;
|
||||
if (family() > socketAddress.family()) return false;
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
if (family() == UNIX_LOCAL) return toString() < socketAddress.toString();
|
||||
#endif
|
||||
if (host() < socketAddress.host()) return true;
|
||||
if (host() > socketAddress.host()) return false;
|
||||
return (port() < socketAddress.port());
|
||||
@@ -152,10 +190,16 @@ SocketAddress& SocketAddress::operator = (const SocketAddress& socketAddress)
|
||||
if (&socketAddress != this)
|
||||
{
|
||||
destruct();
|
||||
if (socketAddress.family() == IPAddress::IPv4)
|
||||
if (socketAddress.family() == IPv4)
|
||||
newIPv4(reinterpret_cast<const sockaddr_in*>(socketAddress.addr()));
|
||||
else
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
else if (socketAddress.family() == IPv6)
|
||||
newIPv6(reinterpret_cast<const sockaddr_in6*>(socketAddress.addr()));
|
||||
#endif
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
else if (socketAddress.family() == UNIX_LOCAL)
|
||||
newLocal(reinterpret_cast<const sockaddr_un*>(socketAddress.addr()));
|
||||
#endif
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -191,19 +235,15 @@ int SocketAddress::af() const
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::Family SocketAddress::family() const
|
||||
{
|
||||
return static_cast<Family>(pImpl()->family());
|
||||
}
|
||||
|
||||
|
||||
std::string SocketAddress::toString() const
|
||||
{
|
||||
std::string result;
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
if (host().family() == IPAddress::IPv6)
|
||||
result.append("[");
|
||||
result.append(host().toString());
|
||||
if (host().family() == IPAddress::IPv6)
|
||||
result.append("]");
|
||||
#endif
|
||||
result.append(":");
|
||||
NumberFormatter::append(result, port());
|
||||
return result;
|
||||
return pImpl()->toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +272,7 @@ void SocketAddress::init(const std::string& hostAddress, Poco::UInt16 portNumber
|
||||
HostEntry::AddressList addresses = he.addresses();
|
||||
if (addresses.size() > 0)
|
||||
{
|
||||
#if defined(POCO_HAVE_IPv6) && !defined(POCO_SOCKETADDRESS_DONT_PREFER_IPV4)
|
||||
#if defined(POCO_HAVE_IPv6) && defined(POCO_SOCKETADDRESS_PREFER_IPv4)
|
||||
// if we get both IPv4 and IPv6 addresses, prefer IPv4
|
||||
std::stable_sort(addresses.begin(), addresses.end(), AFLT());
|
||||
#endif
|
||||
@@ -243,6 +283,109 @@ void SocketAddress::init(const std::string& hostAddress, Poco::UInt16 portNumber
|
||||
}
|
||||
|
||||
|
||||
void SocketAddress::init(Family fam, const std::string& hostAddress, Poco::UInt16 portNumber)
|
||||
{
|
||||
IPAddress ip;
|
||||
if (IPAddress::tryParse(hostAddress, ip))
|
||||
{
|
||||
if (ip.family() != fam) throw AddressFamilyMismatchException(hostAddress);
|
||||
init(ip, portNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
HostEntry he = DNS::hostByName(hostAddress);
|
||||
HostEntry::AddressList addresses = he.addresses();
|
||||
if (addresses.size() > 0)
|
||||
{
|
||||
for (HostEntry::AddressList::const_iterator it = addresses.begin(); it != addresses.end(); ++it)
|
||||
{
|
||||
if (it->family() == fam)
|
||||
{
|
||||
init(*it, portNumber);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw AddressFamilyMismatchException(hostAddress);
|
||||
}
|
||||
else throw HostNotFoundException("No address found for host", hostAddress);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SocketAddress::init(Family fam, const std::string& address)
|
||||
{
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
if (fam == UNIX_LOCAL)
|
||||
{
|
||||
newLocal(address);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
std::string host;
|
||||
std::string port;
|
||||
std::string::const_iterator it = address.begin();
|
||||
std::string::const_iterator end = address.end();
|
||||
|
||||
if (*it == '[')
|
||||
{
|
||||
++it;
|
||||
while (it != end && *it != ']') host += *it++;
|
||||
if (it == end) throw InvalidArgumentException("Malformed IPv6 address");
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (it != end && *it != ':') host += *it++;
|
||||
}
|
||||
if (it != end && *it == ':')
|
||||
{
|
||||
++it;
|
||||
while (it != end) port += *it++;
|
||||
}
|
||||
else throw InvalidArgumentException("Missing port number");
|
||||
init(fam, host, resolveService(port));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SocketAddress::init(const std::string& hostAndPort)
|
||||
{
|
||||
poco_assert (!hostAndPort.empty());
|
||||
|
||||
std::string host;
|
||||
std::string port;
|
||||
std::string::const_iterator it = hostAndPort.begin();
|
||||
std::string::const_iterator end = hostAndPort.end();
|
||||
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
if (*it == '/')
|
||||
{
|
||||
newLocal(hostAndPort);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (*it == '[')
|
||||
{
|
||||
++it;
|
||||
while (it != end && *it != ']') host += *it++;
|
||||
if (it == end) throw InvalidArgumentException("Malformed IPv6 address");
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (it != end && *it != ':') host += *it++;
|
||||
}
|
||||
if (it != end && *it == ':')
|
||||
{
|
||||
++it;
|
||||
while (it != end) port += *it++;
|
||||
}
|
||||
else throw InvalidArgumentException("Missing port number");
|
||||
init(host, resolveService(port));
|
||||
}
|
||||
|
||||
|
||||
Poco::UInt16 SocketAddress::resolveService(const std::string& service)
|
||||
{
|
||||
unsigned port;
|
||||
@@ -266,3 +409,29 @@ Poco::UInt16 SocketAddress::resolveService(const std::string& service)
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
|
||||
Poco::BinaryWriter& operator << (Poco::BinaryWriter& writer, const Poco::Net::SocketAddress& value)
|
||||
{
|
||||
writer << value.host();
|
||||
writer << value.port();
|
||||
return writer;
|
||||
}
|
||||
|
||||
|
||||
Poco::BinaryReader& operator >> (Poco::BinaryReader& reader, Poco::Net::SocketAddress& value)
|
||||
{
|
||||
Poco::Net::IPAddress host;
|
||||
reader >> host;
|
||||
Poco::UInt16 port;
|
||||
reader >> port;
|
||||
value = Poco::Net::SocketAddress(host, port);
|
||||
return reader;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator << (std::ostream& ostr, const Poco::Net::SocketAddress& address)
|
||||
{
|
||||
ostr << address.toString();
|
||||
return ostr;
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "Poco/Net/SocketAddressImpl.h"
|
||||
#include "Poco/Net/SocketDefs.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include <cstring>
|
||||
|
||||
|
||||
@@ -60,11 +61,22 @@ IPv4SocketAddressImpl::IPv4SocketAddressImpl(const void* addr, UInt16 port)
|
||||
{
|
||||
std::memset(&_addr, 0, sizeof(_addr));
|
||||
_addr.sin_family = AF_INET;
|
||||
poco_set_sin_len(&_addr);
|
||||
std::memcpy(&_addr.sin_addr, addr, sizeof(_addr.sin_addr));
|
||||
_addr.sin_port = port;
|
||||
}
|
||||
|
||||
|
||||
std::string IPv4SocketAddressImpl::toString() const
|
||||
{
|
||||
std::string result;
|
||||
result.append(host().toString());
|
||||
result.append(":");
|
||||
NumberFormatter::append(result, ntohs(port()));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
|
||||
|
||||
@@ -100,7 +112,59 @@ IPv6SocketAddressImpl::IPv6SocketAddressImpl(const void* addr, UInt16 port, UInt
|
||||
}
|
||||
|
||||
|
||||
std::string IPv6SocketAddressImpl::toString() const
|
||||
{
|
||||
std::string result;
|
||||
result.append("[");
|
||||
result.append(host().toString());
|
||||
result.append("]");
|
||||
result.append(":");
|
||||
NumberFormatter::append(result, ntohs(port()));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#endif // POCO_HAVE_IPv6
|
||||
|
||||
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
|
||||
|
||||
//
|
||||
// LocalSocketAddressImpl
|
||||
//
|
||||
|
||||
|
||||
LocalSocketAddressImpl::LocalSocketAddressImpl(const struct sockaddr_un* addr)
|
||||
{
|
||||
_pAddr = new sockaddr_un;
|
||||
std::memcpy(_pAddr, addr, sizeof(struct sockaddr_un));
|
||||
}
|
||||
|
||||
|
||||
LocalSocketAddressImpl::LocalSocketAddressImpl(const char* path)
|
||||
{
|
||||
_pAddr = new sockaddr_un;
|
||||
poco_set_sun_len(_pAddr, std::strlen(path) + sizeof(struct sockaddr_un) - sizeof(_pAddr->sun_path) + 1);
|
||||
_pAddr->sun_family = AF_UNIX;
|
||||
std::strcpy(_pAddr->sun_path, path);
|
||||
}
|
||||
|
||||
|
||||
LocalSocketAddressImpl::~LocalSocketAddressImpl()
|
||||
{
|
||||
delete _pAddr;
|
||||
}
|
||||
|
||||
|
||||
std::string LocalSocketAddressImpl::toString() const
|
||||
{
|
||||
std::string result(path());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#endif // POCO_OS_FAMILY_UNIX
|
||||
|
||||
|
||||
} } } // namespace Poco::Net::Impl
|
||||
|
@@ -31,6 +31,11 @@
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
using Poco::IOException;
|
||||
using Poco::TimeoutException;
|
||||
using Poco::InvalidArgumentException;
|
||||
@@ -42,16 +47,34 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
bool checkIsBrokenTimeout()
|
||||
{
|
||||
#if defined(POCO_BROKEN_TIMEOUTS)
|
||||
return true;
|
||||
#elif defined(POCO_OS_FAMILY_WINDOWS)
|
||||
// on Windows 7 and lower, socket timeouts have a minimum of 500ms, use poll for timeouts on this case
|
||||
// https://social.msdn.microsoft.com/Forums/en-US/76620f6d-22b1-4872-aaf0-833204f3f867/minimum-timeout-value-for-sorcvtimeo
|
||||
OSVERSIONINFO vi;
|
||||
vi.dwOSVersionInfoSize = sizeof(vi);
|
||||
if (GetVersionEx(&vi) == 0) return true; //throw SystemException("Cannot get OS version information");
|
||||
return vi.dwMajorVersion < 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion < 2);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
SocketImpl::SocketImpl():
|
||||
_sockfd(POCO_INVALID_SOCKET),
|
||||
_blocking(true)
|
||||
_blocking(true),
|
||||
_isBrokenTimeout(checkIsBrokenTimeout())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SocketImpl::SocketImpl(poco_socket_t sockfd):
|
||||
_sockfd(sockfd),
|
||||
_blocking(true)
|
||||
_blocking(true),
|
||||
_isBrokenTimeout(checkIsBrokenTimeout())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -165,16 +188,21 @@ void SocketImpl::connectNB(const SocketAddress& address)
|
||||
|
||||
|
||||
void SocketImpl::bind(const SocketAddress& address, bool reuseAddress)
|
||||
{
|
||||
bind(address, reuseAddress, true);
|
||||
}
|
||||
|
||||
|
||||
void SocketImpl::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
|
||||
{
|
||||
if (_sockfd == POCO_INVALID_SOCKET)
|
||||
{
|
||||
init(address.af());
|
||||
}
|
||||
if (reuseAddress)
|
||||
{
|
||||
setReuseAddress(true);
|
||||
if (reusePort)
|
||||
setReusePort(true);
|
||||
}
|
||||
#if defined(POCO_VXWORKS)
|
||||
int rc = ::bind(_sockfd, (sockaddr*) address.addr(), address.length());
|
||||
#else
|
||||
@@ -185,9 +213,15 @@ void SocketImpl::bind(const SocketAddress& address, bool reuseAddress)
|
||||
|
||||
|
||||
void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only)
|
||||
{
|
||||
bind6(address, reuseAddress, true, ipV6Only);
|
||||
}
|
||||
|
||||
|
||||
void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only)
|
||||
{
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
if (address.family() != IPAddress::IPv6)
|
||||
if (address.family() != SocketAddress::IPv6)
|
||||
throw Poco::InvalidArgumentException("SocketAddress must be an IPv6 address");
|
||||
|
||||
if (_sockfd == POCO_INVALID_SOCKET)
|
||||
@@ -200,10 +234,9 @@ void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV
|
||||
if (ipV6Only) throw Poco::NotImplementedException("IPV6_V6ONLY not defined.");
|
||||
#endif
|
||||
if (reuseAddress)
|
||||
{
|
||||
setReuseAddress(true);
|
||||
if (reusePort)
|
||||
setReusePort(true);
|
||||
}
|
||||
int rc = ::bind(_sockfd, address.addr(), address.length());
|
||||
if (rc != 0) error(address.toString());
|
||||
#else
|
||||
@@ -260,13 +293,14 @@ void SocketImpl::shutdown()
|
||||
|
||||
int SocketImpl::sendBytes(const void* buffer, int length, int flags)
|
||||
{
|
||||
#if defined(POCO_BROKEN_TIMEOUTS)
|
||||
if (_sndTimeout.totalMicroseconds() != 0)
|
||||
if (_isBrokenTimeout)
|
||||
{
|
||||
if (!poll(_sndTimeout, SELECT_WRITE))
|
||||
throw TimeoutException();
|
||||
if (_sndTimeout.totalMicroseconds() != 0)
|
||||
{
|
||||
if (!poll(_sndTimeout, SELECT_WRITE))
|
||||
throw TimeoutException();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int rc;
|
||||
do
|
||||
@@ -282,13 +316,14 @@ int SocketImpl::sendBytes(const void* buffer, int length, int flags)
|
||||
|
||||
int SocketImpl::receiveBytes(void* buffer, int length, int flags)
|
||||
{
|
||||
#if defined(POCO_BROKEN_TIMEOUTS)
|
||||
if (_recvTimeout.totalMicroseconds() != 0)
|
||||
if (_isBrokenTimeout)
|
||||
{
|
||||
if (!poll(_recvTimeout, SELECT_READ))
|
||||
throw TimeoutException();
|
||||
if (_recvTimeout.totalMicroseconds() != 0)
|
||||
{
|
||||
if (!poll(_recvTimeout, SELECT_READ))
|
||||
throw TimeoutException();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int rc;
|
||||
do
|
||||
@@ -331,13 +366,14 @@ int SocketImpl::sendTo(const void* buffer, int length, const SocketAddress& addr
|
||||
|
||||
int SocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
|
||||
{
|
||||
#if defined(POCO_BROKEN_TIMEOUTS)
|
||||
if (_recvTimeout.totalMicroseconds() != 0)
|
||||
if (_isBrokenTimeout)
|
||||
{
|
||||
if (!poll(_recvTimeout, SELECT_READ))
|
||||
throw TimeoutException();
|
||||
if (_recvTimeout.totalMicroseconds() != 0)
|
||||
{
|
||||
if (!poll(_recvTimeout, SELECT_READ))
|
||||
throw TimeoutException();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
char abuffer[SocketAddress::MAX_ADDRESS_LENGTH];
|
||||
struct sockaddr* pSA = reinterpret_cast<struct sockaddr*>(abuffer);
|
||||
@@ -555,11 +591,11 @@ void SocketImpl::setSendTimeout(const Poco::Timespan& timeout)
|
||||
#if defined(_WIN32) && !defined(POCO_BROKEN_TIMEOUTS)
|
||||
int value = (int) timeout.totalMilliseconds();
|
||||
setOption(SOL_SOCKET, SO_SNDTIMEO, value);
|
||||
#elif defined(POCO_BROKEN_TIMEOUTS)
|
||||
_sndTimeout = timeout;
|
||||
#else
|
||||
#elif !defined(POCO_BROKEN_TIMEOUTS)
|
||||
setOption(SOL_SOCKET, SO_SNDTIMEO, timeout);
|
||||
#endif
|
||||
if (_isBrokenTimeout)
|
||||
_sndTimeout = timeout;
|
||||
}
|
||||
|
||||
|
||||
@@ -570,11 +606,11 @@ Poco::Timespan SocketImpl::getSendTimeout()
|
||||
int value;
|
||||
getOption(SOL_SOCKET, SO_SNDTIMEO, value);
|
||||
result = Timespan::TimeDiff(value)*1000;
|
||||
#elif defined(POCO_BROKEN_TIMEOUTS)
|
||||
result = _sndTimeout;
|
||||
#else
|
||||
#elif !defined(POCO_BROKEN_TIMEOUTS)
|
||||
getOption(SOL_SOCKET, SO_SNDTIMEO, result);
|
||||
#endif
|
||||
if (_isBrokenTimeout)
|
||||
result = _sndTimeout;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -588,9 +624,9 @@ void SocketImpl::setReceiveTimeout(const Poco::Timespan& timeout)
|
||||
#else
|
||||
setOption(SOL_SOCKET, SO_RCVTIMEO, timeout);
|
||||
#endif
|
||||
#else
|
||||
_recvTimeout = timeout;
|
||||
#endif
|
||||
if (_isBrokenTimeout)
|
||||
_recvTimeout = timeout;
|
||||
}
|
||||
|
||||
|
||||
@@ -601,11 +637,11 @@ Poco::Timespan SocketImpl::getReceiveTimeout()
|
||||
int value;
|
||||
getOption(SOL_SOCKET, SO_RCVTIMEO, value);
|
||||
result = Timespan::TimeDiff(value)*1000;
|
||||
#elif defined(POCO_BROKEN_TIMEOUTS)
|
||||
result = _recvTimeout;
|
||||
#else
|
||||
#elif !defined(POCO_BROKEN_TIMEOUTS)
|
||||
getOption(SOL_SOCKET, SO_RCVTIMEO, result);
|
||||
#endif
|
||||
if (_isBrokenTimeout)
|
||||
result = _recvTimeout;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1060,6 +1096,8 @@ void SocketImpl::error(int code, const std::string& arg)
|
||||
throw IOException("Broken pipe", code);
|
||||
case EBADF:
|
||||
throw IOException("Bad socket descriptor", code);
|
||||
case ENOENT:
|
||||
throw IOException("Not found", arg, code);
|
||||
#endif
|
||||
default:
|
||||
throw IOException(NumberFormatter::format(code), arg, code);
|
||||
|
@@ -39,7 +39,7 @@ StreamSocket::StreamSocket(const SocketAddress& address): Socket(new StreamSocke
|
||||
}
|
||||
|
||||
|
||||
StreamSocket::StreamSocket(IPAddress::Family family): Socket(new StreamSocketImpl(family))
|
||||
StreamSocket::StreamSocket(SocketAddress::Family family): Socket(new StreamSocketImpl(family))
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -26,13 +26,17 @@ StreamSocketImpl::StreamSocketImpl()
|
||||
}
|
||||
|
||||
|
||||
StreamSocketImpl::StreamSocketImpl(IPAddress::Family family)
|
||||
StreamSocketImpl::StreamSocketImpl(SocketAddress::Family family)
|
||||
{
|
||||
if (family == IPAddress::IPv4)
|
||||
if (family == SocketAddress::IPv4)
|
||||
init(AF_INET);
|
||||
#if defined(POCO_HAVE_IPv6)
|
||||
else if (family == IPAddress::IPv6)
|
||||
else if (family == SocketAddress::IPv6)
|
||||
init(AF_INET6);
|
||||
#endif
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
else if (family == SocketAddress::UNIX_LOCAL)
|
||||
init(AF_UNIX);
|
||||
#endif
|
||||
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to StreamSocketImpl");
|
||||
}
|
||||
|
@@ -28,6 +28,21 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
//
|
||||
// TCPServerConnectionFilter
|
||||
//
|
||||
|
||||
|
||||
TCPServerConnectionFilter::~TCPServerConnectionFilter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// TCPServer
|
||||
//
|
||||
|
||||
|
||||
TCPServer::TCPServer(TCPServerConnectionFactory::Ptr pFactory, Poco::UInt16 portNumber, TCPServerParams::Ptr pParams):
|
||||
_socket(ServerSocket(portNumber)),
|
||||
_thread(threadName(_socket)),
|
||||
@@ -120,9 +135,18 @@ void TCPServer::run()
|
||||
try
|
||||
{
|
||||
StreamSocket ss = _socket.acceptConnection();
|
||||
// enabe nodelay per default: OSX really needs that
|
||||
ss.setNoDelay(true);
|
||||
_pDispatcher->enqueue(ss);
|
||||
|
||||
if (!_pConnectionFilter || _pConnectionFilter->accept(ss))
|
||||
{
|
||||
// enable nodelay per default: OSX really needs that
|
||||
#if defined(POCO_OS_FAMILY_UNIX)
|
||||
if (ss.address().family() != AddressFamily::UNIX_LOCAL)
|
||||
#endif
|
||||
{
|
||||
ss.setNoDelay(true);
|
||||
}
|
||||
_pDispatcher->enqueue(ss);
|
||||
}
|
||||
}
|
||||
catch (Poco::Exception& exc)
|
||||
{
|
||||
@@ -191,6 +215,14 @@ int TCPServer::refusedConnections() const
|
||||
}
|
||||
|
||||
|
||||
void TCPServer::setConnectionFilter(const TCPServerConnectionFilter::Ptr& pConnectionFilter)
|
||||
{
|
||||
poco_assert (_stopped);
|
||||
|
||||
_pConnectionFilter = pConnectionFilter;
|
||||
}
|
||||
|
||||
|
||||
std::string TCPServer::threadName(const ServerSocket& socket)
|
||||
{
|
||||
#if _WIN32_WCE == 0x0800
|
||||
|
@@ -19,7 +19,6 @@
|
||||
#include "Poco/Net/HTTPClientSession.h"
|
||||
#include "Poco/Net/HTTPServerSession.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Buffer.h"
|
||||
#include "Poco/MemoryStream.h"
|
||||
#include "Poco/NullStream.h"
|
||||
#include "Poco/BinaryWriter.h"
|
||||
@@ -113,6 +112,14 @@ int WebSocket::receiveFrame(void* buffer, int length, int& flags)
|
||||
}
|
||||
|
||||
|
||||
int WebSocket::receiveFrame(Poco::Buffer<char>& buffer, int& flags)
|
||||
{
|
||||
int n = static_cast<WebSocketImpl*>(impl())->receiveBytes(buffer, 0);
|
||||
flags = static_cast<WebSocketImpl*>(impl())->frameFlags();
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
WebSocket::Mode WebSocket::mode() const
|
||||
{
|
||||
return static_cast<WebSocketImpl*>(impl())->mustMaskPayload() ? WS_CLIENT : WS_SERVER;
|
||||
|
@@ -106,7 +106,7 @@ int WebSocketImpl::sendBytes(const void* buffer, int length, int flags)
|
||||
}
|
||||
|
||||
|
||||
int WebSocketImpl::receiveBytes(void* buffer, int length, int)
|
||||
int WebSocketImpl::receiveHeader(char mask[4], bool& useMask)
|
||||
{
|
||||
char header[MAX_HEADER_LENGTH];
|
||||
int n = receiveNBytes(header, 2);
|
||||
@@ -116,82 +116,101 @@ int WebSocketImpl::receiveBytes(void* buffer, int length, int)
|
||||
return n;
|
||||
}
|
||||
poco_assert (n == 2);
|
||||
Poco::UInt8 lengthByte = static_cast<Poco::UInt8>(header[1]);
|
||||
int maskOffset = 0;
|
||||
if (lengthByte & FRAME_FLAG_MASK) maskOffset += 4;
|
||||
lengthByte &= 0x7f;
|
||||
if (lengthByte > 0 || maskOffset > 0)
|
||||
{
|
||||
if (lengthByte + 2 + maskOffset < MAX_HEADER_LENGTH)
|
||||
{
|
||||
n = receiveNBytes(header + 2, lengthByte + maskOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = receiveNBytes(header + 2, MAX_HEADER_LENGTH - 2);
|
||||
}
|
||||
if (n <= 0) throw WebSocketException("Incomplete header received", WebSocket::WS_ERR_INCOMPLETE_FRAME);
|
||||
n += 2;
|
||||
}
|
||||
Poco::MemoryInputStream istr(header, n);
|
||||
Poco::BinaryReader reader(istr, Poco::BinaryReader::NETWORK_BYTE_ORDER);
|
||||
Poco::UInt8 flags;
|
||||
char mask[4];
|
||||
reader >> flags >> lengthByte;
|
||||
Poco::UInt8 flags = static_cast<Poco::UInt8>(header[0]);
|
||||
_frameFlags = flags;
|
||||
int payloadLength = 0;
|
||||
int payloadOffset = 2;
|
||||
if ((lengthByte & 0x7f) == 127)
|
||||
Poco::UInt8 lengthByte = static_cast<Poco::UInt8>(header[1]);
|
||||
useMask = ((lengthByte & FRAME_FLAG_MASK) != 0);
|
||||
int payloadLength;
|
||||
lengthByte &= 0x7f;
|
||||
if (lengthByte == 127)
|
||||
{
|
||||
n = receiveNBytes(header + 2, 8);
|
||||
if (n <= 0)
|
||||
{
|
||||
_frameFlags = 0;
|
||||
return n;
|
||||
}
|
||||
Poco::MemoryInputStream istr(header + 2, 8);
|
||||
Poco::BinaryReader reader(istr, Poco::BinaryReader::NETWORK_BYTE_ORDER);
|
||||
Poco::UInt64 l;
|
||||
reader >> l;
|
||||
if (l > length) throw WebSocketException(Poco::format("Insufficient buffer for payload size %Lu", l), WebSocket::WS_ERR_PAYLOAD_TOO_BIG);
|
||||
payloadLength = static_cast<int>(l);
|
||||
payloadOffset += 8;
|
||||
}
|
||||
else if ((lengthByte & 0x7f) == 126)
|
||||
else if (lengthByte == 126)
|
||||
{
|
||||
n = receiveNBytes(header + 2, 2);
|
||||
if (n <= 0)
|
||||
{
|
||||
_frameFlags = 0;
|
||||
return n;
|
||||
}
|
||||
Poco::MemoryInputStream istr(header + 2, 2);
|
||||
Poco::BinaryReader reader(istr, Poco::BinaryReader::NETWORK_BYTE_ORDER);
|
||||
Poco::UInt16 l;
|
||||
reader >> l;
|
||||
if (l > length) throw WebSocketException(Poco::format("Insufficient buffer for payload size %hu", l), WebSocket::WS_ERR_PAYLOAD_TOO_BIG);
|
||||
payloadLength = static_cast<int>(l);
|
||||
payloadOffset += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Poco::UInt8 l = lengthByte & 0x7f;
|
||||
if (l > length) throw WebSocketException(Poco::format("Insufficient buffer for payload size %u", unsigned(l)), WebSocket::WS_ERR_PAYLOAD_TOO_BIG);
|
||||
payloadLength = static_cast<int>(l);
|
||||
payloadLength = lengthByte;
|
||||
}
|
||||
if (lengthByte & FRAME_FLAG_MASK)
|
||||
|
||||
if (useMask)
|
||||
{
|
||||
reader.readRaw(mask, 4);
|
||||
payloadOffset += 4;
|
||||
n = receiveNBytes(mask, 4);
|
||||
if (n <= 0)
|
||||
{
|
||||
_frameFlags = 0;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
int received = 0;
|
||||
if (payloadOffset < n)
|
||||
|
||||
return payloadLength;
|
||||
}
|
||||
|
||||
|
||||
int WebSocketImpl::receivePayload(char *buffer, int payloadLength, char mask[4], bool useMask)
|
||||
{
|
||||
int received = receiveNBytes(reinterpret_cast<char*>(buffer), payloadLength);
|
||||
if (received <= 0) throw WebSocketException("Incomplete frame received", WebSocket::WS_ERR_INCOMPLETE_FRAME);
|
||||
|
||||
if (useMask)
|
||||
{
|
||||
std::memcpy(buffer, header + payloadOffset, n - payloadOffset);
|
||||
received = n - payloadOffset;
|
||||
}
|
||||
if (received < payloadLength)
|
||||
{
|
||||
n = receiveNBytes(reinterpret_cast<char*>(buffer) + received, payloadLength - received);
|
||||
if (n <= 0) throw WebSocketException("Incomplete frame received", WebSocket::WS_ERR_INCOMPLETE_FRAME);
|
||||
received += n;
|
||||
}
|
||||
if (lengthByte & FRAME_FLAG_MASK)
|
||||
{
|
||||
char* p = reinterpret_cast<char*>(buffer);
|
||||
for (int i = 0; i < received; i++)
|
||||
{
|
||||
p[i] ^= mask[i % 4];
|
||||
buffer[i] ^= mask[i % 4];
|
||||
}
|
||||
}
|
||||
return received;
|
||||
}
|
||||
|
||||
|
||||
int WebSocketImpl::receiveBytes(void* buffer, int length, int)
|
||||
{
|
||||
char mask[4];
|
||||
bool useMask;
|
||||
int payloadLength = receiveHeader(mask, useMask);
|
||||
if (payloadLength <= 0)
|
||||
return payloadLength;
|
||||
if (payloadLength > length)
|
||||
throw WebSocketException(Poco::format("Insufficient buffer for payload size %hu", payloadLength), WebSocket::WS_ERR_PAYLOAD_TOO_BIG);
|
||||
return receivePayload(reinterpret_cast<char*>(buffer), payloadLength, mask, useMask);
|
||||
}
|
||||
|
||||
|
||||
int WebSocketImpl::receiveBytes(Poco::Buffer<char>& buffer, int)
|
||||
{
|
||||
char mask[4];
|
||||
bool useMask;
|
||||
int payloadLength = receiveHeader(mask, useMask);
|
||||
if (payloadLength <= 0)
|
||||
return payloadLength;
|
||||
int oldSize = buffer.size();
|
||||
buffer.resize(oldSize + payloadLength);
|
||||
return receivePayload(buffer.begin() + oldSize, payloadLength, mask, useMask);
|
||||
}
|
||||
|
||||
|
||||
int WebSocketImpl::receiveNBytes(void* buffer, int bytes)
|
||||
{
|
||||
int received = receiveSomeBytes(reinterpret_cast<char*>(buffer), bytes);
|
||||
@@ -212,7 +231,7 @@ int WebSocketImpl::receiveNBytes(void* buffer, int bytes)
|
||||
|
||||
int WebSocketImpl::receiveSomeBytes(char* buffer, int bytes)
|
||||
{
|
||||
int n = static_cast<int>(_buffer.size() - _bufferOffset);
|
||||
int n = _buffer.size() - _bufferOffset;
|
||||
if (n > 0)
|
||||
{
|
||||
if (bytes < n) n = bytes;
|
||||
@@ -257,12 +276,24 @@ void WebSocketImpl::bind(const SocketAddress& address, bool reuseAddress)
|
||||
}
|
||||
|
||||
|
||||
void WebSocketImpl::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
|
||||
{
|
||||
throw Poco::InvalidAccessException("Cannot bind() a WebSocketImpl");
|
||||
}
|
||||
|
||||
|
||||
void WebSocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only)
|
||||
{
|
||||
throw Poco::InvalidAccessException("Cannot bind6() a WebSocketImpl");
|
||||
}
|
||||
|
||||
|
||||
void WebSocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only)
|
||||
{
|
||||
throw Poco::InvalidAccessException("Cannot bind6() a WebSocketImpl");
|
||||
}
|
||||
|
||||
|
||||
void WebSocketImpl::listen(int backlog)
|
||||
{
|
||||
throw Poco::InvalidAccessException("Cannot listen() on a WebSocketImpl");
|
||||
|
Reference in New Issue
Block a user