reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
CommandServer.cxx
Go to the documentation of this file.
1#include "rutil/ResipAssert.h"
2#include <sstream>
3#include <signal.h>
4
8#if defined(USE_SSL)
10#endif
12#include <rutil/Data.hxx>
13#include <rutil/DnsUtil.hxx>
14#include <rutil/Logger.hxx>
15#include <rutil/ParseBuffer.hxx>
16#include <rutil/Socket.hxx>
18#include <rutil/Timer.hxx>
19
22#include "repro/ReproRunner.hxx"
24#include "repro/WebAdmin.hxx"
25
26using namespace repro;
27using namespace resip;
28using namespace std;
29
30#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
31
33 Data ipAddr,
34 int port,
35 IpVersion version,
36 WebAdmin* webAdmin) :
37 XmlRpcHandler(std::make_shared<XmlRpcSocketServer>(*this, port, version, ipAddr)),
38 mReproRunner(reproRunner),
39 mWebAdmin(webAdmin)
40{
41}
42
43#ifdef BUILD_QPID_PROTON
45 const resip::Data& brokerUrl,
46 bool broadcast,
47 WebAdmin* webAdmin) :
48 XmlRpcHandler(std::make_shared<XmlRpcProtonServer>(*this, brokerUrl, broadcast)),
49 mReproRunner(reproRunner),
50 mWebAdmin(webAdmin)
51{
52}
53#endif
54
58
59void
60CommandServer::sendResponse(unsigned int connectionId,
61 unsigned int requestId,
62 const Data& responseData,
63 unsigned int resultCode,
64 const Data& resultText)
65{
66 std::stringstream ss;
67 ss << Symbols::CRLF << " <Result Code=\"" << resultCode << "\"";
68 ss << ">" << resultText.xmlCharDataEncode() << "</Result>" << Symbols::CRLF;
69 if(!responseData.empty())
70 {
71 ss << " <Data>" << Symbols::CRLF;
72 ss << responseData.xmlCharDataEncode();
73 ss << " </Data>" << Symbols::CRLF;
74 }
75 mRpc->sendResponse(connectionId, requestId, ss.str().c_str(), resultCode >= 200 /* isFinal */);
76}
77
78void
79CommandServer::handleRequest(unsigned int connectionId, unsigned int requestId, const resip::Data& request)
80{
81 DebugLog (<< "CommandServer::handleRequest: connectionId=" << connectionId << ", requestId=" << requestId << ", request=\r\n" << request);
82
83 try
84 {
85 ParseBuffer pb(request);
86 XMLCursor xml(pb);
87
88 if(!mReproRunner.getProxy())
89 {
90 sendResponse(connectionId, requestId, Data::Empty, 400, "Proxy not running.");
91 return;
92 }
93
94 if(isEqualNoCase(xml.getTag(), "GetStackInfo"))
95 {
96 handleGetStackInfoRequest(connectionId, requestId, xml);
97 }
98 else if(isEqualNoCase(xml.getTag(), "GetStackStats"))
99 {
100 handleGetStackStatsRequest(connectionId, requestId, xml);
101 }
102 else if(isEqualNoCase(xml.getTag(), "ResetStackStats"))
103 {
104 handleResetStackStatsRequest(connectionId, requestId, xml);
105 }
106 else if(isEqualNoCase(xml.getTag(), "LogDnsCache"))
107 {
108 handleLogDnsCacheRequest(connectionId, requestId, xml);
109 }
110 else if(isEqualNoCase(xml.getTag(), "ClearDnsCache"))
111 {
112 handleClearDnsCacheRequest(connectionId, requestId, xml);
113 }
114 else if(isEqualNoCase(xml.getTag(), "GetDnsCache"))
115 {
116 handleGetDnsCacheRequest(connectionId, requestId, xml);
117 }
118 else if(isEqualNoCase(xml.getTag(), "GetCongestionStats"))
119 {
120 handleGetCongestionStatsRequest(connectionId, requestId, xml);
121 }
122 else if(isEqualNoCase(xml.getTag(), "SetCongestionTolerance"))
123 {
124 handleSetCongestionToleranceRequest(connectionId, requestId, xml);
125 }
126 else if(isEqualNoCase(xml.getTag(), "Shutdown"))
127 {
128 handleShutdownRequest(connectionId, requestId, xml);
129 }
130 else if(isEqualNoCase(xml.getTag(), "GetProxyConfig"))
131 {
132 handleGetProxyConfigRequest(connectionId, requestId, xml);
133 }
134 else if(isEqualNoCase(xml.getTag(), "Restart"))
135 {
136 handleRestartRequest(connectionId, requestId, xml);
137 }
138 else if(isEqualNoCase(xml.getTag(), "AddTransport"))
139 {
140 handleAddTransportRequest(connectionId, requestId, xml);
141 }
142 else if(isEqualNoCase(xml.getTag(), "RemoveTransport"))
143 {
144 handleRemoveTransportRequest(connectionId, requestId, xml);
145 }
146 else if(isEqualNoCase(xml.getTag(), "HttpRequest"))
147 {
148 handleHttpRequest(connectionId, requestId, xml);
149 }
150 else
151 {
152 WarningLog(<< "CommandServer::handleRequest: Received XML message with unknown method: " << xml.getTag());
153 sendResponse(connectionId, requestId, Data::Empty, 400, "Unknown method");
154 }
155 }
156 catch(resip::BaseException& e)
157 {
158 WarningLog(<< "CommandServer::handleRequest: ParseException: " << e);
159 sendResponse(connectionId, requestId, Data::Empty, 400, "Parse error");
160 }
161}
162
163void
164CommandServer::handleGetStackInfoRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
165{
166 InfoLog(<< "CommandServer::handleGetStackInfoRequest");
167
168 Data buffer;
169 DataStream strm(buffer);
170 mReproRunner.getProxy()->getStack().dump(strm);
171 strm.flush();
172
173 sendResponse(connectionId, requestId, buffer, 200, "Stack info retrieved.");
174}
175
176void
177CommandServer::handleGetStackStatsRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
178{
179 InfoLog(<< "CommandServer::handleGetStackStatsRequest");
180
181 Lock lock(mStatisticsWaitersMutex);
182 mStatisticsWaiters.push_back(std::make_pair(connectionId, requestId));
183
184 if(!mReproRunner.getProxy()->getStack().pollStatistics())
185 {
186 sendResponse(connectionId, requestId, Data::Empty, 400, "Statistics Manager is not enabled.");
187 }
188}
189
190void
192{
193 Lock lock(mStatisticsWaitersMutex);
194 if(mStatisticsWaiters.size() > 0)
195 {
196 Data buffer;
197 DataStream strm(buffer);
199 statsMessage.loadOut(payload); // !slg! could optimize by providing stream operator on StatisticsMessage
200 strm << payload << endl;
201
202 StatisticsWaitersList::iterator it = mStatisticsWaiters.begin();
203 for(; it != mStatisticsWaiters.end(); it++)
204 {
205 sendResponse(it->first, it->second, buffer, 200, "Stack stats retrieved.");
206 }
207 }
208}
209
210void
211CommandServer::handleResetStackStatsRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
212{
213 InfoLog(<< "CommandServer::handleResetStackStatsRequest");
214
215 mReproRunner.getProxy()->getStack().zeroOutStatistics();
216 sendResponse(connectionId, requestId, Data::Empty, 200, "Stack stats reset.");
217}
218
219void
220CommandServer::handleLogDnsCacheRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
221{
222 InfoLog(<< "CommandServer::handleLogDnsCacheRequest");
223
224 mReproRunner.getProxy()->getStack().logDnsCache();
225 sendResponse(connectionId, requestId, Data::Empty, 200, "DNS cache logged.");
226}
227
228void
229CommandServer::handleClearDnsCacheRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
230{
231 InfoLog(<< "CommandServer::handleQueryDnsCacheRequest");
232
233 mReproRunner.getProxy()->getStack().clearDnsCache();
234 sendResponse(connectionId, requestId, Data::Empty, 200, "DNS cache cleared.");
235}
236
237void
238CommandServer::handleGetDnsCacheRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
239{
240 InfoLog(<< "CommandServer::handleGetDnsCacheRequest");
241
242 mReproRunner.getProxy()->getStack().getDnsCacheDump(make_pair((unsigned long)connectionId, (unsigned long)requestId), this);
243 // Note: Response will be sent when callback is invoked
244}
245
246void
247CommandServer::onDnsCacheDumpRetrieved(std::pair<unsigned long, unsigned long> key, const Data& dnsCache)
248{
249 if(dnsCache.empty())
250 {
251 sendResponse(key.first, key.second, "empty\r\n", 200, "DNS cache retrieved.");
252 }
253 else
254 {
255 sendResponse(key.first, key.second, dnsCache, 200, "DNS cache retrieved.");
256 }
257}
258
259void
260CommandServer::handleGetCongestionStatsRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
261{
262 InfoLog(<< "CommandServer::handleGetCongestionStatsRequest");
263
264 CongestionManager* congestionManager = mReproRunner.getProxy()->getStack().getCongestionManager();
265 if(congestionManager != 0)
266 {
267 Data buffer;
268 DataStream strm(buffer);
269 congestionManager->encodeCurrentState(strm);
270
271 sendResponse(connectionId, requestId, buffer, 200, "Congestion stats retrieved.");
272 }
273 else
274 {
275 sendResponse(connectionId, requestId, Data::Empty, 400, "Congestion Manager is not enabled.");
276 }
277}
278
279void
280CommandServer::handleSetCongestionToleranceRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
281{
282 InfoLog(<< "CommandServer::handleSetCongestionToleranceRequest");
283
284 Data fifoDescription;
285 Data metricData;
287 unsigned long maxTolerance=0;
288
289 GeneralCongestionManager* congestionManager = dynamic_cast<GeneralCongestionManager*>(mReproRunner.getProxy()->getStack().getCongestionManager());
290 if(congestionManager != 0)
291 {
292 // Check for Parameters
293 if(xml.firstChild())
294 {
295 if(isEqualNoCase(xml.getTag(), "request"))
296 {
297 if(xml.firstChild())
298 {
299 while(true)
300 {
301 if(isEqualNoCase(xml.getTag(), "fifoDescription"))
302 {
303 if(xml.firstChild())
304 {
305 fifoDescription = xml.getValue();
306 xml.parent();
307 }
308 }
309 else if(isEqualNoCase(xml.getTag(), "metric"))
310 {
311 if(xml.firstChild())
312 {
313 metricData = xml.getValue();
314 xml.parent();
315 }
316 }
317 else if(isEqualNoCase(xml.getTag(), "maxtolerance"))
318 {
319 if(xml.firstChild())
320 {
321 maxTolerance = xml.getValue().convertUnsignedLong();
322 xml.parent();
323 }
324 }
325 if(!xml.nextSibling())
326 {
327 // break on no more sibilings
328 break;
329 }
330 }
331 xml.parent();
332 }
333 }
334 xml.parent();
335 }
336
337 if(isEqualNoCase(metricData, "WAIT_TIME"))
338 {
340 }
341 else if(isEqualNoCase(metricData, "TIME_DEPTH"))
342 {
344 }
345 else if(isEqualNoCase(metricData, "SIZE"))
346 {
348 }
349 else
350 {
351 sendResponse(connectionId, requestId, Data::Empty, 400, "Invalid metric specified: must be SIZE, TIME_DEPTH or WAIT_TIME.");
352 return;
353 }
354
355 if(maxTolerance == 0)
356 {
357 sendResponse(connectionId, requestId, Data::Empty, 400, "Invalid MaxTolerance specified: must be greater than 0.");
358 return;
359 }
360
361 if(congestionManager->updateFifoTolerances(fifoDescription, metric, maxTolerance))
362 {
363 sendResponse(connectionId, requestId, Data::Empty, 200, "Congestion Tolerance set.");
364 }
365 else
366 {
367 sendResponse(connectionId, requestId, Data::Empty, 400, "Invalid fifo description provided.");
368 }
369 }
370 else
371 {
372 sendResponse(connectionId, requestId, Data::Empty, 400, "Congestion Manager is not enabled.");
373 }
374}
375
376void
377CommandServer::handleShutdownRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
378{
379 InfoLog(<< "CommandServer::handleShutdownRequest");
380
381 sendResponse(connectionId, requestId, Data::Empty, 200, "Shutdown initiated.");
382 raise(SIGTERM);
383}
384
385void
386CommandServer::handleGetProxyConfigRequest(unsigned int connectionId, unsigned int requestId, resip::XMLCursor& xml)
387{
388 InfoLog(<< "CommandServer::handleGetProxyConfigRequest");
389
390 Data buffer;
391 DataStream strm(buffer);
392 strm << mReproRunner.getProxy()->getConfig();
393
394 sendResponse(connectionId, requestId, buffer, 200, "Proxy config retrieved.");
395}
396
397void
398CommandServer::handleRestartRequest(unsigned int connectionId, unsigned int requestId, resip::XMLCursor& xml)
399{
400 InfoLog(<< "CommandServer::handleRestartRequest");
401
402 mReproRunner.restart();
403 if(mReproRunner.getProxy())
404 {
405 sendResponse(connectionId, requestId, Data::Empty, 200, "Restart completed.");
406 }
407 else
408 {
409 sendResponse(connectionId, requestId, Data::Empty, 200, "Restart failed.");
410 }
411}
412
413void
414CommandServer::handleAddTransportRequest(unsigned int connectionId, unsigned int requestId, resip::XMLCursor& xml)
415{
416 InfoLog(<< "CommandServer::handleAddTransportRequest");
417
418 TransportType type = UDP;
419 int port = 0;
420 IpVersion ipVersion=V4;
421 Data ipInterface;
422 Data recordRouteUri;
423 uint32_t rcvBufLen = 0;
424 bool stunEnabled = false;
425 Data sipDomainname;
427 uint32_t transportFlags = 0;
428 Data certificateFilename;
429 Data privateKeyFilename;
431 bool useEmailAsSIP = false;
432
433 // Check for Parameters
434 if(xml.firstChild())
435 {
436 if(isEqualNoCase(xml.getTag(), "request"))
437 {
438 if(xml.firstChild())
439 {
440 while(true)
441 {
442 if(isEqualNoCase(xml.getTag(), "type"))
443 {
444 if(xml.firstChild())
445 {
446 type = toTransportType(xml.getValue());
447 xml.parent();
448 }
449 }
450 else if(isEqualNoCase(xml.getTag(), "port"))
451 {
452 if(xml.firstChild())
453 {
454 port = xml.getValue().convertInt();
455 xml.parent();
456 }
457 }
458 else if(isEqualNoCase(xml.getTag(), "ipversion"))
459 {
460 if(xml.firstChild())
461 {
462 if(isEqualNoCase(xml.getValue(), "v6") || xml.getValue() == "6") // be a little leanient with this, allow just a 6
463 {
464 ipVersion = V6;
465 }
466 xml.parent();
467 }
468 }
469 else if(isEqualNoCase(xml.getTag(), "interface"))
470 {
471 if(xml.firstChild())
472 {
473 ipInterface = xml.getValue();
474 xml.parent();
475 }
476 }
477 else if(isEqualNoCase(xml.getTag(), "rruri"))
478 {
479 if(xml.firstChild())
480 {
481 recordRouteUri = xml.getValue();
482 xml.parent();
483 }
484 }
485 else if(isEqualNoCase(xml.getTag(), "udprcvbuflen"))
486 {
487 if(xml.firstChild())
488 {
489 rcvBufLen = xml.getValue().convertUnsignedLong();
490 xml.parent();
491 }
492 }
493 else if(isEqualNoCase(xml.getTag(), "stun"))
494 {
495 if(xml.firstChild())
496 {
497 if(isEqualNoCase(xml.getValue(), "yes"))
498 {
499 stunEnabled = true;
500 }
501 xml.parent();
502 }
503 }
504 else if(isEqualNoCase(xml.getTag(), "flags"))
505 {
506 if(xml.firstChild())
507 {
508 transportFlags = xml.getValue().convertUnsignedLong();
509 xml.parent();
510 }
511 }
512 else if(isEqualNoCase(xml.getTag(), "domain"))
513 {
514 if(xml.firstChild())
515 {
516 sipDomainname = xml.getValue();
517 xml.parent();
518 }
519 }
520 else if(isEqualNoCase(xml.getTag(), "ssltype"))
521 {
522 if(xml.firstChild())
523 {
524#if defined(USE_SSL)
525 try
526 {
527 sslType = BaseSecurity::parseSSLType(xml.getValue());
528 }
529 catch (invalid_argument& e)
530 {
531 WarningLog(<< e.what());
532 }
533#endif
534 xml.parent();
535 }
536 }
537 else if(isEqualNoCase(xml.getTag(), "certfile"))
538 {
539 if(xml.firstChild())
540 {
541 certificateFilename = xml.getValue();
542 xml.parent();
543 }
544 }
545 else if(isEqualNoCase(xml.getTag(), "keyfile"))
546 {
547 if(xml.firstChild())
548 {
549 privateKeyFilename = xml.getValue();
550 xml.parent();
551 }
552 }
553 else if(isEqualNoCase(xml.getTag(), "tlscvm"))
554 {
555 if(xml.firstChild())
556 {
557 if(isEqualNoCase(xml.getValue(), "opt"))
558 {
560 }
561 else if(isEqualNoCase(xml.getValue(), "man"))
562 {
564 }
565 xml.parent();
566 }
567 }
568 else if(isEqualNoCase(xml.getTag(), "tlsuseemail"))
569 {
570 if(xml.firstChild())
571 {
572 if(isEqualNoCase(xml.getValue(), "yes"))
573 {
574 useEmailAsSIP = true;
575 }
576 xml.parent();
577 }
578 }
579
580 if(!xml.nextSibling())
581 {
582 // break on no more sibilings
583 break;
584 }
585 }
586 xml.parent();
587 }
588 }
589 xml.parent();
590 }
591
592 // We need at least port and transport type to be valid to add
593 if(port == 0)
594 {
595 sendResponse(connectionId, requestId, Data::Empty, 400, "Invalid port specified: must be non-zero.");
596 return;
597 }
598
599 if(type == UNKNOWN_TRANSPORT)
600 {
601 Data errorString("Invalid transport specified: must one of UDP, TCP");
602#if defined( USE_SSL )
603 errorString += ", TLS, WS, WSS";
604#endif
605#if defined( USE_DTLS )
606 errorString += ", DTLS";
607#endif
608 sendResponse(connectionId, requestId, Data::Empty, 400, errorString);
609 return;
610 }
611
612 // Build RecordRoute URI if needed
613 NameAddr rr;
614 if(!recordRouteUri.empty())
615 {
616 try
617 {
618 if(isEqualNoCase(recordRouteUri, "auto")) // auto generated record route uri
619 {
620 if(isSecure(type))
621 {
622 rr.uri().host()=sipDomainname;
623 rr.uri().port()=port;
624 rr.uri().param(resip::p_transport)=resip::Tuple::toDataLower(type);
625 InfoLog (<< "Transport specific record-route enabled (generated): " << rr);
626 }
627 else
628 {
629 rr.uri().host()=ipInterface;
630 rr.uri().port()=port;
631 rr.uri().param(resip::p_transport)=resip::Tuple::toDataLower(type);
632 InfoLog (<< "Transport specific record-route enabled (generated): " << rr);
633 }
634 }
635 else
636 {
637 NameAddr rrtemp(recordRouteUri);
638 rr = rrtemp;
639 InfoLog (<< "Transport specific record-route enabled: " << rr);
640 }
641 }
642 catch(BaseException& e)
643 {
644 ErrLog (<< "Invalid uri provided in rruri setting (ignoring): " << e);
645 }
646 }
647
648 // Build transport info text for response message
649 Data transportInfoText("type=");
650 transportInfoText += getTransportNameFromType(type).c_str();
651 transportInfoText += ", port=" + Data(port);
652 transportInfoText += ", ipversion=" + Data((ipVersion == V4 ? "V4" : "V6"));
653 if(!ipInterface.empty())
654 {
655 transportInfoText += ", interface=" + ipInterface;
656 }
657 if(!recordRouteUri.empty())
658 {
659 transportInfoText += ", rruri=" + Data::from(rr);
660 }
661 transportInfoText += ", stun=" + Data((stunEnabled ? "YES" : "NO"));
662 transportInfoText += ", flags=" + Data((uint32_t)transportFlags);
663 if(rcvBufLen)
664 {
665 transportInfoText += ", udprcvbuflen=" + Data((uint32_t)rcvBufLen);
666 }
667 if(isSecure(type))
668 {
669 if(!sipDomainname.empty())
670 {
671 transportInfoText += ", domain=" + sipDomainname;
672 }
673 transportInfoText += ", ssltype=" + Data((sslType == SecurityTypes::TLSv1 ? "TLSv1" : "DynamicTLS"));
674 if(!certificateFilename.empty())
675 {
676 transportInfoText += ", cert=" + certificateFilename;
677 }
678 if(!privateKeyFilename.empty())
679 {
680 transportInfoText += ", key=" + privateKeyFilename;
681 }
682 transportInfoText += ", tlscvm=" + Data((cvm == SecurityTypes::None ? "NONE" : (cvm == SecurityTypes::Optional ? "OPT" : "MAN")));
683 transportInfoText += ", tlsuseemail=" + Data((stunEnabled ? "YES" : "NO"));
684 }
685
686 try
687 {
688 Transport* transport = mReproRunner.getProxy()->getStack().addTransport(
689 type, port, ipVersion, stunEnabled ? StunEnabled : StunDisabled, ipInterface,
690 sipDomainname, Data::Empty, sslType, transportFlags, certificateFilename,
691 privateKeyFilename, cvm, useEmailAsSIP);
692
693 if(transport)
694 {
695 if(!rr.uri().host().empty())
696 {
697 mReproRunner.getProxy()->addTransportRecordRoute(transport->getKey(), rr);
698 }
699 if(rcvBufLen)
700 {
701 transport->setRcvBufLen(rcvBufLen);
702 }
703
704 transportInfoText += ", transportKey=" + Data(transport->getKey());
705
706 Data text("Transport add requested: ");
707 text += transportInfoText;
708 sendResponse(connectionId, requestId, Data::Empty, 200, text);
709 }
710 else
711 {
712 Data text("Unknown error adding transport: ");
713 text += transportInfoText;
714 sendResponse(connectionId, requestId, Data::Empty, 500, text);
715 }
716 }
717 catch(BaseException& e)
718 {
719 Data text("Exception adding transport: ");
720 text += transportInfoText;
721 text += " - " + e.getMessage();
722 sendResponse(connectionId, requestId, Data::Empty, 500, text);
723 }
724}
725
726void
727CommandServer::handleRemoveTransportRequest(unsigned int connectionId, unsigned int requestId, resip::XMLCursor& xml)
728{
729 unsigned int transportKey = 0;
730
731 InfoLog(<< "CommandServer::handleRemoveTransportRequest");
732
733 // Check for Parameters
734 if(xml.firstChild())
735 {
736 if(isEqualNoCase(xml.getTag(), "request"))
737 {
738 if(xml.firstChild())
739 {
740 while(true)
741 {
742 if(isEqualNoCase(xml.getTag(), "key"))
743 {
744 if(xml.firstChild())
745 {
746 transportKey = xml.getValue().convertUnsignedLong();
747 xml.parent();
748 }
749 }
750 if(!xml.nextSibling())
751 {
752 // break on no more sibilings
753 break;
754 }
755 }
756 xml.parent();
757 }
758 }
759 xml.parent();
760 }
761
762 // We need transport key to remove
763 if(transportKey == 0)
764 {
765 sendResponse(connectionId, requestId, Data::Empty, 400, "Invalid transport key specified: must be non-zero.");
766 return;
767 }
768 mReproRunner.getProxy()->getStack().removeTransport(transportKey);
769 mReproRunner.getProxy()->removeTransportRecordRoute(transportKey);
770
771 Data text("Transport remove requested: transportKey=");
772 text += Data(transportKey);
773 sendResponse(connectionId, requestId, Data::Empty, 200, text);
774}
775
776void
777CommandServer::handleHttpRequest(unsigned int connectionId, unsigned int requestId, resip::XMLCursor& xml)
778{
779 InfoLog(<< "CommandServer::handleHttpRequest");
780
781 // Check for Parameters
782 std::map<Data, Data> m;
783 std::set<Data> keys;
784 xmlToMap(m, keys, xml);
785
786 if(!mWebAdmin)
787 {
788 // FIXME - do this without binding the WebAdmin instance to a port
789 ErrLog(<<"at least one WebAdmin instance must be configured, even if it is only bound to localhost");
790 sendResponse(connectionId, requestId, Data::Empty, 400, "WebAdmin not available.");
791 return;
792 }
793
794 try
795 {
796 Data& user = m["User"];
797 Data& password = m["Password"];
798 Data uri;
799 DataStream s(uri);
800 s << "/" << m["Page"] << ".html";
801 bool firstParam = true;
802 for(const auto& n : m)
803 {
804 const Data& k = n.first;
805 const Data& v = n.second;
806 if(k == "User" || k == "Password" || k == "Page")
807 {
808 continue;
809 }
810 s << (firstParam ? "?" : "&") << k << "=";
811 v.urlEncode(s);
812 firstParam = false;
813 }
814 s.flush();
815 int pageNumber = -1; // FIXME - add logic for handling response
816 mWebAdmin->buildPage("GET", uri, pageNumber, user, password);
817 sendResponse(connectionId, requestId, Data::Empty, 200, "HTTP Request processed, response ignored");
818 }
819 catch(std::exception&)
820 {
821 sendResponse(connectionId, requestId, Data::Empty, 400, "Exception.");
822 return;
823 }
824}
825
826void
827CommandServer::xmlToMap(std::map<Data, Data>& m, std::set<Data> keys, resip::XMLCursor& xml)
828{
829 // Check for Parameters
830 if(xml.firstChild())
831 {
832 if(isEqualNoCase(xml.getTag(), "request"))
833 {
834 if(xml.firstChild())
835 {
836 while(true)
837 {
838 const Data& key = xml.getTag();
839 if(!keys.empty() && keys.find(key) == keys.end())
840 {
841 ErrLog(<<"unexpected key: " << key);
842 m.clear();
843 return;
844 }
845 if(xml.firstChild())
846 {
847 const Data& value = xml.getValue();
848 m[key] = value;
849 xml.parent();
850 }
851 else
852 {
853 ErrLog(<<"no value for key: " << key);
854 }
855 if(!xml.nextSibling())
856 {
857 // break on no more sibilings
858 break;
859 }
860 }
861 xml.parent();
862 }
863 }
864 xml.parent();
865 }
866 if(!keys.empty() && (m.size() < keys.size()))
867 {
868 ErrLog(<<"some keys not found");
869 m.clear();
870 }
871}
872
873
874/* ====================================================================
875 * The Vovida Software License, Version 1.0
876 *
877 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
878 * Copyright (c) 2010-2026 SIP Spectrum, Inc. All rights reserved.
879 * Copyright (c) 2022 Daniel Pocock https://danielpocock.com
880 * Copyright (c) 2022 Software Freedom Institute LLC https://softwarefreedom.institute
881 *
882 * Redistribution and use in source and binary forms, with or without
883 * modification, are permitted provided that the following conditions
884 * are met:
885 *
886 * 1. Redistributions of source code must retain the above copyright
887 * notice, this list of conditions and the following disclaimer.
888 *
889 * 2. Redistributions in binary form must reproduce the above copyright
890 * notice, this list of conditions and the following disclaimer in
891 * the documentation and/or other materials provided with the
892 * distribution.
893 *
894 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
895 * and "Vovida Open Communication Application Library (VOCAL)" must
896 * not be used to endorse or promote products derived from this
897 * software without prior written permission. For written
898 * permission, please contact vocal@vovida.org.
899 *
900 * 4. Products derived from this software may not be called "VOCAL", nor
901 * may "VOCAL" appear in their name, without prior written
902 * permission of Vovida Networks, Inc.
903 *
904 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
905 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
906 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
907 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
908 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
909 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
910 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
911 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
912 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
913 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
914 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
915 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
916 * DAMAGE.
917 *
918 * ====================================================================
919 *
920 * This software consists of voluntary contributions made by Vovida
921 * Networks, Inc. and many individuals on behalf of Vovida Networks,
922 * Inc. For more information on Vovida Networks, Inc., please see
923 * <http://www.vovida.org/>.
924 *
925 */
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define ErrLog(args_)
Definition Logger.hxx:137
Handles cross-platform sockets compatibility.
virtual void sendResponse(unsigned int connectionId, unsigned int requestId, const resip::Data &responseData, unsigned int resultCode, const resip::Data &resultText)
CommandServer(ReproRunner &reproRunner, resip::Data ipAddr, int port, resip::IpVersion version, WebAdmin *webAdmin)
virtual void handleStatisticsMessage(resip::StatisticsMessage &statsMessage)
virtual void onDnsCacheDumpRetrieved(std::pair< unsigned long, unsigned long > key, const resip::Data &dnsEntryStrings)
virtual void handleRequest(unsigned int connectionId, unsigned int requestId, const resip::Data &request)
ProxyConfig & getConfig() noexcept
Definition Proxy.hxx:89
void removeTransportRecordRoute(unsigned int transportKey)
Definition Proxy.cxx:636
void addTransportRecordRoute(unsigned int transportKey, const resip::NameAddr &recordRoute)
Definition Proxy.cxx:630
resip::SipStack & getStack() noexcept
Definition Proxy.hxx:88
virtual void restart()
virtual Proxy * getProxy()
virtual void buildPage(const resip::Data &method, const resip::Data &uri, int pageNumber, const resip::Data &user, const resip::Data &password)
Definition WebAdmin.cxx:298
std::shared_ptr< XmlRpcServerBase > mRpc
The abstract base-class for all exceptions thrown by resip code.
const Data & getMessage() const noexcept
static SecurityTypes::SSLType parseSSLType(const Data &typeName)
Converts a string containing an SSL type name to the corresponding enum value.
Abstract base class that provides a basic congestion management interface.
virtual EncodeStream & encodeCurrentState(EncodeStream &strm) const =0
Get the current state of all monitored fifos.to a stream.
An iostream that operates on an existing Data.
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
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
EncodeStream & urlEncode(EncodeStream &s) const
Escapes a Data to a stream according to HTTP URL encoding rules.
Definition Data.cxx:1421
static Data from(const T &x)
Converts from arbitrary other type to Data.
Definition Data.hxx:398
int convertInt() const
Takes the contents of the Data and converts them to an integer.
Definition Data.cxx:1684
This is a general-purpose congestion manager.
MetricType
Enumeration of congestion metric types this class supports.
@ WAIT_TIME
The expected service time (the time it takes for new items to be serviced) This is the recommended me...
@ SIZE
The current size of the fifo.
@ TIME_DEPTH
The age of the oldest item in the fifo.
virtual bool updateFifoTolerances(const resip::Data &fifoDescription, MetricType metric, uint32_t maxTolerance)
Update the metric type and tolerances of a given fifo that the GeneralCongestionManager is already aw...
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
Definition NameAddr.hxx:19
Provides string-parsing functionality with protection from buffer overflow.
EncodeStream & dump(EncodeStream &strm) const
output current state of the stack - for debug
void clearDnsCache()
Clear the DNS Cache.
void getDnsCacheDump(std::pair< unsigned long, unsigned long > key, GetDnsCacheDumpHandler *handler)
Get a string representation of the DNS Cache.
Transport * addTransport(TransportType protocol, int port, IpVersion version=V4, StunSetting stun=StunDisabled, const Data &ipInterface=Data::Empty, const Data &sipDomainname=Data::Empty, const Data &privateKeyPassPhrase=Data::Empty, SecurityTypes::SSLType sslType=SecurityTypes::DynamicTLS, unsigned transportFlags=0, const Data &certificateFilename="", const Data &privateKeyFilename="", SecurityTypes::TlsClientVerificationMode cvm=SecurityTypes::None, bool useEmailAsSIP=false, std::shared_ptr< WsConnectionValidator >=nullptr, std::shared_ptr< WsCookieContextFactory >=nullptr, const Data &netNs=Data::Empty)
Used by the application to add in a new built-in transport.
Definition SipStack.cxx:362
void removeTransport(unsigned int transportKey)
Used to remove a previously added transport.
Definition SipStack.cxx:620
void logDnsCache()
Log the DNS Cache to WarningLog for Debugging.
void zeroOutStatistics()
Resets all of the cumulative statistics counters.
bool pollStatistics()
Immediately polls for statistics to be logged and sent to external handlers, instead of waiting for n...
void loadOut(Payload &payload) const
static const char * CRLF
Definition Symbols.hxx:21
The base class for Transport classes.
Definition Transport.hxx:83
unsigned int getKey() const
virtual void setRcvBufLen(int buflen)
static const Data & toDataLower(TransportType type)
Definition Tuple.cxx:933
int & port()
Definition Uri.hxx:145
Data & host()
Definition Uri.hxx:40
const Data & param(const ExtensionParameter &param) const
Const accessor for non-natively-supported parameter types.
const Data & getValue() const
const Data & getTag() const
CongestionManager * getCongestionManager()
Accessor for the CongestionManager object the stack is using.
This Class is used to implement a primitive form of RPC using loose XML formatting.
SSLType
Note: Before adding to the SSLType enum, please see the comments about mTlsCtx in resip/stack/ssl/Sec...
dcm! – add UnusedChecking(_enum) below;
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116
std::string getTransportNameFromType(const TransportType typeEnum)
Function which translates a transport enum value to its corrisponding name.
TransportType toTransportType(const resip::Data &transportName)
std::unique_lock< Mutex > Lock
A convenience class to lock a Lockable (such as a Mutex) on object creation, and unlock on destructio...
Definition Lock.hxx:28
bool isSecure(TransportType type)
Returns true if passed in transport type is a secure transport protocol.
TransportType
An enumeration of transport protocols.
@ UNKNOWN_TRANSPORT
IpVersion
An enumeration of IP versions.
unsigned int uint32_t
Definition stdint.h:85