1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "signaling/src/sdp/HybridSdpParser.h"
7 #include "signaling/src/sdp/SdpLog.h"
8 #include "signaling/src/sdp/SdpPref.h"
9 #include "signaling/src/sdp/SdpTelemetry.h"
10 #include "signaling/src/sdp/SipccSdpParser.h"
11 #include "signaling/src/sdp/RsdparsaSdpParser.h"
12 #include "signaling/src/sdp/ParsingResultComparer.h"
13 
14 #include "mozilla/Logging.h"
15 #include "mozilla/Preferences.h"
16 #include "mozilla/Telemetry.h"
17 
18 #include <unordered_map>
19 
20 namespace mozilla {
21 
22 using mozilla::LogLevel;
23 
ParserName()24 const std::string& HybridSdpParser::ParserName() {
25   const static std::string PARSER_NAME = "hybrid";
26   return PARSER_NAME;
27 }
28 
HybridSdpParser()29 HybridSdpParser::HybridSdpParser()
30     : mStrictSuccess(SdpPref::StrictSuccess()),
31       mPrimary(SdpPref::Primary()),
32       mSecondary(SdpPref::Secondary()),
33       mFailover(SdpPref::Failover()) {
34   MOZ_ASSERT(!(mSecondary && mFailover),
35              "Can not have both a secondary and failover parser!");
36   MOZ_LOG(SdpLog, LogLevel::Info,
37           ("Primary SDP Parser: %s", mPrimary->Name().c_str()));
38   mSecondary.apply([](auto& parser) {
39     MOZ_LOG(SdpLog, LogLevel::Info,
40             ("Secondary SDP Logger: %s", parser->Name().c_str()));
41   });
42   mFailover.apply([](auto& parser) {
43     MOZ_LOG(SdpLog, LogLevel::Info,
44             ("Failover SDP Logger: %s", parser->Name().c_str()));
45   });
46 }
47 
Parse(const std::string & aText)48 auto HybridSdpParser::Parse(const std::string& aText)
49     -> UniquePtr<SdpParser::Results> {
50   using Results = UniquePtr<SdpParser::Results>;
51   using Role = SdpTelemetry::Roles;
52   using Mode = SdpPref::AlternateParseModes;
53 
54   Mode mode = Mode::Never;
55   auto results = mPrimary->Parse(aText);
56 
57   auto successful = [&](Results& aRes) -> bool {
58     // In strict mode any reported error counts as failure
59     if (mStrictSuccess) {
60       return aRes->Ok();
61     }
62     return aRes->Sdp() != nullptr;
63   };
64   // Pass results on for comparison and return A if it was a success and B
65   // otherwise.
66   auto compare = [&](Results&& aResB) -> Results {
67     SdpTelemetry::RecordParse(aResB, mode, Role::Secondary);
68     ParsingResultComparer::Compare(results, aResB, aText, mode);
69     return std::move(successful(results) ? results : aResB);
70   };
71   // Run secondary parser, if there is one, and update selected results.
72   mSecondary.apply([&](auto& sec) {
73     mode = Mode::Parallel;
74     results = compare(std::move(sec->Parse(aText)));
75   });
76   // Run failover parser, if there is one, and update selected results.
77   mFailover.apply([&](auto& failover) {  // Only run if primary parser failed
78     mode = Mode::Failover;
79     if (!successful(results)) {
80       results = compare(std::move(failover->Parse(aText)));
81     }
82   });
83 
84   SdpTelemetry::RecordParse(results, mode, Role::Primary);
85   return results;
86 }
87 
88 }  // namespace mozilla
89