25#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
35 mRpc->buildFdSet(fdset);
47 return mRpc->isSane();
62 mTuple(ipAddr,port,ipVer,
TCP,
Data::Empty)
65 mFd = ::socket(ipVer ==
V4 ? PF_INET : PF_INET6, SOCK_STREAM, 0);
67 mFd = ::socket(PF_INET, SOCK_STREAM, 0);
74 ErrLog(<<
"XmlRpcServerBase::XmlRpcServerBase: Failed to create socket: " <<
strError(e));
79 DebugLog (<<
"XmlRpcServerBase::XmlRpcServerBase: Creating fd=" << (
int)mFd
80 << (ipVer ==
V4 ?
" V4/" :
" V6/") );
84 if (::setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, &on,
sizeof(on)))
86 if (::setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, (
const char*)&on,
sizeof(on)))
91 ErrLog(<<
"XmlRpcServerBase::XmlRpcServerBase: Couldn't set sockoptions SO_REUSEADDR: " <<
strError(e));
100 if ( ::setsockopt(mFd, IPPROTO_IPV6, IPV6_V6ONLY, &on,
sizeof(on)) )
104 ErrLog(<<
"XmlRpcServerBase::XmlRpcServerBase: Couldn't set sockoptions IPV6_V6ONLY: " <<
strError(e));
120 ErrLog(<<
"XmlRpcServerBase::XmlRpcServerBase: " << mTuple <<
" already in use ");
124 ErrLog(<<
"XmlRpcServerBase::XmlRpcServerBase: Could not bind to " << mTuple);
135 ErrLog(<<
"XmlRpcServerBase::XmlRpcServerBase: Could not make HTTP socket non-blocking " << port);
143 int e = listen(mFd,5);
148 InfoLog(<<
"XmlRpcServerBase::XmlRpcServerBase: Failed listen " <<
strError(e));
178 it->second->buildFdSet(fdset);
196 StackLog(<<
"outgoing message found");
242 bool ok = it->second->process(fdset);
262 socklen_t peerLen = tuple.
length();
263 Socket sock = accept( mFd, &peer, &peerLen);
270#if EAGAIN != EWOULDBLOCK
276 ErrLog(<<
"XmlRpcServerBase::process: Some error reading from socket: " << e);
284 closeOldestConnection();
290 DebugLog (<<
"XmlRpcServerBase::process: Received TCP connection as connection=" << connection->
getConnectionId() <<
" fd=" << (
int)sock);
296 unsigned int requestId,
297 const Data& responseData,
306 const Data& eventData)
319XmlRpcSocketServer::closeOldestConnection()
324 ConnectionMap::iterator lowestConnectionIdIt =
mConnections.end();
328 if(it->second->getConnectionId() < lowestConnectionIdIt->second->getConnectionId())
330 lowestConnectionIdIt = it;
333 delete lowestConnectionIdIt->second;
346 InfoLog (<<
"The call was interrupted by a signal before any data was read : " <<
strError(e));
352 InfoLog (<<
"fd is not a valid file descriptor or is not open for reading : " <<
strError(e));
355 InfoLog (<<
"fd is attached to an object which is unsuitable for reading : " <<
strError(e));
358 InfoLog (<<
"buf is outside your accessible address space : " <<
strError(e));
363 InfoLog (<<
" The network subsystem has failed. ");
366 InfoLog (<<
" The buf or from parameters are not part of the user address space, "
367 "or the fromlen parameter is too small to accommodate the peer address. ");
370 InfoLog (<<
" The (blocking) call was canceled through WSACancelBlockingCall. ");
373 InfoLog (<<
" A blocking Windows Sockets 1.1 call is in progress, or the "
374 "service provider is still processing a callback function. ");
377 InfoLog (<<
" The socket has not been bound with bind, or an unknown flag was specified, "
378 "or MSG_OOB was specified for a socket with SO_OOBINLINE enabled, "
379 "or (for byte stream-style sockets only) len was zero or negative. ");
382 InfoLog (<<
"The socket is connected. This function is not permitted with a connected socket, "
383 "whether the socket is connection-oriented or connectionless. ");
386 InfoLog (<<
" The connection has been broken due to the keep-alive activity "
387 "detecting a failure while the operation was in progress. ");
390 InfoLog (<<
"The descriptor is not a socket. ");
393 InfoLog (<<
" MSG_OOB was specified, but the socket is not stream-style such as type "
394 "SOCK_STREAM, OOB data is not supported in the communication domain associated with this socket, "
395 "or the socket is unidirectional and supports only send operations. ");
398 InfoLog (<<
"The socket has been shut down; it is not possible to recvfrom on a socket after "
399 "shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH. ");
402 InfoLog (<<
" The message was too large to fit into the specified buffer and was truncated. ");
405 InfoLog (<<
" The connection has been dropped, because of a network failure or because the "
406 "system on the other end went down without notice. ");
409 InfoLog (<<
"Connection reset ");
416 case WSAEHOSTUNREACH:
417 InfoLog (<<
"A socket operation was attempted to an unreachable host ");
420 InfoLog (<<
"Either the application has not called WSAStartup or WSAStartup failed. "
421 "The application may be accessing a socket that the current active task does not own (that is, trying to share a socket between tasks),"
422 "or WSACleanup has been called too many times. ");
425 InfoLog (<<
"An attempt was made to access a socket in a way forbidden by its access permissions ");
428 InfoLog (<<
"An operation on a socket could not be performed because the system lacked sufficient "
429 "buffer space or because a queue was full");
432 InfoLog (<<
"A request to send or receive data was disallowed because the socket is not connected "
433 "and (when sending on a datagram socket using sendto) no address was supplied");
435 case WSAECONNABORTED:
436 InfoLog (<<
"An established connection was aborted by the software in your host computer, possibly "
437 "due to a data transmission time-out or protocol error");
439 case WSAEADDRNOTAVAIL:
440 InfoLog (<<
"The requested address is not valid in its context. This normally results from an attempt to "
441 "bind to an address that is not valid for the local computer");
443 case WSAEAFNOSUPPORT:
444 InfoLog (<<
"An address incompatible with the requested protocol was used");
446 case WSAEDESTADDRREQ:
447 InfoLog (<<
"A required address was omitted from an operation on a socket");
450 InfoLog (<<
"A socket operation was attempted to an unreachable network");
461#ifdef BUILD_QPID_PROTON
466 std::chrono::seconds(60),
467 std::chrono::seconds(2)),
468 mBrokerUrl(brokerUrl),
474 InfoLog(<<
"XmlRpcServerBase::XmlRpcServerBase: using Qpid Proton AMQP to send to " << brokerUrl);
477XmlRpcProtonServer::~XmlRpcProtonServer()
479 if(mQpidProtonThread.get())
482 mQpidProtonThread->shutdown();
483 mQpidProtonThread->join();
496 mQpidProtonThread->addReceiver(shared_from_this());
498 mQpidProtonThread->run();
507 StackLog(<<
"processIncoming invoked");
514 std::unique_ptr<proton::message> m(fifo.
getNext());
515 Data replyTo(m->reply_to());
516 StackLog(<<
"reply to: " << m->reply_to());
517 auto it = mQueueConnection.find(replyTo);
518 unsigned int connectionId;
519 XmlRpcProtonConnection* connection =
nullptr;
520 if(it == mQueueConnection.end())
523 std::shared_ptr<ProtonThreadBase::ProtonSenderBase> sender = mQpidProtonThread->getSenderForReply(m->reply_to());
524 connection =
new XmlRpcProtonConnection(*
this, replyTo, sender);
525 connectionId = connection->getConnectionId();
526 mConnections[connectionId] = connection;
527 mQueueConnection[replyTo] = connectionId;
531 connectionId = it->second;
532 StackLog(<<
"existing client: " << connectionId);
533 connection =
dynamic_cast<XmlRpcProtonConnection*
>(mConnections[connectionId]);
536 ErrLog(<<
"invalid connectionId: " << connectionId <<
" for queue " << replyTo);
539 unsigned int requestId = connection->getNextRequestId();
540 Data requestBody =
Data(proton::get<std::string>(m->body()));
541 connection->onRequest(requestId, requestBody);
542 StackLog(<<
"message received: " << requestBody);
543 handleRequest(connectionId, requestId, requestBody);
544 StackLog(<<
"message handled, requestId = " << requestId);
548 ErrLog(<<
"exception while parsing the XML");
Handles cross-platform sockets compatibility.
#define WSANOTINITIALISED
bool getIsFinal() const noexcept
unsigned int getConnectionId() const noexcept
unsigned int getRequestId() const noexcept
const resip::Data & getResponseData() const noexcept
unsigned int getConnectionId() const
virtual void buildFdSet(resip::FdSet &fdset)
void process(resip::FdSet &fdset)
std::shared_ptr< XmlRpcServerBase > mRpc
XmlRpcServerBase(XmlRpcHandler &h)
void process(resip::FdSet &fdset)
resip::SelectInterruptor mSelectInterruptor
virtual ~XmlRpcServerBase()
ConnectionMap mConnections
virtual void buildFdSet(resip::FdSet &fdset)
virtual void sendEvent(unsigned int connectionId, const resip::Data &eventData)
resip::Fifo< ResponseInfo > mResponseFifo
virtual void sendResponse(unsigned int connectionId, unsigned int requestId, const resip::Data &responseData, bool isFinal=true)
virtual void processIncoming(resip::FdSet &fdset)=0
XmlRpcSocketServer(XmlRpcHandler &h, int port, resip::IpVersion version, resip::Data ipAddr=resip::Data::Empty)
static void logSocketError(int e)
virtual ~XmlRpcSocketServer()
virtual void buildFdSet(resip::FdSet &fdset)
void processIncoming(resip::FdSet &fdset)
bool messageAvailable() const
is a message available?
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
const char * c_str() const
Returns a null-terminated string representing.
Object-oriented wrapper for your platform's file-descriptor set.
bool readyToRead(Socket fd)
void process(FdSet &fdset)
cleanup signalled fd
void interrupt()
cause the 'artificial' fd to signal
void buildFdSet(FdSet &fdset)
Used to add the 'artificial' fd to the fdset that will be responsible for interrupting a subsequent s...
Msg * getNext()
Returns the first message available.
Represents a network address.
sockaddr & getMutableSockaddr()
Retrieve the binary representation of the socket address for this tuple.
static Data inet_ntop(const Tuple &tuple)
Converts the binary socket address to presentation format, via the DnsUtil::inet_ntop() method.
This Class is used to implement a primitive form of RPC using loose XML formatting.
dcm! – add UnusedChecking(_enum) below;
std::string strError(int err)
IpVersion
An enumeration of IP versions.
bool makeSocketNonBlocking(Socket fd)