reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
XmlRpcConnection.cxx
Go to the documentation of this file.
1#include "rutil/ResipAssert.h"
2
3#include <rutil/Data.hxx>
4#include <rutil/Socket.hxx>
7#include <rutil/Logger.hxx>
9#include <rutil/DnsUtil.hxx>
10#include <rutil/ParseBuffer.hxx>
11
14
15using namespace repro;
16using namespace resip;
17using namespace std;
18
19#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
20
21std::atomic<unsigned int> XmlRpcConnectionBase::NextConnectionId(1);
22
24 mXmlRcpServer(server),
25 mConnectionId(NextConnectionId++),
26 mNextRequestId(1)
27{
28}
29
33
40
41
43{
44 resip_assert(mSock > 0);
45#ifdef WIN32
46 closesocket(mSock);
47#else
48 close(mSock);
49#endif
50 mSock=0;
51}
52
53
54void
56{
57 if (!mTxBuffer.empty())
58 {
59 fdset.setWrite(mSock);
60 }
61 fdset.setRead(mSock);
62}
63
64
65bool
67{
68 if (fdset.hasException(mSock))
69 {
70 int errNum = 0;
71 int errNumSize = sizeof(errNum);
72 getsockopt(mSock,SOL_SOCKET,SO_ERROR,(char *)&errNum,(socklen_t *)&errNumSize);
73 InfoLog (<< "XmlRpcSocketConnection::process: Exception reading from socket "
74 << (int)mSock << " code: " << errNum << "; closing connection");
75 return false;
76 }
77
78 if (fdset.readyToRead(mSock))
79 {
80 bool ok = processSomeReads();
81 if (!ok)
82 {
83 return false;
84 }
85 }
86 if ((!mTxBuffer.empty()) && fdset.readyToWrite(mSock))
87 {
88 bool ok = processSomeWrites();
89 if (!ok)
90 {
91 return false;
92 }
93 }
94
95 return true;
96}
97
98bool
99XmlRpcSocketConnection::processSomeReads()
100{
101 const int bufSize = 8000;
102 char buf[bufSize];
103
104
105#if defined(WIN32)
106 int bytesRead = ::recv(mSock, buf, bufSize, 0);
107#else
108 int bytesRead = ::read(mSock, buf, bufSize);
109#endif
110
111 if (bytesRead == INVALID_SOCKET)
112 {
113 int e = getErrno();
115 InfoLog (<< "XmlRpcSocketConnection::processSomeReads: Failed read on " << (int)mSock);
116 return false;
117 }
118 else if(bytesRead == 0)
119 {
120 DebugLog (<< "XmlRpcSocketConnection::processSomeReads: Connection closed by remote");
121 return false;
122 }
123
124 //DebugLog (<< "XmlRpcSocketConnection::processSomeReads: read=" << bytesRead);
125
126 mRxBuffer += Data( buf, bytesRead );
127
128 while(tryParse());
129
130 return true;
131}
132
133
134bool
135XmlRpcSocketConnection::tryParse()
136{
137 ParseBuffer pb(mRxBuffer);
138 Data initialTag;
139 const char* start = pb.position();
140 pb.skipWhitespace();
141 pb.skipToChar('<');
142 if(!pb.eof())
143 {
144 pb.skipChar();
145 const char* anchor = pb.position();
146 pb.skipToChar('>');
147 if(!pb.eof())
148 {
149 initialTag = pb.data(anchor);
150 // Find end of initial tag
151 pb.skipToChars("</" + initialTag + ">");
152 if (!pb.eof())
153 {
154 pb.skipN(initialTag.size() + 3); // Skip past </InitialTag>
155 unsigned int requestId = getNextRequestId();
156 mRequests[requestId] = pb.data(start);
157 mXmlRcpServer.handleRequest(getConnectionId(), requestId, mRequests[requestId]);
158
159 // Remove processed data from RxBuffer
160 pb.skipWhitespace();
161 if(!pb.eof())
162 {
163 anchor = pb.position();
164 pb.skipToEnd();
165 mRxBuffer = pb.data(anchor);
166 return true;
167 }
168 else
169 {
170 mRxBuffer.clear();
171 }
172 }
173 }
174 }
175 return false;
176}
177
178bool
179XmlRpcSocketConnection::processSomeWrites()
180{
181 if (mTxBuffer.empty())
182 {
183 return true;
184 }
185
186 //DebugLog (<< "XmlRpcSocketConnection::processSomeWrites: Writing " << mTxBuffer );
187
188#if defined(WIN32)
189 int bytesWritten = ::send(mSock, mTxBuffer.data(), (int)mTxBuffer.size(), 0);
190#else
191 int bytesWritten = ::write(mSock, mTxBuffer.data(), mTxBuffer.size() );
192#endif
193
194 if (bytesWritten == INVALID_SOCKET)
195 {
196 int e = getErrno();
198 InfoLog (<< "XmlRpcSocketConnection::processSomeWrites - failed write on " << mSock << " " << strError(e));
199
200 return false;
201 }
202
203 if (bytesWritten == (int)mTxBuffer.size())
204 {
205 DebugLog (<< "XmlRpcSocketConnection::processSomeWrites - Wrote it all" );
206 mTxBuffer = Data::Empty;
207
208 //return false; // return false causes connection to close and clean up
209 return true; // keep connection up
210 }
211 else
212 {
213 Data rest = mTxBuffer.substr(bytesWritten);
214 mTxBuffer = rest;
215 DebugLog( << "XmlRpcSocketConnection::processSomeWrites - Wrote " << bytesWritten << " bytes - still need to do " << mTxBuffer );
216 }
217
218 return true;
219}
220
221bool
222XmlRpcConnectionBase::sendResponse(unsigned int requestId, const Data& responseData, bool isFinal)
223{
224 RequestMap::iterator it = mRequests.find(requestId);
225 if(it != mRequests.end())
226 {
227 Data& request = it->second;
228 Data response(request.size() + responseData.size() + 30, Data::Preallocate);
229 ParseBuffer pb(request);
230
231 // A response is formed by starting with the request and inserting the
232 // ResponseData between <Response> tags at the same level as the <Request> tags
233 const char* start = pb.position();
234 pb.skipToChars("</Request>");
235 if (!pb.eof())
236 {
237 pb.skipN(10); // Skip past </Request>
238 pb.skipWhitespace();
239
240 // Response starts with request message up to end of Request tag
241 response = pb.data(start);
242
243 // Add in response data
244 response += Symbols::CRLF;
245 response += " <Response>" + responseData + " </Response>";
246 response += Symbols::CRLF;
247
248 // Add remainder of request message
249 start = pb.position();
250 pb.skipToEnd();
251 response += pb.data(start);
252 }
253 else
254 {
255 // No Request in message - just send bare response
256 response = "<Response>" + responseData + "</Response>";
257 }
258 sendResponse(response);
259 if(isFinal)
260 {
261 mRequests.erase(it);
262 }
263 return true;
264 }
265 return false;
266}
267
268void
270{
271 mTxBuffer += response;
272}
273
274void
276{
277 mTxBuffer += eventData;
278}
279
280#ifdef BUILD_QPID_PROTON
281
282XmlRpcProtonConnection::XmlRpcProtonConnection(XmlRpcProtonServer& server, const resip::Data& replyTo,
283 std::shared_ptr<ProtonThreadBase::ProtonSenderBase> sender) :
284 XmlRpcConnectionBase(server),
285 mReplyTo(replyTo),
286 mSender(sender)
287{
288}
289
290XmlRpcProtonConnection::~XmlRpcProtonConnection()
291{
292}
293
294void
295XmlRpcProtonConnection::onRequest(unsigned int requestId, const resip::Data& request)
296{
297 mRequests[requestId] = request;
298}
299
300void
301XmlRpcProtonConnection::buildFdSet(resip::FdSet& fdset)
302{
303 // no need to do anything here, Qpid Proton has its own threads
304}
305
306bool
307XmlRpcProtonConnection::process(resip::FdSet& fdset)
308{
309 // no need to do anything here, Qpid Proton has its own threads
310 StackLog(<<"process invoked");
311 return true;
312}
313
314void
315XmlRpcProtonConnection::sendResponse(const resip::Data& responseData)
316{
317 StackLog(<<"sending via Proton: " << responseData);
318 mSender->sendMessage(responseData);
319}
320
321void
322XmlRpcProtonConnection::sendEvent(const resip::Data& eventData)
323{
324 StackLog(<<"sending via Proton: " << eventData);
325 mSender->sendMessage(eventData);
326}
327
328#endif
329
330
331/* ====================================================================
332 * The Vovida Software License, Version 1.0
333 *
334 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
335 * Copyright (c) 2010 SIP Spectrum, Inc. All rights reserved.
336 * Copyright (c) 2022 Daniel Pocock https://danielpocock.com
337 * Copyright (c) 2022 Software Freedom Institute LLC https://softwarefreedom.institute
338 *
339 * Redistribution and use in source and binary forms, with or without
340 * modification, are permitted provided that the following conditions
341 * are met:
342 *
343 * 1. Redistributions of source code must retain the above copyright
344 * notice, this list of conditions and the following disclaimer.
345 *
346 * 2. Redistributions in binary form must reproduce the above copyright
347 * notice, this list of conditions and the following disclaimer in
348 * the documentation and/or other materials provided with the
349 * distribution.
350 *
351 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
352 * and "Vovida Open Communication Application Library (VOCAL)" must
353 * not be used to endorse or promote products derived from this
354 * software without prior written permission. For written
355 * permission, please contact vocal@vovida.org.
356 *
357 * 4. Products derived from this software may not be called "VOCAL", nor
358 * may "VOCAL" appear in their name, without prior written
359 * permission of Vovida Networks, Inc.
360 *
361 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
362 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
363 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
364 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
365 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
366 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
367 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
368 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
369 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
370 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
371 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
372 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
373 * DAMAGE.
374 *
375 * ====================================================================
376 *
377 * This software consists of voluntary contributions made by Vovida
378 * Networks, Inc. and many individuals on behalf of Vovida Networks,
379 * Inc. For more information on Vovida Networks, Inc., please see
380 * <http://www.vovida.org/>.
381 *
382 */
383
#define DebugLog(args_)
Definition Logger.hxx:128
#define StackLog(args_)
Definition Logger.hxx:125
#define InfoLog(args_)
Definition Logger.hxx:131
#define resip_assert(x)
This file needs to work for both C and C++ code.
Handles cross-platform sockets compatibility.
#define INVALID_SOCKET
Definition Socket.hxx:95
static int getErrno()
virtual bool sendResponse(unsigned int requestId, const resip::Data &responseData, bool isFinal)
unsigned int getConnectionId() const
XmlRpcConnectionBase(XmlRpcServerBase &server)
virtual void handleRequest(unsigned int connectionId, unsigned int requestId, const resip::Data &request)
virtual void sendResponse(const resip::Data &response)
virtual bool process(resip::FdSet &fdset)
virtual void buildFdSet(resip::FdSet &fdset)
XmlRpcSocketConnection(XmlRpcSocketServer &server, resip::Socket sock)
virtual void sendEvent(const resip::Data &eventData)
static void logSocketError(int e)
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
static const Data Empty
Constant that represents a zero-length data.
Definition Data.hxx:882
static const PreallocateType Preallocate
used only to disambiguate constructors
Definition Data.hxx:116
Data substr(size_type first, size_type count=Data::npos) const
Copies a portion of this Data into a new Data.
Definition Data.cxx:1932
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
Data & clear()
Clears the contents of this Data.
Definition Data.hxx:800
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
Object-oriented wrapper for your platform's file-descriptor set.
Definition Socket.hxx:162
bool readyToWrite(Socket fd)
Definition Socket.hxx:194
bool readyToRead(Socket fd)
Definition Socket.hxx:189
void setRead(Socket fd)
Definition Socket.hxx:204
bool hasException(Socket fd)
Definition Socket.hxx:199
void setWrite(Socket fd)
Definition Socket.hxx:216
Provides string-parsing functionality with protection from buffer overflow.
CurrentPosition skipToEnd()
CurrentPosition skipWhitespace()
CurrentPosition skipToChars(const char *cs)
CurrentPosition position() const
CurrentPosition skipN(size_t count)
void data(Data &data, const char *start) const
make the passed in data share memory with the buffer (uses Data::Share)
static const char * CRLF
Definition Symbols.hxx:21
This Class is used to implement a primitive form of RPC using loose XML formatting.
dcm! – add UnusedChecking(_enum) below;
int Socket
Definition Socket.hxx:94
std::string strError(int err)
Definition compat.hxx:274