mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-01-19 12:07:13 +01:00
4a6bfc086c
Switched to POCO library for unified platform/library interface. Deprecated the external module API. It was creating more problems than solving. Removed most built-in libraries in favor of system libraries for easier maintenance. Cleaned and secured code with help from static analyzers.
223 lines
6.2 KiB
C++
223 lines
6.2 KiB
C++
//
|
|
// UDPSocketReader.h
|
|
//
|
|
// Library: Net
|
|
// Package: UDP
|
|
// Module: UDPSocketReader
|
|
//
|
|
// Definition of the UDPSocketReader class.
|
|
//
|
|
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
|
|
// and Contributors.
|
|
//
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
//
|
|
|
|
|
|
#ifndef Net_UDPSocketReader_INCLUDED
|
|
#define Net_UDPSocketReader_INCLUDED
|
|
|
|
|
|
#include "Poco/Net/Net.h"
|
|
#include "Poco/Net/DatagramSocket.h"
|
|
|
|
|
|
namespace Poco {
|
|
namespace Net {
|
|
|
|
|
|
template <std::size_t S = POCO_UDP_BUF_SIZE>
|
|
class UDPSocketReader
|
|
/// UDPSocketReader is responsible for UDP socket I/O operations.
|
|
/// When data or error is detected on a socket, the reader is invoked
|
|
/// to do the I/O. After the data is read, it is passed on, to one
|
|
/// of the handlers for processing. Errors are also passed to a
|
|
/// handler for handling (if any configured).
|
|
/// Depending on settings, data senders may be notified of the handler's
|
|
/// data and error backlogs.
|
|
{
|
|
private:
|
|
class Counter
|
|
{
|
|
public:
|
|
Counter(): val(0)
|
|
{
|
|
}
|
|
|
|
operator AtomicCounter::ValueType ()
|
|
{
|
|
return static_cast<AtomicCounter::ValueType>(val);
|
|
}
|
|
|
|
Counter& operator=(AtomicCounter::ValueType value)
|
|
{
|
|
val = static_cast<Poco::Int32>(value);
|
|
return *this;
|
|
}
|
|
|
|
Poco::Int32 operator++()
|
|
{
|
|
return ++val;
|
|
}
|
|
|
|
Counter& operator++(int)
|
|
{
|
|
return val++;
|
|
}
|
|
|
|
private:
|
|
Poco::Int32 val;
|
|
};
|
|
|
|
public:
|
|
UDPSocketReader(typename UDPHandlerImpl<S>::List& handlers, int backlogThreshold = 0):
|
|
_handlers(handlers),
|
|
_handler(_handlers.begin()),
|
|
_backlogThreshold(backlogThreshold)
|
|
/// Creates the UDPSocketReader.
|
|
{
|
|
poco_assert(_handler != _handlers.end());
|
|
}
|
|
|
|
UDPSocketReader(typename UDPHandlerImpl<S>::List& handlers, const UDPServerParams& serverParams):
|
|
_handlers(handlers),
|
|
_handler(_handlers.begin()),
|
|
_backlogThreshold(serverParams.backlogThreshold())
|
|
/// Creates the UDPSocketReader.
|
|
{
|
|
poco_assert(_handler != _handlers.end());
|
|
}
|
|
|
|
~UDPSocketReader()
|
|
/// Destroys the UDPSocketReader.
|
|
{
|
|
}
|
|
|
|
void read(DatagramSocket& sock)
|
|
/// Reads data from the socket and passes it to the next handler.
|
|
/// Errors are also passed to the handler. If object is configured
|
|
/// for replying to sender and data or error backlog threshold is
|
|
/// exceeded, sender is notified of the current backlog size.
|
|
{
|
|
typedef typename UDPHandlerImpl<S>::MsgSizeT RT;
|
|
char* p = 0;
|
|
struct sockaddr* pSA = 0;
|
|
poco_socklen_t* pAL = 0;
|
|
poco_socket_t sockfd = sock.impl()->sockfd();
|
|
nextHandler();
|
|
try
|
|
{
|
|
p = handler().next(sockfd);
|
|
if (p)
|
|
{
|
|
Poco::UInt16 off = handler().offset();
|
|
poco_socklen_t* pAL = reinterpret_cast<poco_socklen_t*>(p + sizeof(RT));
|
|
*pAL = SocketAddress::MAX_ADDRESS_LENGTH;
|
|
struct sockaddr* pSA = reinterpret_cast<struct sockaddr*>(p + sizeof(RT) + sizeof(poco_socklen_t));
|
|
RT ret = sock.receiveFrom(p + off, S - off - 1, &pSA, &pAL);
|
|
if (ret < 0)
|
|
{
|
|
AtomicCounter::ValueType errors = setError(sock.impl()->sockfd(), p, Error::getMessage(Error::last()));
|
|
if (_backlogThreshold > 0 && errors > _backlogThreshold && errors != _errorBacklog[sockfd])
|
|
{
|
|
Poco::Int32 err = static_cast<Poco::Int32>(errors);
|
|
sock.sendTo(&err, sizeof(Poco::Int32), SocketAddress(pSA, *pAL));
|
|
_errorBacklog[sockfd] = errors;
|
|
}
|
|
return;
|
|
}
|
|
AtomicCounter::ValueType data = handler().setData(p, ret);
|
|
p[off + ret] = 0; // for ascii convenience, zero-terminate
|
|
if (_backlogThreshold > 0 && data > _backlogThreshold && data != _dataBacklog[sockfd])
|
|
{
|
|
Poco::Int32 d = static_cast<Poco::Int32>(data);
|
|
sock.sendTo(&d, sizeof(Poco::Int32), SocketAddress(pSA, *pAL));
|
|
_dataBacklog[sockfd] = data;
|
|
}
|
|
}
|
|
else return;
|
|
}
|
|
catch (Poco::Exception& exc)
|
|
{
|
|
AtomicCounter::ValueType errors = setError(sock.impl()->sockfd(), p, exc.displayText());
|
|
if (_backlogThreshold > 0 && errors > _backlogThreshold && errors != _errorBacklog[sockfd] && pSA && pAL)
|
|
{
|
|
Poco::Int32 err = static_cast<Poco::Int32>(errors);
|
|
sock.sendTo(&err, sizeof(Poco::Int32), SocketAddress(pSA, *pAL));
|
|
_errorBacklog[sockfd] = errors;
|
|
}
|
|
}
|
|
handler().notify();
|
|
}
|
|
|
|
bool handlerStopped() const
|
|
/// Returns true if all handlers are stopped.
|
|
{
|
|
bool stopped = true;
|
|
typename UDPHandlerImpl<S>::List::iterator it = _handlers.begin();
|
|
typename UDPHandlerImpl<S>::List::iterator end = _handlers.end();
|
|
for (; it != end; ++it) stopped = stopped && (*it)->stopped();
|
|
return stopped;
|
|
}
|
|
|
|
void stopHandler()
|
|
/// Stops all handlers.
|
|
{
|
|
typename UDPHandlerImpl<S>::List::iterator it = _handlers.begin();
|
|
typename UDPHandlerImpl<S>::List::iterator end = _handlers.end();
|
|
for (; it != end; ++it) (*it)->stop();
|
|
}
|
|
|
|
bool handlerDone() const
|
|
/// Returns true if all handlers are done processing data.
|
|
{
|
|
bool done = true;
|
|
typename UDPHandlerImpl<S>::List::iterator it = _handlers.begin();
|
|
typename UDPHandlerImpl<S>::List::iterator end = _handlers.end();
|
|
for (; it != end; ++it) done = done && (*it)->done();
|
|
return done;
|
|
}
|
|
|
|
AtomicCounter::ValueType setError(poco_socket_t sock, char* buf = 0, const std::string& err = "")
|
|
/// Sets error to the provided buffer buf. If the buffer is null, a new buffer is obtained
|
|
/// from handler.
|
|
/// If successful, returns the handler's eror backlog size, otherwise returns zero.
|
|
{
|
|
if (!buf) buf = handler().next(sock);
|
|
if (buf) return handler().setError(buf, err.empty() ? Error::getMessage(Error::last()) : err);
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
void nextHandler()
|
|
/// Re-points the handler iterator to the next handler in
|
|
/// round-robin fashion.
|
|
{
|
|
poco_assert_dbg (_handler != _handlers.end());
|
|
if (++_handler == _handlers.end()) _handler = _handlers.begin();
|
|
}
|
|
|
|
UDPHandlerImpl<S>& handler()
|
|
/// Returns the reference to the current handler.
|
|
{
|
|
poco_assert_dbg (_handler != _handlers.end());
|
|
return **_handler;
|
|
}
|
|
|
|
typedef typename UDPHandlerImpl<S>::List HandlerList;
|
|
typedef typename UDPHandlerImpl<S>::List::iterator HandlerIterator;
|
|
typedef std::map<poco_socket_t, Counter> CounterMap;
|
|
|
|
HandlerList& _handlers;
|
|
HandlerIterator _handler;
|
|
CounterMap _dataBacklog;
|
|
CounterMap _errorBacklog;
|
|
int _backlogThreshold;
|
|
};
|
|
|
|
|
|
} } // namespace Poco::Net
|
|
|
|
|
|
#endif // Net_UDPSocketReader_INCLUDED
|