reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
RegSyncServer.cxx
Go to the documentation of this file.
1#if defined(HAVE_CONFIG_H)
2#include "config.h"
3#endif
4
5#include <sstream>
6
9#include <rutil/ResipAssert.h>
10#include <rutil/Data.hxx>
11#include <rutil/DnsUtil.hxx>
12#include <rutil/Logger.hxx>
13#include <rutil/ParseBuffer.hxx>
14#include <rutil/Socket.hxx>
16#include <rutil/Timer.hxx>
17
21
22using namespace repro;
23using namespace resip;
24using namespace std;
25
26#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
27
28
30 int port,
31 IpVersion version,
33 XmlRpcHandler(std::unique_ptr<XmlRpcServerBase>(new XmlRpcSocketServer(*this, port, version))),
34 mRegDb(regDb),
35 mPubDb(pubDb)
36{
37 if (mRegDb)
38 {
39 mRegDb->addHandler(this);
40 }
41 if (mPubDb)
42 {
43 mPubDb->addHandler(this);
44 }
45}
46
47#ifdef BUILD_QPID_PROTON
49 const resip::Data& brokerQueue,
51 XmlRpcHandler(std::unique_ptr<XmlRpcProtonServer>(new XmlRpcProtonServer(*this, brokerQueue, true))),
52 mRegDb(regDb),
53 mPubDb(pubDb)
54{
55 if (mRegDb)
56 {
57 mRegDb->addHandler(this);
58 }
59 if (mPubDb)
60 {
61 mPubDb->addHandler(this);
62 }
63}
64#endif
65
67{
68 if (mRegDb)
69 {
70 mRegDb->removeHandler(this);
71 }
72 if (mPubDb)
73 {
74 mPubDb->removeHandler(this);
75 }
76}
77
78void
79RegSyncServer::sendResponse(unsigned int connectionId,
80 unsigned int requestId,
81 const Data& responseData,
82 unsigned int resultCode,
83 const Data& resultText)
84{
85 std::stringstream ss;
86 ss << Symbols::CRLF << responseData << " <Result Code=\"" << resultCode << "\"";
87 ss << ">" << resultText.xmlCharDataEncode() << "</Result>" << Symbols::CRLF;
88 mRpc->sendResponse(connectionId, requestId, ss.str().c_str(), resultCode >= 200 /* isFinal */);
89}
90
91void
92RegSyncServer::sendRegistrationModifiedEvent(unsigned int connectionId, const resip::Uri& aor)
93{
94 ContactList contacts;
95
96 mRegDb->getContacts(aor, contacts);
97 sendRegistrationModifiedEvent(connectionId, aor, contacts);
98}
99
100void
101RegSyncServer::sendRegistrationModifiedEvent(unsigned int connectionId, const resip::Uri& aor, const ContactList& contacts)
102{
103 std::stringstream ss;
104 bool infoFound = false;
105
106 ss << "<reginfo>" << Symbols::CRLF;
107 ss << " <aor>" << Data::from(aor).xmlCharDataEncode() << "</aor>" << Symbols::CRLF;
108 ContactList::const_iterator cit = contacts.begin();
109 for(; cit != contacts.end(); cit++)
110 {
111 const ContactInstanceRecord& rec = *cit;
113 rec.mRegExpires != NeverExpire) // Don't sync over static registrations
114 {
115 streamContactInstanceRecord(ss, rec);
116 infoFound = true;
117 }
118 }
119 ss << "</reginfo>" << Symbols::CRLF;
120
121 if(infoFound)
122 {
123 mRpc->sendEvent(connectionId, ss.str().c_str());
124 }
125}
126
127void
128RegSyncServer::sendDocumentModifiedEvent(unsigned int connectionId, const Data& eventType, const Data& documentKey, const Data& eTag, uint64_t expirationTime, uint64_t lastUpdated, const Contents* contents, const SecurityAttributes* securityAttributes)
129{
130 std::stringstream ss;
132
133 ss << "<pubinfo>" << Symbols::CRLF;
134 ss << " <eventtype>" << eventType << "</eventtype>" << Symbols::CRLF;
135 ss << " <documentkey>" << documentKey.xmlCharDataEncode() << "</documentkey>" << Symbols::CRLF;
136 ss << " <etag>" << eTag.xmlCharDataEncode() << "</etag>" << Symbols::CRLF;
137 ss << " <expires>" << (expirationTime <= now ? 0 : expirationTime - now) << "</expires>" << Symbols::CRLF;
138 ss << " <lastupdate>" << now - lastUpdated << "</lastupdate>" << Symbols::CRLF;
139 if (expirationTime != 0 && contents != 0) // lingering records will have expirationTime as 0 - don't need to send contents - refreshes also have no body
140 {
141 resip_assert(securityAttributes);
142 ss << " <contents>" << contents->getBodyData().xmlCharDataEncode() << "</contents>" << Symbols::CRLF;
143 ss << " <isencrypted>" << (securityAttributes->isEncrypted() ? "true" : "false") << "</isencrypted>" << Symbols::CRLF;
144 if (securityAttributes->isEncrypted())
145 {
146 ss << " <sigstatus>";
147 switch (securityAttributes->getSignatureStatus())
148 {
149 case SignatureNone:
150 ss << "none";
151 break;
152 case SignatureIsBad:
153 ss << "bad";
154 break;
155 case SignatureTrusted:
156 ss << "trusted";
157 break;
159 ss << "catrusted";
160 break;
162 ss << "nottrusted";
163 break;
165 ss << "selfsigned";
166 break;
167 default:
168 resip_assert(false);
169 ss << "unknown";
170 break;
171 }
172 ss << "</sigstatus>" << Symbols::CRLF;
173 if (!securityAttributes->getSigner().empty())
174 {
175 ss << " <signer>" << securityAttributes->getSigner().xmlCharDataEncode() << "</signer>" << Symbols::CRLF;
176 }
177 if (!securityAttributes->getIdentity().empty())
178 {
179 ss << " <identity>" << securityAttributes->getIdentity().xmlCharDataEncode() << "</identity>" << Symbols::CRLF;
180 ss << " <identitystrength>";
181 switch (securityAttributes->getIdentityStrength())
182 {
184 ss << "from";
185 break;
187 ss << "failedidentity";
188 break;
190 ss << "identity";
191 break;
192 default:
193 resip_assert(false);
194 ss << "unknown";
195 break;
196 }
197 ss << "</identitystrength>" << Symbols::CRLF;
198 }
199 // Note: intentionally not syncing mLevel and mEncryptionPerformed from SecurityAttributes since they are for outbound messages only
200 }
201 }
202 ss << "</pubinfo>" << Symbols::CRLF;
203
204 mRpc->sendEvent(connectionId, ss.str().c_str());
205}
206
207void
208RegSyncServer::sendDocumentRemovedEvent(unsigned int connectionId, const Data& eventType, const Data& documentKey, const Data& eTag, uint64_t lastUpdated)
209{
210 std::stringstream ss;
212
213 ss << "<pubinfo>" << Symbols::CRLF;
214 ss << " <eventtype>" << eventType.xmlCharDataEncode() << "</eventtype>" << Symbols::CRLF;
215 ss << " <documentkey>" << documentKey.xmlCharDataEncode() << "</documentkey>" << Symbols::CRLF;
216 ss << " <etag>" << eTag.xmlCharDataEncode() << "</etag>" << Symbols::CRLF;
217 ss << " <expires>0</expires>" << Symbols::CRLF;
218 ss << " <lastupdate>" << now - lastUpdated << "</lastupdate>" << Symbols::CRLF;
219 ss << "</pubinfo>" << Symbols::CRLF;
220
221 mRpc->sendEvent(connectionId, ss.str().c_str());
222}
223
224void
225RegSyncServer::handleRequest(unsigned int connectionId, unsigned int requestId, const resip::Data& request)
226{
227 DebugLog (<< "RegSyncServer::handleRequest: connectionId=" << connectionId << ", requestId=" << requestId << ", request=" << request);
228
229 try
230 {
231 ParseBuffer pb(request);
232 XMLCursor xml(pb);
233
234 if(isEqualNoCase(xml.getTag(), "InitialSync"))
235 {
236 handleInitialSyncRequest(connectionId, requestId, xml);
237 }
238 else
239 {
240 WarningLog(<< "RegSyncServer::handleRequest: Received XML message with unknown method: " << xml.getTag());
241 sendResponse(connectionId, requestId, Data::Empty, 400, "Unknown method");
242 }
243 }
244 catch(resip::BaseException& e)
245 {
246 WarningLog(<< "RegSyncServer::handleRequest: ParseException: " << e);
247 sendResponse(connectionId, requestId, Data::Empty, 400, "Parse error");
248 }
249}
250
251void
252RegSyncServer::handleInitialSyncRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
253{
254 InfoLog(<< "RegSyncServer::handleInitialSyncRequest");
255
256 // Check for correct Version
257 unsigned int version = 0;
258 if(xml.firstChild())
259 {
260 if(isEqualNoCase(xml.getTag(), "request"))
261 {
262 if(xml.firstChild())
263 {
264 if(isEqualNoCase(xml.getTag(), "version"))
265 {
266 if(xml.firstChild())
267 {
268 version = xml.getValue().convertUnsignedLong();
269 xml.parent();
270 }
271 }
272 xml.parent();
273 }
274 }
275 xml.parent();
276 }
277
278 if(version == REGSYNC_VERSION)
279 {
280 if (mRegDb)
281 {
282 mRegDb->initialSync(connectionId);
283 }
284 if (mPubDb)
285 {
286 mPubDb->initialSync(connectionId);
287 }
288 sendResponse(connectionId, requestId, Data::Empty, 200, "Initial Sync Completed.");
289 }
290 else
291 {
292 sendResponse(connectionId, requestId, Data::Empty, 505, "Version not supported.");
293 }
294}
295
296void
297RegSyncServer::streamContactInstanceRecord(std::stringstream& ss, const ContactInstanceRecord& rec)
298{
300
301 ss << " <contactinfo>" << Symbols::CRLF;
302 ss << " <contacturi>" << Data::from(rec.mContact).xmlCharDataEncode() << "</contacturi>" << Symbols::CRLF;
303 // If contact is expired or removed, then pass expires time as 0, otherwise send number of seconds until expirey
304 ss << " <expires>" << (((rec.mRegExpires == 0) || (rec.mRegExpires <= now)) ? 0 : (rec.mRegExpires-now)) << "</expires>" << Symbols::CRLF;
305 ss << " <lastupdate>" << now-rec.mLastUpdated << "</lastupdate>" << Symbols::CRLF;
306 if(rec.mReceivedFrom.getPort() != 0)
307 {
308 resip::Data binaryFlowToken;
309 Tuple::writeBinaryToken(rec.mReceivedFrom,binaryFlowToken);
310 ss << " <receivedfrom>" << binaryFlowToken.base64encode() << "</receivedfrom>" << Symbols::CRLF;
311 }
313 {
314 resip::Data binaryFlowToken;
315 Tuple::writeBinaryToken(rec.mPublicAddress,binaryFlowToken);
316 ss << " <publicaddress>" << binaryFlowToken.base64encode() << "</publicaddress>" << Symbols::CRLF;
317 }
318 NameAddrs::const_iterator naIt = rec.mSipPath.begin();
319 for(; naIt != rec.mSipPath.end(); naIt++)
320 {
321 ss << " <sippath>" << Data::from(naIt->uri()).xmlCharDataEncode() << "</sippath>" << Symbols::CRLF;
322 }
323 if(!rec.mInstance.empty())
324 {
325 ss << " <instance>" << rec.mInstance.xmlCharDataEncode() << "</instance>" << Symbols::CRLF;
326 }
327 if(rec.mRegId != 0)
328 {
329 ss << " <regid>" << rec.mRegId << "</regid>" << Symbols::CRLF;
330 }
331 if (!rec.mUserAgent.empty())
332 {
333 ss << " <useragent>" << rec.mUserAgent.xmlCharDataEncode() << "</useragent>" << Symbols::CRLF;
334 }
335 ss << " </contactinfo>" << Symbols::CRLF;
336}
337
338void
340{
341 sendRegistrationModifiedEvent(0, aor, contacts);
342}
343
344void
345RegSyncServer::onInitialSyncAor(unsigned int connectionId, const resip::Uri& aor, const ContactList& contacts)
346{
347 sendRegistrationModifiedEvent(connectionId, aor, contacts);
348}
349
350void
351RegSyncServer::onDocumentModified(bool sync, const Data& eventType, const Data& documentKey, const Data& eTag, uint64_t expirationTime, uint64_t lastUpdated, const Contents* contents, const SecurityAttributes* securityAttributes)
352{
353 resip_assert(!sync); // We register so that we don't get callbacks for sync'd documents
354 sendDocumentModifiedEvent(0, eventType, documentKey, eTag, expirationTime, lastUpdated, contents, securityAttributes);
355}
356
357void
358RegSyncServer::onDocumentRemoved(bool sync, const Data& eventType, const Data& documentKey, const Data& eTag, uint64_t lastUpdated)
359{
360 resip_assert(!sync); // We register so that we don't get callbacks for sync'd documents
361 sendDocumentRemovedEvent(0, eventType, documentKey, eTag, lastUpdated);
362}
363
364void
365RegSyncServer::onInitialSyncDocument(unsigned int connectionId, const Data& eventType, const Data& documentKey, const Data& eTag, uint64_t expirationTime, uint64_t lastUpdated, const Contents* contents, const SecurityAttributes* securityAttributes)
366{
367 sendDocumentModifiedEvent(connectionId, eventType, documentKey, eTag, expirationTime, lastUpdated, contents, securityAttributes);
368}
369
370
371/* ====================================================================
372 * The Vovida Software License, Version 1.0
373 *
374 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
375 * Copyright (c) 2015 SIP Spectrum, Inc. All rights reserved.
376 * Copyright (c) 2022 Daniel Pocock https://danielpocock.com
377 * Copyright (c) 2022 Software Freedom Institute LLC https://softwarefreedom.institute
378 *
379 * Redistribution and use in source and binary forms, with or without
380 * modification, are permitted provided that the following conditions
381 * are met:
382 *
383 * 1. Redistributions of source code must retain the above copyright
384 * notice, this list of conditions and the following disclaimer.
385 *
386 * 2. Redistributions in binary form must reproduce the above copyright
387 * notice, this list of conditions and the following disclaimer in
388 * the documentation and/or other materials provided with the
389 * distribution.
390 *
391 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
392 * and "Vovida Open Communication Application Library (VOCAL)" must
393 * not be used to endorse or promote products derived from this
394 * software without prior written permission. For written
395 * permission, please contact vocal@vovida.org.
396 *
397 * 4. Products derived from this software may not be called "VOCAL", nor
398 * may "VOCAL" appear in their name, without prior written
399 * permission of Vovida Networks, Inc.
400 *
401 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
402 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
403 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
404 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
405 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
406 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
407 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
408 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
409 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
410 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
411 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
412 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
413 * DAMAGE.
414 *
415 * ====================================================================
416 *
417 * This software consists of voluntary contributions made by Vovida
418 * Networks, Inc. and many individuals on behalf of Vovida Networks,
419 * Inc. For more information on Vovida Networks, Inc., please see
420 * <http://www.vovida.org/>.
421 *
422 */
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
static Data CRLF("\r\n")
#define REGSYNC_VERSION
#define resip_assert(x)
This file needs to work for both C and C++ code.
Handles cross-platform sockets compatibility.
virtual void onInitialSyncDocument(unsigned int connectionId, const resip::Data &eventType, const resip::Data &documentKey, const resip::Data &eTag, uint64_t expirationTime, uint64_t lastUpdated, const resip::Contents *contents, const resip::SecurityAttributes *securityAttributes)
virtual void sendDocumentModifiedEvent(unsigned int connectionId, const resip::Data &eventType, const resip::Data &documentKey, const resip::Data &eTag, uint64_t expirationTime, uint64_t lastUpdated, const resip::Contents *contents, const resip::SecurityAttributes *securityAttributes)
virtual void onInitialSyncAor(unsigned int connectionId, const resip::Uri &aor, const resip::ContactList &contacts)
virtual void sendRegistrationModifiedEvent(unsigned int connectionId, const resip::Uri &aor)
virtual void handleRequest(unsigned int connectionId, unsigned int requestId, const resip::Data &request)
virtual void sendResponse(unsigned int connectionId, unsigned int requestId, const resip::Data &responseData, unsigned int resultCode, const resip::Data &resultText)
virtual void onDocumentModified(bool sync, const resip::Data &eventType, const resip::Data &documentKey, const resip::Data &eTag, uint64_t expirationTime, uint64_t lastUpdated, const resip::Contents *contents, const resip::SecurityAttributes *securityAttributes)
virtual void onDocumentRemoved(bool sync, const resip::Data &eventType, const resip::Data &documentKey, const resip::Data &eTag, uint64_t lastUpdated)
virtual void sendDocumentRemovedEvent(unsigned int connectionId, const resip::Data &eventType, const resip::Data &documentKey, const resip::Data &eTag, uint64_t lastUpdated)
RegSyncServer(resip::InMemorySyncRegDb *regDb, int port, resip::IpVersion version, resip::InMemorySyncPubDb *pubDb=0)
virtual void onAorModified(const resip::Uri &aor, const resip::ContactList &contacts)
std::shared_ptr< XmlRpcServerBase > mRpc
The abstract base-class for all exceptions thrown by resip code.
A single contact record, bound to an Aor during registration.
Base class for all SIP body types.
Definition Contents.hxx:51
virtual Data getBodyData() const
Definition Contents.cxx:661
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
Data base64encode(bool useUrlSafe=false) const
Performs RFC 3548 Base 64 encoding of the contents of this data.
Definition Data.cxx:2682
unsigned long convertUnsignedLong() const
Definition Data.cxx:1724
Data xmlCharDataEncode() const
Performs in-place XML Character Data escaping of a Data.
Definition Data.cxx:1454
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
static Data from(const T &x)
Converts from arbitrary other type to Data.
Definition Data.hxx:398
const char * begin() const noexcept
Returns a pointer to the beginning of the buffer used by the Data.
Definition Data.hxx:642
Implementation of a persistence manager.
virtual void initialSync(unsigned int connectionId)
virtual void addHandler(InMemorySyncPubDbHandler *handler)
virtual void removeHandler(InMemorySyncPubDbHandler *handler)
Implementation of a persistence manager.
virtual void addHandler(InMemorySyncRegDbHandler *handler)
virtual void initialSync(unsigned int connectionId)
virtual void getContacts(const Uri &aor, ContactList &container)
virtual void removeHandler(InMemorySyncRegDbHandler *handler)
Provides string-parsing functionality with protection from buffer overflow.
iterator end()
Returns an iterator pointing to the last header field value.
iterator begin()
Returns an iterator pointing to the first header field value.
const Data & getSigner() const
SignatureStatus getSignatureStatus() const
IdentityStrength getIdentityStrength() const
const Data & getIdentity() const
static const char * CRLF
Definition Symbols.hxx:21
static uint64_t getTimeSecs()
Returns the current clock time in seconds.
Definition Timer.hxx:78
bool onlyUseExistingConnection
Definition Tuple.hxx:192
static void writeBinaryToken(const Tuple &tuple, Data &container, const Data &salt=Data::Empty)
Definition Tuple.cxx:266
int getPort() const
Definition Tuple.cxx:466
TransportType getType() const
Definition Tuple.hxx:122
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
const Data & getValue() const
const Data & getTag() const
This Class is used to implement a primitive form of RPC using loose XML formatting.
dcm! – add UnusedChecking(_enum) below;
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116
static const uint64_t NeverExpire
@ UNKNOWN_TRANSPORT
IpVersion
An enumeration of IP versions.
std::list< ContactInstanceRecord > ContactList
unsigned __int64 uint64_t
Definition stdint.h:95