~ubuntu-branches/ubuntu/saucy/resiprocate/saucy-proposed

« back to all changes in this revision

Viewing changes to repro/CommandServer.cxx

  • Committer: Package Import Robot
  • Author(s): Daniel Pocock
  • Date: 2012-05-17 19:29:59 UTC
  • Revision ID: package-import@ubuntu.com-20120517192959-vv00m77isztdy64q
Tags: upstream-1.8.2
ImportĀ upstreamĀ versionĀ 1.8.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <cassert>
 
2
#include <sstream>
 
3
#include <signal.h>
 
4
 
 
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>
 
16
 
 
17
#include "repro/XmlRpcServerBase.hxx"
 
18
#include "repro/XmlRpcConnection.hxx"
 
19
#include "repro/ReproRunner.hxx"
 
20
#include "repro/CommandServer.hxx"
 
21
 
 
22
using namespace repro;
 
23
using namespace resip;
 
24
using namespace std;
 
25
 
 
26
#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
 
27
 
 
28
 
 
29
CommandServer::CommandServer(ReproRunner& reproRunner,
 
30
                             int port, 
 
31
                             IpVersion version) :
 
32
   XmlRpcServerBase(port, version),
 
33
   mReproRunner(reproRunner)
 
34
{
 
35
   reproRunner.getProxy()->getStack().setExternalStatsHandler(this);
 
36
}
 
37
 
 
38
CommandServer::~CommandServer()
 
39
{
 
40
}
 
41
 
 
42
void 
 
43
CommandServer::sendResponse(unsigned int connectionId, 
 
44
                           unsigned int requestId, 
 
45
                           const Data& responseData, 
 
46
                           unsigned int resultCode, 
 
47
                           const Data& resultText)
 
48
{
 
49
   std::stringstream ss;
 
50
   ss << Symbols::CRLF << "    <Result Code=\"" << resultCode << "\"";
 
51
   ss << ">" << resultText.xmlCharDataEncode() << "</Result>" << Symbols::CRLF;
 
52
   if(!responseData.empty())
 
53
   { 
 
54
      ss << "    <Data>" << Symbols::CRLF;
 
55
      ss << responseData;
 
56
      ss << "    </Data>" << Symbols::CRLF;
 
57
   }
 
58
   XmlRpcServerBase::sendResponse(connectionId, requestId, ss.str().c_str(), resultCode >= 200 /* isFinal */);
 
59
}
 
60
 
 
61
void 
 
62
CommandServer::handleRequest(unsigned int connectionId, unsigned int requestId, const resip::Data& request)
 
63
{
 
64
   DebugLog (<< "CommandServer::handleRequest:  connectionId=" << connectionId << ", requestId=" << requestId << ", request=\r\n" << request);
 
65
 
 
66
   try
 
67
   {
 
68
      ParseBuffer pb(request);
 
69
      XMLCursor xml(pb);
 
70
 
 
71
      if(!mReproRunner.getProxy())
 
72
      {
 
73
         sendResponse(connectionId, requestId, Data::Empty, 400, "Proxy not running.");
 
74
         return;
 
75
      }
 
76
 
 
77
      if(isEqualNoCase(xml.getTag(), "GetStackInfo"))
 
78
      {
 
79
         handleGetStackInfoRequest(connectionId, requestId, xml);
 
80
      }
 
81
      else if(isEqualNoCase(xml.getTag(), "GetStackStats"))
 
82
      {
 
83
         handleGetStackStatsRequest(connectionId, requestId, xml);
 
84
      }
 
85
      else if(isEqualNoCase(xml.getTag(), "ResetStackStats"))
 
86
      {
 
87
         handleResetStackStatsRequest(connectionId, requestId, xml);
 
88
      }      
 
89
      else if(isEqualNoCase(xml.getTag(), "LogDnsCache"))
 
90
      {
 
91
         handleLogDnsCacheRequest(connectionId, requestId, xml);
 
92
      }
 
93
      else if(isEqualNoCase(xml.getTag(), "ClearDnsCache"))
 
94
      {
 
95
         handleClearDnsCacheRequest(connectionId, requestId, xml);
 
96
      }
 
97
      else if(isEqualNoCase(xml.getTag(), "GetDnsCache"))
 
98
      {
 
99
         handleGetDnsCacheRequest(connectionId, requestId, xml);
 
100
      }
 
101
      else if(isEqualNoCase(xml.getTag(), "GetCongestionStats"))
 
102
      {
 
103
         handleGetCongestionStatsRequest(connectionId, requestId, xml);
 
104
      }
 
105
      else if(isEqualNoCase(xml.getTag(), "SetCongestionTolerance"))
 
106
      {
 
107
         handleSetCongestionToleranceRequest(connectionId, requestId, xml);
 
108
      }
 
109
      else if(isEqualNoCase(xml.getTag(), "Shutdown"))
 
110
      {
 
111
         handleShutdownRequest(connectionId, requestId, xml);
 
112
      }
 
113
      else if(isEqualNoCase(xml.getTag(), "GetProxyConfig"))
 
114
      {
 
115
         handleGetProxyConfigRequest(connectionId, requestId, xml);
 
116
      }
 
117
      else if(isEqualNoCase(xml.getTag(), "Restart"))
 
118
      {
 
119
         handleRestartRequest(connectionId, requestId, xml);
 
120
      }
 
121
      else 
 
122
      {
 
123
         WarningLog(<< "CommandServer::handleRequest: Received XML message with unknown method: " << xml.getTag());
 
124
         sendResponse(connectionId, requestId, Data::Empty, 400, "Unknown method");
 
125
      }
 
126
   }
 
127
   catch(resip::BaseException& e)
 
128
   {
 
129
      WarningLog(<< "CommandServer::handleRequest: ParseException: " << e);
 
130
      sendResponse(connectionId, requestId, Data::Empty, 400, "Parse error");
 
131
   }
 
132
}
 
133
 
 
134
void 
 
135
CommandServer::handleGetStackInfoRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
 
136
{
 
137
   InfoLog(<< "CommandServer::handleGetStackInfoRequest");
 
138
 
 
139
   Data buffer;
 
140
   DataStream strm(buffer);
 
141
   mReproRunner.getProxy()->getStack().dump(strm);
 
142
   strm.flush();
 
143
 
 
144
   sendResponse(connectionId, requestId, buffer, 200, "Stack info retrieved.");
 
145
}
 
146
 
 
147
void 
 
148
CommandServer::handleGetStackStatsRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
 
149
{
 
150
   InfoLog(<< "CommandServer::handleGetStackStatsRequest");
 
151
 
 
152
   Lock lock(mStatisticsWaitersMutex);
 
153
   mStatisticsWaiters.push_back(std::make_pair(connectionId, requestId));
 
154
 
 
155
   if(!mReproRunner.getProxy()->getStack().pollStatistics())
 
156
   {
 
157
      sendResponse(connectionId, requestId, Data::Empty, 400, "Statistics Manager is not enabled.");
 
158
   }
 
159
}
 
160
 
 
161
bool 
 
162
CommandServer::operator()(resip::StatisticsMessage &statsMessage)
 
163
{
 
164
   Lock lock(mStatisticsWaitersMutex);
 
165
   if(mStatisticsWaiters.size() > 0)
 
166
   {
 
167
      Data buffer;
 
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;
 
172
 
 
173
      StatisticsWaitersList::iterator it = mStatisticsWaiters.begin();
 
174
      for(; it != mStatisticsWaiters.end(); it++)
 
175
      {
 
176
         sendResponse(it->first, it->second, buffer, 200, "Stack stats retrieved.");
 
177
      }
 
178
   }
 
179
   return true;
 
180
}
 
181
 
 
182
void 
 
183
CommandServer::handleResetStackStatsRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
 
184
{
 
185
   InfoLog(<< "CommandServer::handleResetStackStatsRequest");
 
186
 
 
187
   mReproRunner.getProxy()->getStack().zeroOutStatistics();
 
188
   sendResponse(connectionId, requestId, Data::Empty, 200, "Stack stats reset.");
 
189
}
 
190
 
 
191
void 
 
192
CommandServer::handleLogDnsCacheRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
 
193
{
 
194
   InfoLog(<< "CommandServer::handleLogDnsCacheRequest");
 
195
 
 
196
   mReproRunner.getProxy()->getStack().logDnsCache();
 
197
   sendResponse(connectionId, requestId, Data::Empty, 200, "DNS cache logged.");
 
198
}
 
199
 
 
200
void 
 
201
CommandServer::handleClearDnsCacheRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
 
202
{
 
203
   InfoLog(<< "CommandServer::handleQueryDnsCacheRequest");
 
204
 
 
205
   mReproRunner.getProxy()->getStack().clearDnsCache();
 
206
   sendResponse(connectionId, requestId, Data::Empty, 200, "DNS cache cleared.");
 
207
}
 
208
 
 
209
void 
 
210
CommandServer::handleGetDnsCacheRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
 
211
{
 
212
   InfoLog(<< "CommandServer::handleGetDnsCacheRequest");
 
213
 
 
214
   mReproRunner.getProxy()->getStack().getDnsCacheDump(make_pair((unsigned long)connectionId, (unsigned long)requestId), this);
 
215
   // Note: Response will be sent when callback is invoked
 
216
}
 
217
 
 
218
void 
 
219
CommandServer::onDnsCacheDumpRetrieved(std::pair<unsigned long, unsigned long> key, const Data& dnsCache)
 
220
{
 
221
   if(dnsCache.empty())
 
222
   {
 
223
      sendResponse(key.first, key.second, "empty\r\n", 200, "DNS cache retrieved.");
 
224
   }
 
225
   else
 
226
   {
 
227
      sendResponse(key.first, key.second, dnsCache, 200, "DNS cache retrieved.");
 
228
   }
 
229
}
 
230
 
 
231
void 
 
232
CommandServer::handleGetCongestionStatsRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
 
233
{
 
234
   InfoLog(<< "CommandServer::handleGetCongestionStatsRequest");
 
235
 
 
236
   CongestionManager* congestionManager = mReproRunner.getProxy()->getStack().getCongestionManager();
 
237
   if(congestionManager != 0)
 
238
   {
 
239
      Data buffer;
 
240
      DataStream strm(buffer);
 
241
      congestionManager->encodeCurrentState(strm);
 
242
 
 
243
      sendResponse(connectionId, requestId, buffer, 200, "Congestion stats retrieved.");
 
244
   }
 
245
   else
 
246
   {
 
247
      sendResponse(connectionId, requestId, Data::Empty, 400, "Congestion Manager is not enabled.");
 
248
   }
 
249
}
 
250
 
 
251
void 
 
252
CommandServer::handleSetCongestionToleranceRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
 
253
{
 
254
   InfoLog(<< "CommandServer::handleSetCongestionToleranceRequest");
 
255
 
 
256
   Data fifoDescription;
 
257
   Data metricData;
 
258
   GeneralCongestionManager::MetricType metric;
 
259
   unsigned long maxTolerance=0;
 
260
 
 
261
   GeneralCongestionManager* congestionManager = dynamic_cast<GeneralCongestionManager*>(mReproRunner.getProxy()->getStack().getCongestionManager());
 
262
   if(congestionManager != 0)
 
263
   {
 
264
      // Check for Parameters
 
265
      if(xml.firstChild())
 
266
      {
 
267
         if(isEqualNoCase(xml.getTag(), "request"))
 
268
         {
 
269
            if(xml.firstChild())
 
270
            {
 
271
               while(true)
 
272
               {
 
273
                  if(isEqualNoCase(xml.getTag(), "fifoDescription"))
 
274
                  {
 
275
                     if(xml.firstChild())
 
276
                     {
 
277
                        fifoDescription = xml.getValue();
 
278
                        xml.parent();
 
279
                     }
 
280
                  }
 
281
                  else if(isEqualNoCase(xml.getTag(), "metric"))
 
282
                  {
 
283
                     if(xml.firstChild())
 
284
                     {
 
285
                        metricData = xml.getValue();
 
286
                        xml.parent();
 
287
                     }
 
288
                  }
 
289
                  else if(isEqualNoCase(xml.getTag(), "maxtolerance"))
 
290
                  {
 
291
                     if(xml.firstChild())
 
292
                     {
 
293
                        maxTolerance = xml.getValue().convertUnsignedLong();
 
294
                        xml.parent();
 
295
                     }
 
296
                  }
 
297
                  if(!xml.nextSibling())
 
298
                  {
 
299
                     // break on no more sibilings
 
300
                     break;
 
301
                  }
 
302
               }
 
303
               xml.parent();
 
304
            }
 
305
         }
 
306
         xml.parent();
 
307
      }
 
308
 
 
309
      if(isEqualNoCase(metricData, "WAIT_TIME"))
 
310
      {
 
311
         metric = GeneralCongestionManager::WAIT_TIME;
 
312
      }
 
313
      else if(isEqualNoCase(metricData, "TIME_DEPTH"))
 
314
      {
 
315
         metric = GeneralCongestionManager::TIME_DEPTH;
 
316
      }
 
317
      else if(isEqualNoCase(metricData, "SIZE"))
 
318
      {
 
319
         metric = GeneralCongestionManager::SIZE;
 
320
      }
 
321
      else 
 
322
      {
 
323
         sendResponse(connectionId, requestId, Data::Empty, 400, "Invalid metric specified: must be SIZE, TIME_DEPTH or WAIT_TIME.");
 
324
         return;
 
325
      }
 
326
 
 
327
      if(maxTolerance == 0)
 
328
      {
 
329
         sendResponse(connectionId, requestId, Data::Empty, 400, "Invalid MaxTolerance specified: must be greater than 0.");
 
330
         return;
 
331
      }
 
332
 
 
333
      if(congestionManager->updateFifoTolerances(fifoDescription, metric, maxTolerance))
 
334
      {
 
335
         sendResponse(connectionId, requestId, Data::Empty, 200, "Congestion Tolerance set.");
 
336
      }
 
337
      else
 
338
      {
 
339
         sendResponse(connectionId, requestId, Data::Empty, 400, "Invalid fifo description provided.");
 
340
      }
 
341
   }
 
342
   else
 
343
   {
 
344
      sendResponse(connectionId, requestId, Data::Empty, 400, "Congestion Manager is not enabled.");
 
345
   }
 
346
}
 
347
 
 
348
void 
 
349
CommandServer::handleShutdownRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
 
350
{
 
351
   InfoLog(<< "CommandServer::handleShutdownRequest");
 
352
 
 
353
   sendResponse(connectionId, requestId, Data::Empty, 200, "Shutdown initiated.");
 
354
   raise(SIGTERM);
 
355
}
 
356
 
 
357
void 
 
358
CommandServer::handleGetProxyConfigRequest(unsigned int connectionId, unsigned int requestId, resip::XMLCursor& xml)
 
359
{
 
360
   InfoLog(<< "CommandServer::handleGetProxyConfigRequest");
 
361
 
 
362
   Data buffer;
 
363
   DataStream strm(buffer);
 
364
   strm << mReproRunner.getProxy()->getConfig();
 
365
 
 
366
   sendResponse(connectionId, requestId, buffer, 200, "Proxy config retrieved.");
 
367
}
 
368
 
 
369
void 
 
370
CommandServer::handleRestartRequest(unsigned int connectionId, unsigned int requestId, resip::XMLCursor& xml)
 
371
{
 
372
   InfoLog(<< "CommandServer::handleRestartRequest");
 
373
 
 
374
   mReproRunner.restart();
 
375
   if(mReproRunner.getProxy())
 
376
   {
 
377
      mReproRunner.getProxy()->getStack().setExternalStatsHandler(this);
 
378
      sendResponse(connectionId, requestId, Data::Empty, 200, "Restart completed.");
 
379
   }
 
380
   else
 
381
   {
 
382
      sendResponse(connectionId, requestId, Data::Empty, 200, "Restart failed.");
 
383
   }
 
384
}
 
385
 
 
386
/* ====================================================================
 
387
 * The Vovida Software License, Version 1.0 
 
388
 * 
 
389
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
 
390
 * Copyright (c) 2010 SIP Spectrum, Inc.  All rights reserved.
 
391
 * 
 
392
 * Redistribution and use in source and binary forms, with or without
 
393
 * modification, are permitted provided that the following conditions
 
394
 * are met:
 
395
 * 
 
396
 * 1. Redistributions of source code must retain the above copyright
 
397
 *    notice, this list of conditions and the following disclaimer.
 
398
 * 
 
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
 
402
 *    distribution.
 
403
 * 
 
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.
 
409
 *
 
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.
 
413
 * 
 
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
 
426
 * DAMAGE.
 
427
 * 
 
428
 * ====================================================================
 
429
 * 
 
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/>.
 
434
 *
 
435
 */