5
#include <resip/stack/Symbols.hxx>
6
#include <resip/stack/Tuple.hxx>
7
#include <resip/stack/SipStack.hxx>
8
#include <rutil/GeneralCongestionManager.hxx>
9
#include <rutil/Data.hxx>
10
#include <rutil/DnsUtil.hxx>
11
#include <rutil/Logger.hxx>
12
#include <rutil/ParseBuffer.hxx>
13
#include <rutil/Socket.hxx>
14
#include <rutil/TransportType.hxx>
15
#include <rutil/Timer.hxx>
17
#include "repro/XmlRpcServerBase.hxx"
18
#include "repro/XmlRpcConnection.hxx"
19
#include "repro/ReproRunner.hxx"
20
#include "repro/CommandServer.hxx"
22
using namespace repro;
23
using namespace resip;
26
#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
29
CommandServer::CommandServer(ReproRunner& reproRunner,
32
XmlRpcServerBase(port, version),
33
mReproRunner(reproRunner)
35
reproRunner.getProxy()->getStack().setExternalStatsHandler(this);
38
CommandServer::~CommandServer()
43
CommandServer::sendResponse(unsigned int connectionId,
44
unsigned int requestId,
45
const Data& responseData,
46
unsigned int resultCode,
47
const Data& resultText)
50
ss << Symbols::CRLF << " <Result Code=\"" << resultCode << "\"";
51
ss << ">" << resultText.xmlCharDataEncode() << "</Result>" << Symbols::CRLF;
52
if(!responseData.empty())
54
ss << " <Data>" << Symbols::CRLF;
56
ss << " </Data>" << Symbols::CRLF;
58
XmlRpcServerBase::sendResponse(connectionId, requestId, ss.str().c_str(), resultCode >= 200 /* isFinal */);
62
CommandServer::handleRequest(unsigned int connectionId, unsigned int requestId, const resip::Data& request)
64
DebugLog (<< "CommandServer::handleRequest: connectionId=" << connectionId << ", requestId=" << requestId << ", request=\r\n" << request);
68
ParseBuffer pb(request);
71
if(!mReproRunner.getProxy())
73
sendResponse(connectionId, requestId, Data::Empty, 400, "Proxy not running.");
77
if(isEqualNoCase(xml.getTag(), "GetStackInfo"))
79
handleGetStackInfoRequest(connectionId, requestId, xml);
81
else if(isEqualNoCase(xml.getTag(), "GetStackStats"))
83
handleGetStackStatsRequest(connectionId, requestId, xml);
85
else if(isEqualNoCase(xml.getTag(), "ResetStackStats"))
87
handleResetStackStatsRequest(connectionId, requestId, xml);
89
else if(isEqualNoCase(xml.getTag(), "LogDnsCache"))
91
handleLogDnsCacheRequest(connectionId, requestId, xml);
93
else if(isEqualNoCase(xml.getTag(), "ClearDnsCache"))
95
handleClearDnsCacheRequest(connectionId, requestId, xml);
97
else if(isEqualNoCase(xml.getTag(), "GetDnsCache"))
99
handleGetDnsCacheRequest(connectionId, requestId, xml);
101
else if(isEqualNoCase(xml.getTag(), "GetCongestionStats"))
103
handleGetCongestionStatsRequest(connectionId, requestId, xml);
105
else if(isEqualNoCase(xml.getTag(), "SetCongestionTolerance"))
107
handleSetCongestionToleranceRequest(connectionId, requestId, xml);
109
else if(isEqualNoCase(xml.getTag(), "Shutdown"))
111
handleShutdownRequest(connectionId, requestId, xml);
113
else if(isEqualNoCase(xml.getTag(), "GetProxyConfig"))
115
handleGetProxyConfigRequest(connectionId, requestId, xml);
117
else if(isEqualNoCase(xml.getTag(), "Restart"))
119
handleRestartRequest(connectionId, requestId, xml);
123
WarningLog(<< "CommandServer::handleRequest: Received XML message with unknown method: " << xml.getTag());
124
sendResponse(connectionId, requestId, Data::Empty, 400, "Unknown method");
127
catch(resip::BaseException& e)
129
WarningLog(<< "CommandServer::handleRequest: ParseException: " << e);
130
sendResponse(connectionId, requestId, Data::Empty, 400, "Parse error");
135
CommandServer::handleGetStackInfoRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
137
InfoLog(<< "CommandServer::handleGetStackInfoRequest");
140
DataStream strm(buffer);
141
mReproRunner.getProxy()->getStack().dump(strm);
144
sendResponse(connectionId, requestId, buffer, 200, "Stack info retrieved.");
148
CommandServer::handleGetStackStatsRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
150
InfoLog(<< "CommandServer::handleGetStackStatsRequest");
152
Lock lock(mStatisticsWaitersMutex);
153
mStatisticsWaiters.push_back(std::make_pair(connectionId, requestId));
155
if(!mReproRunner.getProxy()->getStack().pollStatistics())
157
sendResponse(connectionId, requestId, Data::Empty, 400, "Statistics Manager is not enabled.");
162
CommandServer::operator()(resip::StatisticsMessage &statsMessage)
164
Lock lock(mStatisticsWaitersMutex);
165
if(mStatisticsWaiters.size() > 0)
168
DataStream strm(buffer);
169
StatisticsMessage::Payload payload;
170
statsMessage.loadOut(payload); // !slg! could optimize by providing stream operator on StatisticsMessage
171
strm << payload << endl;
173
StatisticsWaitersList::iterator it = mStatisticsWaiters.begin();
174
for(; it != mStatisticsWaiters.end(); it++)
176
sendResponse(it->first, it->second, buffer, 200, "Stack stats retrieved.");
183
CommandServer::handleResetStackStatsRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
185
InfoLog(<< "CommandServer::handleResetStackStatsRequest");
187
mReproRunner.getProxy()->getStack().zeroOutStatistics();
188
sendResponse(connectionId, requestId, Data::Empty, 200, "Stack stats reset.");
192
CommandServer::handleLogDnsCacheRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
194
InfoLog(<< "CommandServer::handleLogDnsCacheRequest");
196
mReproRunner.getProxy()->getStack().logDnsCache();
197
sendResponse(connectionId, requestId, Data::Empty, 200, "DNS cache logged.");
201
CommandServer::handleClearDnsCacheRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
203
InfoLog(<< "CommandServer::handleQueryDnsCacheRequest");
205
mReproRunner.getProxy()->getStack().clearDnsCache();
206
sendResponse(connectionId, requestId, Data::Empty, 200, "DNS cache cleared.");
210
CommandServer::handleGetDnsCacheRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
212
InfoLog(<< "CommandServer::handleGetDnsCacheRequest");
214
mReproRunner.getProxy()->getStack().getDnsCacheDump(make_pair((unsigned long)connectionId, (unsigned long)requestId), this);
215
// Note: Response will be sent when callback is invoked
219
CommandServer::onDnsCacheDumpRetrieved(std::pair<unsigned long, unsigned long> key, const Data& dnsCache)
223
sendResponse(key.first, key.second, "empty\r\n", 200, "DNS cache retrieved.");
227
sendResponse(key.first, key.second, dnsCache, 200, "DNS cache retrieved.");
232
CommandServer::handleGetCongestionStatsRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
234
InfoLog(<< "CommandServer::handleGetCongestionStatsRequest");
236
CongestionManager* congestionManager = mReproRunner.getProxy()->getStack().getCongestionManager();
237
if(congestionManager != 0)
240
DataStream strm(buffer);
241
congestionManager->encodeCurrentState(strm);
243
sendResponse(connectionId, requestId, buffer, 200, "Congestion stats retrieved.");
247
sendResponse(connectionId, requestId, Data::Empty, 400, "Congestion Manager is not enabled.");
252
CommandServer::handleSetCongestionToleranceRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
254
InfoLog(<< "CommandServer::handleSetCongestionToleranceRequest");
256
Data fifoDescription;
258
GeneralCongestionManager::MetricType metric;
259
unsigned long maxTolerance=0;
261
GeneralCongestionManager* congestionManager = dynamic_cast<GeneralCongestionManager*>(mReproRunner.getProxy()->getStack().getCongestionManager());
262
if(congestionManager != 0)
264
// Check for Parameters
267
if(isEqualNoCase(xml.getTag(), "request"))
273
if(isEqualNoCase(xml.getTag(), "fifoDescription"))
277
fifoDescription = xml.getValue();
281
else if(isEqualNoCase(xml.getTag(), "metric"))
285
metricData = xml.getValue();
289
else if(isEqualNoCase(xml.getTag(), "maxtolerance"))
293
maxTolerance = xml.getValue().convertUnsignedLong();
297
if(!xml.nextSibling())
299
// break on no more sibilings
309
if(isEqualNoCase(metricData, "WAIT_TIME"))
311
metric = GeneralCongestionManager::WAIT_TIME;
313
else if(isEqualNoCase(metricData, "TIME_DEPTH"))
315
metric = GeneralCongestionManager::TIME_DEPTH;
317
else if(isEqualNoCase(metricData, "SIZE"))
319
metric = GeneralCongestionManager::SIZE;
323
sendResponse(connectionId, requestId, Data::Empty, 400, "Invalid metric specified: must be SIZE, TIME_DEPTH or WAIT_TIME.");
327
if(maxTolerance == 0)
329
sendResponse(connectionId, requestId, Data::Empty, 400, "Invalid MaxTolerance specified: must be greater than 0.");
333
if(congestionManager->updateFifoTolerances(fifoDescription, metric, maxTolerance))
335
sendResponse(connectionId, requestId, Data::Empty, 200, "Congestion Tolerance set.");
339
sendResponse(connectionId, requestId, Data::Empty, 400, "Invalid fifo description provided.");
344
sendResponse(connectionId, requestId, Data::Empty, 400, "Congestion Manager is not enabled.");
349
CommandServer::handleShutdownRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
351
InfoLog(<< "CommandServer::handleShutdownRequest");
353
sendResponse(connectionId, requestId, Data::Empty, 200, "Shutdown initiated.");
358
CommandServer::handleGetProxyConfigRequest(unsigned int connectionId, unsigned int requestId, resip::XMLCursor& xml)
360
InfoLog(<< "CommandServer::handleGetProxyConfigRequest");
363
DataStream strm(buffer);
364
strm << mReproRunner.getProxy()->getConfig();
366
sendResponse(connectionId, requestId, buffer, 200, "Proxy config retrieved.");
370
CommandServer::handleRestartRequest(unsigned int connectionId, unsigned int requestId, resip::XMLCursor& xml)
372
InfoLog(<< "CommandServer::handleRestartRequest");
374
mReproRunner.restart();
375
if(mReproRunner.getProxy())
377
mReproRunner.getProxy()->getStack().setExternalStatsHandler(this);
378
sendResponse(connectionId, requestId, Data::Empty, 200, "Restart completed.");
382
sendResponse(connectionId, requestId, Data::Empty, 200, "Restart failed.");
386
/* ====================================================================
387
* The Vovida Software License, Version 1.0
389
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
390
* Copyright (c) 2010 SIP Spectrum, Inc. All rights reserved.
392
* Redistribution and use in source and binary forms, with or without
393
* modification, are permitted provided that the following conditions
396
* 1. Redistributions of source code must retain the above copyright
397
* notice, this list of conditions and the following disclaimer.
399
* 2. Redistributions in binary form must reproduce the above copyright
400
* notice, this list of conditions and the following disclaimer in
401
* the documentation and/or other materials provided with the
404
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
405
* and "Vovida Open Communication Application Library (VOCAL)" must
406
* not be used to endorse or promote products derived from this
407
* software without prior written permission. For written
408
* permission, please contact vocal@vovida.org.
410
* 4. Products derived from this software may not be called "VOCAL", nor
411
* may "VOCAL" appear in their name, without prior written
412
* permission of Vovida Networks, Inc.
414
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
415
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
416
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
417
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
418
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
419
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
420
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
421
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
422
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
423
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
424
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
425
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
428
* ====================================================================
430
* This software consists of voluntary contributions made by Vovida
431
* Networks, Inc. and many individuals on behalf of Vovida Networks,
432
* Inc. For more information on Vovida Networks, Inc., please see
433
* <http://www.vovida.org/>.