| /* | 
 |  *  Copyright 2013 The WebRTC Project Authors. All rights reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "p2p/base/transport_description.h" | 
 |  | 
 | #include <cstddef> | 
 | #include <optional> | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | #include "absl/algorithm/container.h" | 
 | #include "absl/strings/ascii.h" | 
 | #include "absl/strings/match.h" | 
 | #include "absl/strings/string_view.h" | 
 | #include "api/rtc_error.h" | 
 | #include "p2p/base/p2p_constants.h" | 
 | #include "rtc_base/logging.h" | 
 | #include "rtc_base/ssl_fingerprint.h" | 
 | #include "rtc_base/strings/string_builder.h" | 
 |  | 
 | using webrtc::RTCError; | 
 | using webrtc::RTCErrorOr; | 
 | using webrtc::RTCErrorType; | 
 |  | 
 | namespace webrtc { | 
 | namespace { | 
 |  | 
 | bool IsIceChar(char c) { | 
 |   // Note: '-', '=', '#' and '_' are *not* valid ice-chars but temporarily | 
 |   // permitted in order to allow external software to upgrade. | 
 |   if (c == '-' || c == '=' || c == '#' || c == '_') { | 
 |     RTC_LOG(LS_WARNING) | 
 |         << "'-', '=', '#' and '-' are not valid ice-char and thus not " | 
 |         << "permitted in ufrag or pwd. This is a protocol violation that " | 
 |         << "is permitted to allow upgrading but will be rejected in " | 
 |         << "the future. See https://crbug.com/1053756"; | 
 |     return true; | 
 |   } | 
 |   return absl::ascii_isalnum(c) || c == '+' || c == '/'; | 
 | } | 
 |  | 
 | RTCError ValidateIceUfrag(absl::string_view raw_ufrag) { | 
 |   if (!(ICE_UFRAG_MIN_LENGTH <= raw_ufrag.size() && | 
 |         raw_ufrag.size() <= ICE_UFRAG_MAX_LENGTH)) { | 
 |     StringBuilder sb; | 
 |     sb << "ICE ufrag must be between " << ICE_UFRAG_MIN_LENGTH << " and " | 
 |        << ICE_UFRAG_MAX_LENGTH << " characters long."; | 
 |     return RTCError(RTCErrorType::SYNTAX_ERROR, sb.Release()); | 
 |   } | 
 |  | 
 |   if (!absl::c_all_of(raw_ufrag, IsIceChar)) { | 
 |     return RTCError( | 
 |         RTCErrorType::SYNTAX_ERROR, | 
 |         "ICE ufrag must contain only alphanumeric characters, '+', and '/'."); | 
 |   } | 
 |  | 
 |   return RTCError::OK(); | 
 | } | 
 |  | 
 | RTCError ValidateIcePwd(absl::string_view raw_pwd) { | 
 |   if (!(ICE_PWD_MIN_LENGTH <= raw_pwd.size() && | 
 |         raw_pwd.size() <= ICE_PWD_MAX_LENGTH)) { | 
 |     StringBuilder sb; | 
 |     sb << "ICE pwd must be between " << ICE_PWD_MIN_LENGTH << " and " | 
 |        << ICE_PWD_MAX_LENGTH << " characters long."; | 
 |     return RTCError(RTCErrorType::SYNTAX_ERROR, sb.Release()); | 
 |   } | 
 |  | 
 |   if (!absl::c_all_of(raw_pwd, IsIceChar)) { | 
 |     return RTCError( | 
 |         RTCErrorType::SYNTAX_ERROR, | 
 |         "ICE pwd must contain only alphanumeric characters, '+', and '/'."); | 
 |   } | 
 |  | 
 |   return RTCError::OK(); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | RTCErrorOr<IceParameters> IceParameters::Parse(absl::string_view raw_ufrag, | 
 |                                                absl::string_view raw_pwd) { | 
 |   IceParameters parameters(std::string(raw_ufrag), std::string(raw_pwd), | 
 |                            /* renomination= */ false); | 
 |   auto result = parameters.Validate(); | 
 |   if (!result.ok()) { | 
 |     return result; | 
 |   } | 
 |   return parameters; | 
 | } | 
 |  | 
 | RTCError IceParameters::Validate() const { | 
 |   // For legacy protocols. | 
 |   // TODO(zhihuang): Remove this once the legacy protocol is no longer | 
 |   // supported. | 
 |   if (ufrag.empty() && pwd.empty()) { | 
 |     return RTCError::OK(); | 
 |   } | 
 |  | 
 |   auto ufrag_result = ValidateIceUfrag(ufrag); | 
 |   if (!ufrag_result.ok()) { | 
 |     return ufrag_result; | 
 |   } | 
 |  | 
 |   auto pwd_result = ValidateIcePwd(pwd); | 
 |   if (!pwd_result.ok()) { | 
 |     return pwd_result; | 
 |   } | 
 |  | 
 |   return RTCError::OK(); | 
 | } | 
 |  | 
 | std::optional<ConnectionRole> StringToConnectionRole( | 
 |     absl::string_view role_str) { | 
 |   const char* const roles[] = { | 
 |       CONNECTIONROLE_ACTIVE_STR, CONNECTIONROLE_PASSIVE_STR, | 
 |       CONNECTIONROLE_ACTPASS_STR, CONNECTIONROLE_HOLDCONN_STR}; | 
 |  | 
 |   for (size_t i = 0; i < std::size(roles); ++i) { | 
 |     if (absl::EqualsIgnoreCase(roles[i], role_str)) { | 
 |       return static_cast<ConnectionRole>(CONNECTIONROLE_ACTIVE + i); | 
 |     } | 
 |   } | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | bool ConnectionRoleToString(const ConnectionRole& role, std::string* role_str) { | 
 |   switch (role) { | 
 |     case CONNECTIONROLE_ACTIVE: | 
 |       *role_str = CONNECTIONROLE_ACTIVE_STR; | 
 |       break; | 
 |     case CONNECTIONROLE_ACTPASS: | 
 |       *role_str = CONNECTIONROLE_ACTPASS_STR; | 
 |       break; | 
 |     case CONNECTIONROLE_PASSIVE: | 
 |       *role_str = CONNECTIONROLE_PASSIVE_STR; | 
 |       break; | 
 |     case CONNECTIONROLE_HOLDCONN: | 
 |       *role_str = CONNECTIONROLE_HOLDCONN_STR; | 
 |       break; | 
 |     default: | 
 |       return false; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | TransportDescription::TransportDescription() | 
 |     : ice_mode(ICEMODE_FULL), connection_role(CONNECTIONROLE_NONE) {} | 
 |  | 
 | TransportDescription::TransportDescription( | 
 |     const std::vector<std::string>& transport_options, | 
 |     absl::string_view ice_ufrag, | 
 |     absl::string_view ice_pwd, | 
 |     IceMode ice_mode, | 
 |     ConnectionRole role, | 
 |     const SSLFingerprint* identity_fingerprint) | 
 |     : transport_options(transport_options), | 
 |       ice_ufrag(ice_ufrag), | 
 |       ice_pwd(ice_pwd), | 
 |       ice_mode(ice_mode), | 
 |       connection_role(role), | 
 |       identity_fingerprint(CopyFingerprint(identity_fingerprint)) {} | 
 |  | 
 | TransportDescription::TransportDescription(absl::string_view ice_ufrag, | 
 |                                            absl::string_view ice_pwd) | 
 |     : ice_ufrag(ice_ufrag), | 
 |       ice_pwd(ice_pwd), | 
 |       ice_mode(ICEMODE_FULL), | 
 |       connection_role(CONNECTIONROLE_NONE) {} | 
 |  | 
 | TransportDescription::TransportDescription(const TransportDescription& from) | 
 |     : transport_options(from.transport_options), | 
 |       ice_ufrag(from.ice_ufrag), | 
 |       ice_pwd(from.ice_pwd), | 
 |       ice_mode(from.ice_mode), | 
 |       connection_role(from.connection_role), | 
 |       identity_fingerprint(CopyFingerprint(from.identity_fingerprint.get())) {} | 
 |  | 
 | TransportDescription::~TransportDescription() = default; | 
 |  | 
 | TransportDescription& TransportDescription::operator=( | 
 |     const TransportDescription& from) { | 
 |   // Self-assignment | 
 |   if (this == &from) | 
 |     return *this; | 
 |  | 
 |   transport_options = from.transport_options; | 
 |   ice_ufrag = from.ice_ufrag; | 
 |   ice_pwd = from.ice_pwd; | 
 |   ice_mode = from.ice_mode; | 
 |   connection_role = from.connection_role; | 
 |  | 
 |   identity_fingerprint.reset(CopyFingerprint(from.identity_fingerprint.get())); | 
 |   return *this; | 
 | } | 
 |  | 
 | }  // namespace webrtc |