diff --git a/src/CompilerServices/MemoryExtensions.cs b/src/CompilerServices/MemoryExtensions.cs new file mode 100644 index 000000000..9cda53273 --- /dev/null +++ b/src/CompilerServices/MemoryExtensions.cs @@ -0,0 +1,19 @@ +using System; +using System.Text; + +namespace SIPSorcery; + +internal static class MemoryExtensions +{ + public static string ToLowerString(this ReadOnlySpan span) + { + var stringBuilder = new StringBuilder(span.Length); + + foreach (var c in span) + { + stringBuilder.Append(char.ToLower(c)); + } + + return stringBuilder.ToString(); + } +} diff --git a/src/CompilerServices/ProtocolTypeExtensions.cs b/src/CompilerServices/ProtocolTypeExtensions.cs new file mode 100644 index 000000000..b73a38106 --- /dev/null +++ b/src/CompilerServices/ProtocolTypeExtensions.cs @@ -0,0 +1,41 @@ +using System.Net.Sockets; + +namespace SIPSorcery; + +internal static class ProtocolTypeExtensions +{ + public static string ToLowerString(this ProtocolType protocolType) + { + return protocolType switch + { + ProtocolType.IP => "ip", + + ProtocolType.Icmp => "icmp", + ProtocolType.Igmp => "igmp", + ProtocolType.Ggp => "ggp", + + ProtocolType.IPv4 => "ipv4", + ProtocolType.Tcp => "tcp", + ProtocolType.Pup => "pup", + ProtocolType.Udp => "udp", + ProtocolType.Idp => "idp", + ProtocolType.IPv6 => "ipv6", + ProtocolType.IPv6RoutingHeader => "routing", + ProtocolType.IPv6FragmentHeader => "fragment", + ProtocolType.IPSecEncapsulatingSecurityPayload => "ipsecencapsulatingsecuritypayload", + ProtocolType.IPSecAuthenticationHeader => "ipsecauthenticationheader", + ProtocolType.IcmpV6 => "icmpv6", + ProtocolType.IPv6NoNextHeader => "nonext", + ProtocolType.IPv6DestinationOptions => "dstopts", + ProtocolType.ND => "nd", + ProtocolType.Raw => "raw", + + ProtocolType.Ipx => "ipx", + ProtocolType.Spx => "spx", + ProtocolType.SpxII => "spx2", + ProtocolType.Unknown => "unknown", + + _ => protocolType.ToString().ToLowerInvariant() + }; + } +} diff --git a/src/CompilerServices/StringBuilderExtensions.cs b/src/CompilerServices/StringBuilderExtensions.cs new file mode 100644 index 000000000..6473de83a --- /dev/null +++ b/src/CompilerServices/StringBuilderExtensions.cs @@ -0,0 +1,12 @@ +using System; +using System.Text; + +namespace SIPSorcery +{ + internal static class StringBuilderExtensions + { +#if NETSTANDARD2_0|| NET462 + public static StringBuilder Append(this StringBuilder builder, ReadOnlySpan value) => builder.Append(value.ToString()); +#endif + } +} diff --git a/src/SIPSorcery.csproj b/src/SIPSorcery.csproj index ef675d569..fc9c0c1fd 100755 --- a/src/SIPSorcery.csproj +++ b/src/SIPSorcery.csproj @@ -20,6 +20,18 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -27,7 +39,7 @@ - netstandard2.0;netstandard2.1;netcoreapp3.1;net462;net5.0;net6.0;net8.0 + netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0;net6.0;net8.0 10.0 true $(NoWarn);SYSLIB0050 diff --git a/src/core/SIP/SIPConstants.cs b/src/core/SIP/SIPConstants.cs index 32da80841..1685c7c7c 100644 --- a/src/core/SIP/SIPConstants.cs +++ b/src/core/SIP/SIPConstants.cs @@ -616,43 +616,69 @@ public static class SIPExtensionHeaders /// A list of extensions that were understood and a boolean indicating whether any unknown extensions were present. public static List ParseSIPExtensions(string extensionList, out string unknownExtensions) { - List knownExtensions = new List(); - unknownExtensions = null; + List knownExtensions = new(); + StringBuilder unknownBuilder = null; - if (String.IsNullOrEmpty(extensionList) == false) + if (string.IsNullOrWhiteSpace(extensionList)) { - string[] extensions = extensionList.Trim().Split(','); + unknownExtensions = null; + return knownExtensions; + } + + ReadOnlySpan remaining = extensionList.AsSpan(); + while (true) + { + int commaIndex = remaining.IndexOf(','); + ReadOnlySpan extension = commaIndex == -1 ? remaining.Trim() : remaining.Slice(0, commaIndex).Trim(); - foreach (string extension in extensions) + if (!extension.IsEmpty) { - if (String.IsNullOrEmpty(extension) == false) + SIPExtensions? parsedExtension = null; + if (extension.Equals(PRACK.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + parsedExtension = SIPExtensions.Prack; + } + else if (extension.Equals(NO_REFER_SUB.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + parsedExtension = SIPExtensions.NoReferSub; + } + else if (extension.Equals(REPLACES.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + parsedExtension = SIPExtensions.Replaces; + } + else if (extension.Equals(SIPREC.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + parsedExtension = SIPExtensions.SipRec; + } + else if (extension.Equals(MULTIPLE_REFER.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + parsedExtension = SIPExtensions.MultipleRefer; + } + + if (parsedExtension.HasValue) + { + knownExtensions.Add(parsedExtension.GetValueOrDefault()); + } + else { - string trimmedExtension = extension.Trim().ToLower(); - switch (trimmedExtension) + unknownBuilder ??= new StringBuilder(); + if (unknownBuilder.Length > 0) { - case PRACK: - knownExtensions.Add(SIPExtensions.Prack); - break; - case NO_REFER_SUB: - knownExtensions.Add(SIPExtensions.NoReferSub); - break; - case REPLACES: - knownExtensions.Add(SIPExtensions.Replaces); - break; - case SIPREC: - knownExtensions.Add(SIPExtensions.SipRec); - break; - case MULTIPLE_REFER: - knownExtensions.Add(SIPExtensions.MultipleRefer); - break; - default: - unknownExtensions += (unknownExtensions != null) ? $",{extension.Trim()}" : extension.Trim(); - break; + unknownBuilder.Append(','); } + unknownBuilder.Append(extension); } } + + if (commaIndex == -1) + { + break; + } + + remaining = remaining.Slice(commaIndex + 1); } + unknownExtensions = unknownBuilder?.ToString(); return knownExtensions; } } diff --git a/src/core/SIP/SIPEndPoint.cs b/src/core/SIP/SIPEndPoint.cs index ac5a02f69..438c34f85 100644 --- a/src/core/SIP/SIPEndPoint.cs +++ b/src/core/SIP/SIPEndPoint.cs @@ -137,11 +137,11 @@ public static SIPEndPoint ParseSIPEndPoint(string sipEndPointStr) return null; } - if (sipEndPointStr.ToLower().StartsWith("udp:") || - sipEndPointStr.ToLower().StartsWith("tcp:") || - sipEndPointStr.ToLower().StartsWith("tls:") || - sipEndPointStr.ToLower().StartsWith("ws:") || - sipEndPointStr.ToLower().StartsWith("wss:")) + if (sipEndPointStr.StartsWith("udp:", StringComparison.OrdinalIgnoreCase) || + sipEndPointStr.StartsWith("tcp:", StringComparison.OrdinalIgnoreCase) || + sipEndPointStr.StartsWith("tls:", StringComparison.OrdinalIgnoreCase) || + sipEndPointStr.StartsWith("ws:", StringComparison.OrdinalIgnoreCase) || + sipEndPointStr.StartsWith("wss:", StringComparison.OrdinalIgnoreCase)) { return ParseSerialisedSIPEndPoint(sipEndPointStr); } diff --git a/src/core/SIP/SIPHeader.cs b/src/core/SIP/SIPHeader.cs index e46e04100..dabb5025f 100644 --- a/src/core/SIP/SIPHeader.cs +++ b/src/core/SIP/SIPHeader.cs @@ -1648,11 +1648,9 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) try { - string headerNameLower = headerName.ToLower(); - #region Via - if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_VIA || - headerNameLower == SIPHeaders.SIP_HEADER_VIA.ToLower()) + if (string.Equals(headerName, SIPHeaders.SIP_COMPACTHEADER_VIA, StringComparison.OrdinalIgnoreCase) || + string.Equals(headerName, SIPHeaders.SIP_HEADER_VIA, StringComparison.OrdinalIgnoreCase)) { //sipHeader.RawVia += headerValue; @@ -1668,14 +1666,14 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region CallId - else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_CALLID || - headerNameLower == SIPHeaders.SIP_HEADER_CALLID.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_COMPACTHEADER_CALLID, StringComparison.CurrentCultureIgnoreCase) || + string.Equals(headerName, SIPHeaders.SIP_HEADER_CALLID, StringComparison.OrdinalIgnoreCase)) { sipHeader.CallId = headerValue; } #endregion #region CSeq - else if (headerNameLower == SIPHeaders.SIP_HEADER_CSEQ.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_CSEQ, StringComparison.OrdinalIgnoreCase)) { //sipHeader.RawCSeq += headerValue; @@ -1703,7 +1701,7 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region Expires - else if (headerNameLower == SIPHeaders.SIP_HEADER_EXPIRES.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_EXPIRES, StringComparison.OrdinalIgnoreCase)) { //sipHeader.RawExpires += headerValue; @@ -1714,7 +1712,7 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region Min-Expires - else if (headerNameLower == SIPHeaders.SIP_HEADER_MINEXPIRES.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_MINEXPIRES, StringComparison.OrdinalIgnoreCase)) { if (!Int64.TryParse(headerValue, out sipHeader.MinExpires)) { @@ -1723,8 +1721,8 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region Contact - else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_CONTACT || - headerNameLower == SIPHeaders.SIP_HEADER_CONTACT.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_COMPACTHEADER_CONTACT, StringComparison.CurrentCultureIgnoreCase) || + string.Equals(headerName, SIPHeaders.SIP_HEADER_CONTACT, StringComparison.OrdinalIgnoreCase)) { List contacts = SIPContactHeader.ParseContactHeader(headerValue); if (contacts != null && contacts.Count > 0) @@ -1734,56 +1732,56 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region From - else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_FROM || - headerNameLower == SIPHeaders.SIP_HEADER_FROM.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_COMPACTHEADER_FROM, StringComparison.CurrentCultureIgnoreCase) || + string.Equals(headerName, SIPHeaders.SIP_HEADER_FROM, StringComparison.OrdinalIgnoreCase)) { //sipHeader.RawFrom = headerValue; sipHeader.From = SIPFromHeader.ParseFromHeader(headerValue); } #endregion #region To - else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_TO || - headerNameLower == SIPHeaders.SIP_HEADER_TO.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_COMPACTHEADER_TO, StringComparison.CurrentCultureIgnoreCase) || + string.Equals(headerName, SIPHeaders.SIP_HEADER_TO, StringComparison.OrdinalIgnoreCase)) { //sipHeader.RawTo = headerValue; sipHeader.To = SIPToHeader.ParseToHeader(headerValue); } #endregion #region WWWAuthenticate - else if (headerNameLower == SIPHeaders.SIP_HEADER_WWWAUTHENTICATE.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_WWWAUTHENTICATE, StringComparison.OrdinalIgnoreCase)) { //sipHeader.RawAuthentication = headerValue; sipHeader.AuthenticationHeaders.Add(SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.WWWAuthenticate, headerValue)); } #endregion #region Authorization - else if (headerNameLower == SIPHeaders.SIP_HEADER_AUTHORIZATION.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_AUTHORIZATION, StringComparison.OrdinalIgnoreCase)) { //sipHeader.RawAuthentication = headerValue; sipHeader.AuthenticationHeaders.Add(SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.Authorize, headerValue)); } #endregion #region ProxyAuthentication - else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXYAUTHENTICATION.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_PROXYAUTHENTICATION, StringComparison.OrdinalIgnoreCase)) { //sipHeader.RawAuthentication = headerValue; sipHeader.AuthenticationHeaders.Add(SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.ProxyAuthenticate, headerValue)); } #endregion #region ProxyAuthorization - else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXYAUTHORIZATION.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_PROXYAUTHORIZATION, StringComparison.OrdinalIgnoreCase)) { sipHeader.AuthenticationHeaders.Add(SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.ProxyAuthorization, headerValue)); } #endregion #region UserAgent - else if (headerNameLower == SIPHeaders.SIP_HEADER_USERAGENT.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_USERAGENT, StringComparison.OrdinalIgnoreCase)) { sipHeader.UserAgent = headerValue; } #endregion #region MaxForwards - else if (headerNameLower == SIPHeaders.SIP_HEADER_MAXFORWARDS.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_MAXFORWARDS, StringComparison.OrdinalIgnoreCase)) { if (!Int32.TryParse(headerValue, out sipHeader.MaxForwards)) { @@ -1792,8 +1790,8 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region ContentLength - else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_CONTENTLENGTH || - headerNameLower == SIPHeaders.SIP_HEADER_CONTENTLENGTH.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_COMPACTHEADER_CONTENTLENGTH, StringComparison.CurrentCultureIgnoreCase) || + string.Equals(headerName, SIPHeaders.SIP_HEADER_CONTENTLENGTH, StringComparison.OrdinalIgnoreCase)) { if (!Int32.TryParse(headerValue, out sipHeader.ContentLength)) { @@ -1802,20 +1800,20 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region ContentType - else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_CONTENTTYPE || - headerNameLower == SIPHeaders.SIP_HEADER_CONTENTTYPE.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_COMPACTHEADER_CONTENTTYPE, StringComparison.CurrentCultureIgnoreCase) || + string.Equals(headerName, SIPHeaders.SIP_HEADER_CONTENTTYPE, StringComparison.OrdinalIgnoreCase)) { sipHeader.ContentType = headerValue; } #endregion #region Accept - else if (headerNameLower == SIPHeaders.SIP_HEADER_ACCEPT.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_ACCEPT, StringComparison.OrdinalIgnoreCase)) { sipHeader.Accept = headerValue; } #endregion #region Route - else if (headerNameLower == SIPHeaders.SIP_HEADER_ROUTE.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_ROUTE, StringComparison.OrdinalIgnoreCase)) { SIPRouteSet routeSet = SIPRouteSet.ParseSIPRouteSet(headerValue); if (routeSet != null) @@ -1828,7 +1826,7 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region RecordRoute - else if (headerNameLower == SIPHeaders.SIP_HEADER_RECORDROUTE.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_RECORDROUTE, StringComparison.OrdinalIgnoreCase)) { SIPRouteSet recordRouteSet = SIPRouteSet.ParseSIPRouteSet(headerValue); if (recordRouteSet != null) @@ -1841,37 +1839,37 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region Allow-Events - else if (headerNameLower == SIPHeaders.SIP_HEADER_ALLOW_EVENTS || headerNameLower == SIPHeaders.SIP_COMPACTHEADER_ALLOWEVENTS) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_ALLOW_EVENTS, StringComparison.CurrentCultureIgnoreCase) || string.Equals(headerName, SIPHeaders.SIP_COMPACTHEADER_ALLOWEVENTS, StringComparison.CurrentCultureIgnoreCase)) { sipHeader.AllowEvents = headerValue; } #endregion #region Event - else if (headerNameLower == SIPHeaders.SIP_HEADER_EVENT.ToLower() || headerNameLower == SIPHeaders.SIP_COMPACTHEADER_EVENT) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_EVENT, StringComparison.OrdinalIgnoreCase) || string.Equals(headerName, SIPHeaders.SIP_COMPACTHEADER_EVENT, StringComparison.CurrentCultureIgnoreCase)) { sipHeader.Event = headerValue; } #endregion #region SubscriptionState. - else if (headerNameLower == SIPHeaders.SIP_HEADER_SUBSCRIPTION_STATE.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_SUBSCRIPTION_STATE, StringComparison.OrdinalIgnoreCase)) { sipHeader.SubscriptionState = headerValue; } #endregion #region Timestamp. - else if (headerNameLower == SIPHeaders.SIP_HEADER_TIMESTAMP.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_TIMESTAMP, StringComparison.OrdinalIgnoreCase)) { sipHeader.Timestamp = headerValue; } #endregion #region Date. - else if (headerNameLower == SIPHeaders.SIP_HEADER_DATE.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_DATE, StringComparison.OrdinalIgnoreCase)) { sipHeader.Date = headerValue; } #endregion #region Refer-Sub. - else if (headerNameLower == SIPHeaders.SIP_HEADER_REFERSUB.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_REFERSUB, StringComparison.OrdinalIgnoreCase)) { if (sipHeader.ReferSub == null) { @@ -1884,8 +1882,8 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region Refer-To. - else if (headerNameLower == SIPHeaders.SIP_HEADER_REFERTO.ToLower() || - headerNameLower == SIPHeaders.SIP_COMPACTHEADER_REFERTO) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_REFERTO, StringComparison.OrdinalIgnoreCase) || + string.Equals(headerName, SIPHeaders.SIP_COMPACTHEADER_REFERTO, StringComparison.CurrentCultureIgnoreCase)) { if (sipHeader.ReferTo == null) { @@ -1898,19 +1896,19 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region Referred-By. - else if (headerNameLower == SIPHeaders.SIP_HEADER_REFERREDBY.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_REFERREDBY, StringComparison.OrdinalIgnoreCase)) { sipHeader.ReferredBy = headerValue; } #endregion #region Replaces. - else if (headerNameLower == SIPHeaders.SIP_HEADER_REPLACES.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_REPLACES, StringComparison.OrdinalIgnoreCase)) { sipHeader.Replaces = headerValue; } #endregion #region Require. - else if (headerNameLower == SIPHeaders.SIP_HEADER_REQUIRE.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_REQUIRE, StringComparison.OrdinalIgnoreCase)) { sipHeader.Require = headerValue; @@ -1921,32 +1919,32 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region Reason. - else if (headerNameLower == SIPHeaders.SIP_HEADER_REASON.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_REASON, StringComparison.OrdinalIgnoreCase)) { sipHeader.Reason = headerValue; } #endregion #region Proxy-ReceivedFrom. - else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_RECEIVEDFROM.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_PROXY_RECEIVEDFROM, StringComparison.OrdinalIgnoreCase)) { sipHeader.ProxyReceivedFrom = headerValue; } #endregion #region Proxy-ReceivedOn. - else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_RECEIVEDON.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_PROXY_RECEIVEDON, StringComparison.OrdinalIgnoreCase)) { sipHeader.ProxyReceivedOn = headerValue; } #endregion #region Proxy-SendFrom. - else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_SENDFROM.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_PROXY_SENDFROM, StringComparison.OrdinalIgnoreCase)) { sipHeader.ProxySendFrom = headerValue; } #endregion #region Supported - else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_SUPPORTED || - headerNameLower == SIPHeaders.SIP_HEADER_SUPPORTED.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_COMPACTHEADER_SUPPORTED, StringComparison.CurrentCultureIgnoreCase) || + string.Equals(headerName, SIPHeaders.SIP_HEADER_SUPPORTED, StringComparison.OrdinalIgnoreCase)) { sipHeader.Supported = headerValue; @@ -1957,133 +1955,133 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region Authentication-Info - else if (headerNameLower == SIPHeaders.SIP_HEADER_AUTHENTICATIONINFO.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_AUTHENTICATIONINFO, StringComparison.OrdinalIgnoreCase)) { sipHeader.AuthenticationInfo = headerValue; } #endregion #region Accept-Encoding - else if (headerNameLower == SIPHeaders.SIP_HEADER_ACCEPTENCODING.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_ACCEPTENCODING, StringComparison.OrdinalIgnoreCase)) { sipHeader.AcceptEncoding = headerValue; } #endregion #region Accept-Language - else if (headerNameLower == SIPHeaders.SIP_HEADER_ACCEPTLANGUAGE.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_ACCEPTLANGUAGE, StringComparison.OrdinalIgnoreCase)) { sipHeader.AcceptLanguage = headerValue; } #endregion #region Alert-Info - else if (headerNameLower == SIPHeaders.SIP_HEADER_ALERTINFO.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_ALERTINFO, StringComparison.OrdinalIgnoreCase)) { sipHeader.AlertInfo = headerValue; } #endregion #region Allow - else if (headerNameLower == SIPHeaders.SIP_HEADER_ALLOW.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_ALLOW, StringComparison.OrdinalIgnoreCase)) { sipHeader.Allow = headerValue; } #endregion #region Call-Info - else if (headerNameLower == SIPHeaders.SIP_HEADER_CALLINFO.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_CALLINFO, StringComparison.OrdinalIgnoreCase)) { sipHeader.CallInfo = headerValue; } #endregion #region Content-Disposition - else if (headerNameLower == SIPHeaders.SIP_HEADER_CONTENT_DISPOSITION.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_CONTENT_DISPOSITION, StringComparison.OrdinalIgnoreCase)) { sipHeader.ContentDisposition = headerValue; } #endregion #region Content-Encoding - else if (headerNameLower == SIPHeaders.SIP_HEADER_CONTENT_ENCODING.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_CONTENT_ENCODING, StringComparison.OrdinalIgnoreCase)) { sipHeader.ContentEncoding = headerValue; } #endregion #region Content-Language - else if (headerNameLower == SIPHeaders.SIP_HEADER_CONTENT_LANGUAGE.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_CONTENT_LANGUAGE, StringComparison.OrdinalIgnoreCase)) { sipHeader.ContentLanguage = headerValue; } #endregion #region Error-Info - else if (headerNameLower == SIPHeaders.SIP_HEADER_ERROR_INFO.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_ERROR_INFO, StringComparison.OrdinalIgnoreCase)) { sipHeader.ErrorInfo = headerValue; } #endregion #region In-Reply-To - else if (headerNameLower == SIPHeaders.SIP_HEADER_IN_REPLY_TO.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_IN_REPLY_TO, StringComparison.OrdinalIgnoreCase)) { sipHeader.InReplyTo = headerValue; } #endregion #region MIME-Version - else if (headerNameLower == SIPHeaders.SIP_HEADER_MIME_VERSION.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_MIME_VERSION, StringComparison.OrdinalIgnoreCase)) { sipHeader.MIMEVersion = headerValue; } #endregion #region Organization - else if (headerNameLower == SIPHeaders.SIP_HEADER_ORGANIZATION.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_ORGANIZATION, StringComparison.OrdinalIgnoreCase)) { sipHeader.Organization = headerValue; } #endregion #region Priority - else if (headerNameLower == SIPHeaders.SIP_HEADER_PRIORITY.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_PRIORITY, StringComparison.OrdinalIgnoreCase)) { sipHeader.Priority = headerValue; } #endregion #region Proxy-Require - else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_REQUIRE.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_PROXY_REQUIRE, StringComparison.OrdinalIgnoreCase)) { sipHeader.ProxyRequire = headerValue; } #endregion #region Reply-To - else if (headerNameLower == SIPHeaders.SIP_HEADER_REPLY_TO.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_REPLY_TO, StringComparison.OrdinalIgnoreCase)) { sipHeader.ReplyTo = headerValue; } #endregion #region Retry-After - else if (headerNameLower == SIPHeaders.SIP_HEADER_RETRY_AFTER.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_RETRY_AFTER, StringComparison.OrdinalIgnoreCase)) { sipHeader.RetryAfter = headerValue; } #endregion #region Subject - else if (headerNameLower == SIPHeaders.SIP_HEADER_SUBJECT.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_SUBJECT, StringComparison.OrdinalIgnoreCase)) { sipHeader.Subject = headerValue; } #endregion #region Unsupported - else if (headerNameLower == SIPHeaders.SIP_HEADER_UNSUPPORTED.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_UNSUPPORTED, StringComparison.OrdinalIgnoreCase)) { sipHeader.Unsupported = headerValue; } #endregion #region Warning - else if (headerNameLower == SIPHeaders.SIP_HEADER_WARNING.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_WARNING, StringComparison.OrdinalIgnoreCase)) { sipHeader.Warning = headerValue; } #endregion #region ETag - else if (headerNameLower == SIPHeaders.SIP_HEADER_ETAG.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_ETAG, StringComparison.OrdinalIgnoreCase)) { sipHeader.ETag = headerValue; } #endregion #region RAck - else if (headerNameLower == SIPHeaders.SIP_HEADER_RELIABLE_ACK.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_RELIABLE_ACK, StringComparison.OrdinalIgnoreCase)) { string[] rackFields = headerValue.Split(' '); if (rackFields?.Length == 0) @@ -2121,7 +2119,7 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region RSeq - else if (headerNameLower == SIPHeaders.SIP_HEADER_RELIABLE_SEQ.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_RELIABLE_SEQ, StringComparison.OrdinalIgnoreCase)) { if (!Int32.TryParse(headerValue, out sipHeader.RSeq)) { @@ -2130,25 +2128,25 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection) } #endregion #region Server - else if (headerNameLower == SIPHeaders.SIP_HEADER_SERVER.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_SERVER, StringComparison.OrdinalIgnoreCase)) { sipHeader.Server = headerValue; } #endregion #region P-Asserted-Indentity - else if (headerNameLower == SIPHeaders.SIP_HEADER_PASSERTED_IDENTITY.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_PASSERTED_IDENTITY, StringComparison.OrdinalIgnoreCase)) { sipHeader.PassertedIdentity.AddRange(SIPUriHeader.ParseHeader(headerValue)); } #endregion #region History-Info - else if (headerNameLower == SIPHeaders.SIP_HEADER_HISTORY_INFO.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_HISTORY_INFO, StringComparison.OrdinalIgnoreCase)) { sipHeader.HistoryInfo.AddRange(SIPUriHeader.ParseHeader(headerValue)); } #endregion #region Diversion - else if (headerNameLower == SIPHeaders.SIP_HEADER_DIVERSION.ToLower()) + else if (string.Equals(headerName, SIPHeaders.SIP_HEADER_DIVERSION, StringComparison.OrdinalIgnoreCase)) { sipHeader.Diversion.AddRange(SIPUriHeader.ParseHeader(headerValue)); } @@ -2397,7 +2395,7 @@ public string GetUnknownHeaderValue(string unknownHeaderName) string headerName = trimmedHeader.Substring(0, delimiterIndex).Trim(); - if (headerName.ToLower() == unknownHeaderName.ToLower()) + if (string.Equals(headerName, unknownHeaderName, StringComparison.OrdinalIgnoreCase)) { return trimmedHeader.Substring(delimiterIndex + 1).Trim(); } diff --git a/src/core/SIP/SIPURI.cs b/src/core/SIP/SIPURI.cs index e7cff1ae7..1cd1fc7fe 100644 --- a/src/core/SIP/SIPURI.cs +++ b/src/core/SIP/SIPURI.cs @@ -413,13 +413,13 @@ public static SIPURI ParseSIPURI(string uri) else if (sipURI.Host.IndexOf(':') != sipURI.Host.LastIndexOf(':')) { // If the host contains multiple ':' characters then it must be an IPv6 address which require a start '[' and an end ']'. - if (sipURI.Host.ToCharArray()[0] != '[') + if (sipURI.Host[0] != '[') { throw new SIPValidationException(SIPValidationFieldsEnum.URI, "The SIP URI host portion contained an IPv6 address that was missing the start '['."); } else if (!sipURI.Host.EndsWith("]") && (sipURI.Host.ToCharArray().Length < sipURI.Host.LastIndexOf(':') + 1 || - sipURI.Host.ToCharArray()[sipURI.Host.LastIndexOf(':') - 1] != ']')) + sipURI.Host[sipURI.Host.LastIndexOf(':') - 1] != ']')) { throw new SIPValidationException(SIPValidationFieldsEnum.URI, "The SIP URI host portion contained an IPv6 address that was missing the end ']'."); } diff --git a/src/core/SIP/SIPUserField.cs b/src/core/SIP/SIPUserField.cs index 6901c3f1f..adab199ee 100644 --- a/src/core/SIP/SIPUserField.cs +++ b/src/core/SIP/SIPUserField.cs @@ -144,25 +144,9 @@ public override string ToString() { try { - string userFieldStr = null; - - if (Name != null) - { - /*if(Regex.Match(Name, @"\s").Success) - { - userFieldStr = "\"" + Name + "\" "; - } - else - { - userFieldStr = Name + " "; - }*/ - - userFieldStr = "\"" + Name + "\" "; - } - - userFieldStr += "<" + URI.ToString() + ">" + Parameters.ToString(); - - return userFieldStr; + return Name != null + ? $"\"{Name}\" <{URI}>{Parameters}" + : $"<{URI}>{Parameters}"; } catch (Exception excp) { diff --git a/src/core/SIPEvents/SIPEventPackages.cs b/src/core/SIPEvents/SIPEventPackages.cs index 9159fe5dd..e80da80cc 100644 --- a/src/core/SIPEvents/SIPEventPackages.cs +++ b/src/core/SIPEvents/SIPEventPackages.cs @@ -85,20 +85,26 @@ public static SIPEventPackagesEnum Parse(string value) } else { - value = value.Trim().ToLower(); - switch (value) + ReadOnlySpan span = value.AsSpan().Trim(); + + if (span.Equals(DIALOG_EVENT_VALUE.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + return SIPEventPackagesEnum.Dialog; + } + else if (span.Equals(MESSAGE_SUMMARY_EVENT_VALUE.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + return SIPEventPackagesEnum.MessageSummary; + } + else if (span.Equals(PRESENCE_EVENT_VALUE.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + return SIPEventPackagesEnum.Presence; + } + else if (span.Equals(REFER_EVENT_VALUE.AsSpan(), StringComparison.OrdinalIgnoreCase)) { - case DIALOG_EVENT_VALUE: - return SIPEventPackagesEnum.Dialog; - case MESSAGE_SUMMARY_EVENT_VALUE: - return SIPEventPackagesEnum.MessageSummary; - case PRESENCE_EVENT_VALUE: - return SIPEventPackagesEnum.Presence; - case REFER_EVENT_VALUE: - return SIPEventPackagesEnum.Refer; - default: - return SIPEventPackagesEnum.None; + return SIPEventPackagesEnum.Refer; } + + return SIPEventPackagesEnum.None; } } @@ -163,9 +169,13 @@ public static bool IsValid(string value) { return false; } - else if (value.ToLower() == "cancelled" || value.ToLower() == "error" || value.ToLower() == "local-bye" || - value.ToLower() == "rejected" || value.ToLower() == "replaced" || value.ToLower() == "remote-bye" || - value.ToLower() == "timeout") + else if (string.Equals(value, "cancelled", StringComparison.OrdinalIgnoreCase) || + string.Equals(value, "error", StringComparison.OrdinalIgnoreCase) || + string.Equals(value, "local-bye", StringComparison.OrdinalIgnoreCase) || + string.Equals(value, "rejected", StringComparison.OrdinalIgnoreCase) || + string.Equals(value, "replaced", StringComparison.OrdinalIgnoreCase) || + string.Equals(value, "remote-bye", StringComparison.OrdinalIgnoreCase) || + string.Equals(value, "timeout", StringComparison.OrdinalIgnoreCase)) { return true; } @@ -183,26 +193,38 @@ public static SIPEventDialogStateEvent Parse(string value) } else { - string trimmedValue = value.Trim().ToLower(); - switch (trimmedValue) + ReadOnlySpan span = value.AsSpan().Trim(); + + if (span.Equals("cancelled".AsSpan(), StringComparison.OrdinalIgnoreCase)) { - case "cancelled": - return SIPEventDialogStateEvent.Cancelled; - case "error": - return SIPEventDialogStateEvent.Error; - case "local-bye": - return SIPEventDialogStateEvent.LocalBye; - case "rejected": - return SIPEventDialogStateEvent.Rejected; - case "replaced": - return SIPEventDialogStateEvent.Replaced; - case "remote-bye": - return SIPEventDialogStateEvent.RemoteBye; - case "timeout": - return SIPEventDialogStateEvent.Timeout; - default: - throw new ArgumentException("The value is not valid for a SIPEventDialogStateEvent."); + return SIPEventDialogStateEvent.Cancelled; } + else if (span.Equals("error".AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + return SIPEventDialogStateEvent.Error; + } + else if (span.Equals("local-bye".AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + return SIPEventDialogStateEvent.LocalBye; + } + else if (span.Equals("rejected".AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + return SIPEventDialogStateEvent.Rejected; + } + else if (span.Equals("replaced".AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + return SIPEventDialogStateEvent.Replaced; + } + else if (span.Equals("remote-bye".AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + return SIPEventDialogStateEvent.RemoteBye; + } + else if (span.Equals("timeout".AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + return SIPEventDialogStateEvent.Timeout; + } + + throw new ArgumentException("The value is not valid for a SIPEventDialogStateEvent."); } } diff --git a/src/net/DtlsSrtp/DtlsUtils.cs b/src/net/DtlsSrtp/DtlsUtils.cs index 09f5d37ac..89d105c6a 100755 --- a/src/net/DtlsSrtp/DtlsUtils.cs +++ b/src/net/DtlsSrtp/DtlsUtils.cs @@ -514,20 +514,24 @@ private static byte[] ConvertRSAParametersField(BigInteger n, int size) /// The hash algorithm to check. public static bool IsHashSupported(string hashAlgorithm) { - switch (hashAlgorithm.ToLower()) - { - case "sha1": - case "sha-1": - case "sha256": - case "sha-256": - case "sha384": - case "sha-384": - case "sha512": - case "sha-512": - return true; - default: - return false; - } + return hashAlgorithm != null && IsHashSupported(hashAlgorithm.AsSpan()); + } + + /// + /// Verifies the hash algorithm is supported by the utility functions in this class. + /// + /// The hash algorithm to check. + public static bool IsHashSupported(ReadOnlySpan hashAlgorithm) + { + return !hashAlgorithm.IsEmpty && ( + hashAlgorithm.Equals("sha1".AsSpan(), StringComparison.OrdinalIgnoreCase) || + hashAlgorithm.Equals("sha-1".AsSpan(), StringComparison.OrdinalIgnoreCase) || + hashAlgorithm.Equals("sha256".AsSpan(), StringComparison.OrdinalIgnoreCase) || + hashAlgorithm.Equals("sha-256".AsSpan(), StringComparison.OrdinalIgnoreCase) || + hashAlgorithm.Equals("sha384".AsSpan(), StringComparison.OrdinalIgnoreCase) || + hashAlgorithm.Equals("sha-384".AsSpan(), StringComparison.OrdinalIgnoreCase) || + hashAlgorithm.Equals("sha512".AsSpan(), StringComparison.OrdinalIgnoreCase) || + hashAlgorithm.Equals("sha-512".AsSpan(), StringComparison.OrdinalIgnoreCase)); } public static string ExportToDerBase64(Certificate certificate) diff --git a/src/net/ICE/RTCIceCandidate.cs b/src/net/ICE/RTCIceCandidate.cs index bfba165c0..db01353d5 100644 --- a/src/net/ICE/RTCIceCandidate.cs +++ b/src/net/ICE/RTCIceCandidate.cs @@ -321,7 +321,7 @@ public void SetDestinationEndPoint(IPEndPoint destinationEP) private string GetFoundation() { - var serverProtocol = IceServer != null ? IceServer.Protocol.ToString().ToLower() : "udp"; + var serverProtocol = IceServer != null ? IceServer.Protocol.ToLowerString() : "udp"; var builder = new System.Text.StringBuilder(); builder = builder.Append(type).Append(address).Append(protocol).Append(serverProtocol); byte[] bytes = System.Text.Encoding.ASCII.GetBytes(builder.ToString()); diff --git a/src/net/ICE/RtpIceChannel.cs b/src/net/ICE/RtpIceChannel.cs index d53cd7f3a..9a7160a61 100755 --- a/src/net/ICE/RtpIceChannel.cs +++ b/src/net/ICE/RtpIceChannel.cs @@ -1388,7 +1388,7 @@ private async Task UpdateChecklist(RTCIceCandidate localCandidate, RTCIceCandida // Attempt to resolve the remote candidate address. if (!IPAddress.TryParse(remoteCandidate.address, out var remoteCandidateIPAddr)) { - if (remoteCandidate.address.ToLower().EndsWith(MDNS_TLD)) + if (remoteCandidate.address.EndsWith(MDNS_TLD, StringComparison.OrdinalIgnoreCase)) { var addresses = await ResolveMdnsName(remoteCandidate).ConfigureAwait(false); if (addresses.Length == 0) diff --git a/src/net/RTP/AudioStream.cs b/src/net/RTP/AudioStream.cs index f39e6462e..10b96cc2e 100644 --- a/src/net/RTP/AudioStream.cs +++ b/src/net/RTP/AudioStream.cs @@ -243,12 +243,12 @@ public virtual Task SendDtmf(byte key, CancellationToken ct) public void CheckAudioFormatsNegotiation() { if (LocalTrack != null && - LocalTrack.Capabilities.Where(x => x.Name().ToLower() != SDP.TELEPHONE_EVENT_ATTRIBUTE).Count() > 0) + LocalTrack.Capabilities.Where(x => !x.Name().Equals(SDP.TELEPHONE_EVENT_ATTRIBUTE, StringComparison.CurrentCultureIgnoreCase)).Count() > 0) { OnAudioFormatsNegotiatedByIndex?.Invoke( Index, LocalTrack.Capabilities - .Where(x => x.Name().ToLower() != SDP.TELEPHONE_EVENT_ATTRIBUTE) + .Where(x => !x.Name().Equals(SDP.TELEPHONE_EVENT_ATTRIBUTE, StringComparison.CurrentCultureIgnoreCase)) .Select(x => x.ToAudioFormat()).ToList()); } } diff --git a/src/net/RTP/RTPSession.cs b/src/net/RTP/RTPSession.cs index baaeabfe9..32e8e33c1 100755 --- a/src/net/RTP/RTPSession.cs +++ b/src/net/RTP/RTPSession.cs @@ -1234,16 +1234,16 @@ public virtual SetDescriptionResultEnum SetRemoteDescription(SdpType sdpType, SD // Adjust the local track's RTP event capability if the remote party has specified a different payload ID. var currentLocalTrackCapabilities = currentMediaStream.LocalTrack.Capabilities; SDPAudioVideoMediaFormat? localRTPEventCapabilities = null; - if (currentLocalTrackCapabilities.Any(x => x.Name().ToLower() == SDP.TELEPHONE_EVENT_ATTRIBUTE)) + if (currentLocalTrackCapabilities.Any(x => x.Name().Equals(SDP.TELEPHONE_EVENT_ATTRIBUTE, StringComparison.CurrentCultureIgnoreCase))) { - localRTPEventCapabilities = currentLocalTrackCapabilities.First(x => x.Name().ToLower() == SDP.TELEPHONE_EVENT_ATTRIBUTE); + localRTPEventCapabilities = currentLocalTrackCapabilities.First(x => x.Name().Equals(SDP.TELEPHONE_EVENT_ATTRIBUTE, StringComparison.CurrentCultureIgnoreCase)); } else { localRTPEventCapabilities = MediaStream.DefaultRTPEventFormat; } - currentMediaStream.LocalTrack.Capabilities = capabilities.Where(x => x.Name().ToLower() != SDP.TELEPHONE_EVENT_ATTRIBUTE).ToList(); + currentMediaStream.LocalTrack.Capabilities = capabilities.Where(x => !x.Name().Equals(SDP.TELEPHONE_EVENT_ATTRIBUTE, StringComparison.CurrentCultureIgnoreCase)).ToList(); if (localRTPEventCapabilities != null) { currentMediaStream.LocalTrack.Capabilities.Add(localRTPEventCapabilities.Value); @@ -1256,7 +1256,7 @@ public virtual SetDescriptionResultEnum SetRemoteDescription(SdpType sdpType, SD if (!commonEventFormat.IsEmpty()) { currentMediaStream.NegotiatedRtpEventPayloadID = commonEventFormat.ID; - currentMediaStream.LocalTrack.Capabilities.RemoveAll(x => x.Name().ToLower() == SDP.TELEPHONE_EVENT_ATTRIBUTE); + currentMediaStream.LocalTrack.Capabilities.RemoveAll(x => x.Name().Equals(SDP.TELEPHONE_EVENT_ATTRIBUTE, StringComparison.CurrentCultureIgnoreCase)); currentMediaStream.LocalTrack.Capabilities.Add(commonEventFormat); } } @@ -1275,7 +1275,7 @@ public virtual SetDescriptionResultEnum SetRemoteDescription(SdpType sdpType, SD if (currentMediaStream.MediaType == SDPMediaTypesEnum.audio) { - if (capabilities?.Where(x => x.Name().ToLower() != SDP.TELEPHONE_EVENT_ATTRIBUTE).Count() == 0) + if (capabilities?.Where(x => !x.Name().Equals(SDP.TELEPHONE_EVENT_ATTRIBUTE, StringComparison.CurrentCultureIgnoreCase)).Count() == 0) { return SetDescriptionResultEnum.AudioIncompatible; } diff --git a/src/net/RTSP/RTSPHeader.cs b/src/net/RTSP/RTSPHeader.cs index 1d1854820..74cb189dd 100644 --- a/src/net/RTSP/RTSPHeader.cs +++ b/src/net/RTSP/RTSPHeader.cs @@ -335,19 +335,19 @@ public static RTSPHeader ParseRTSPHeaders(string[] headersCollection) string headerNameLower = headerName.ToLower(); #region Accept - if (headerNameLower == RTSPHeaders.RTSP_HEADER_ACCEPT.ToLower()) + if (headerNameLower.Equals(RTSPHeaders.RTSP_HEADER_ACCEPT, StringComparison.CurrentCultureIgnoreCase)) { rtspHeader.Accept = headerValue; } #endregion #region ContentType - if (headerNameLower == RTSPHeaders.RTSP_HEADER_CONTENTTYPE.ToLower()) + if (headerNameLower.Equals(RTSPHeaders.RTSP_HEADER_CONTENTTYPE, StringComparison.CurrentCultureIgnoreCase)) { rtspHeader.ContentType = headerValue; } #endregion #region ContentLength - if (headerNameLower == RTSPHeaders.RTSP_HEADER_CONTENTLENGTH.ToLower()) + if (headerNameLower.Equals(RTSPHeaders.RTSP_HEADER_CONTENTLENGTH, StringComparison.CurrentCultureIgnoreCase)) { rtspHeader.RawCSeq = headerValue; @@ -362,7 +362,7 @@ public static RTSPHeader ParseRTSPHeaders(string[] headersCollection) } #endregion #region CSeq - if (headerNameLower == RTSPHeaders.RTSP_HEADER_CSEQ.ToLower()) + if (headerNameLower.Equals(RTSPHeaders.RTSP_HEADER_CSEQ, StringComparison.CurrentCultureIgnoreCase)) { rtspHeader.RawCSeq = headerValue; @@ -379,13 +379,13 @@ public static RTSPHeader ParseRTSPHeaders(string[] headersCollection) } #endregion #region Session - if (headerNameLower == RTSPHeaders.RTSP_HEADER_SESSION.ToLower()) + if (headerNameLower.Equals(RTSPHeaders.RTSP_HEADER_SESSION, StringComparison.CurrentCultureIgnoreCase)) { rtspHeader.Session = headerValue; } #endregion #region Transport - if (headerNameLower == RTSPHeaders.RTSP_HEADER_TRANSPORT.ToLower()) + if (headerNameLower.Equals(RTSPHeaders.RTSP_HEADER_TRANSPORT, StringComparison.CurrentCultureIgnoreCase)) { rtspHeader.Transport = RTSPTransportHeader.Parse(headerValue); } diff --git a/src/net/SDP/SDPAudioVideoMediaFormat.cs b/src/net/SDP/SDPAudioVideoMediaFormat.cs index 24567a10b..ef1cfb8ea 100755 --- a/src/net/SDP/SDPAudioVideoMediaFormat.cs +++ b/src/net/SDP/SDPAudioVideoMediaFormat.cs @@ -39,7 +39,7 @@ public struct SDPAudioVideoMediaFormat public const int DYNAMIC_ID_MAX = 127; public const int DEFAULT_AUDIO_CHANNEL_COUNT = 1; - public static SDPAudioVideoMediaFormat Empty = new SDPAudioVideoMediaFormat() { _isEmpty = true }; + public static SDPAudioVideoMediaFormat Empty = new SDPAudioVideoMediaFormat(); /// /// Indicates whether the format is for audio or video. @@ -117,7 +117,7 @@ public IEnumerable SupportedRtcpFeedbackMessages /// //public string Name { get; set; } - private bool _isEmpty; + private bool _isNotEmpty; /// /// Creates a new SDP media format for a well known media type. Well known type are those that use @@ -131,7 +131,7 @@ public SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum knownFormat) ID = (int)knownFormat; Rtpmap = null; Fmtp = null; - _isEmpty = false; + _isNotEmpty = true; if (Kind == SDPMediaTypesEnum.audio) { @@ -145,28 +145,20 @@ public SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum knownFormat) } } - public bool IsH264 - { - get - { - return (Rtpmap ?? "").ToUpperInvariant().Trim().StartsWith("H264"); - } - } + public bool IsH264 => RtmapIs("H264"); - public bool IsMJPEG - { - get - { - return (Rtpmap ?? "").ToUpperInvariant().Trim().StartsWith("JPEG"); - } - } + public bool IsMJPEG => RtmapIs("JPEG"); - public bool isH265 + public bool isH265 => RtmapIs("H265"); + + private bool RtmapIs(string codec) { - get + if (Rtpmap is null) { - return (Rtpmap ?? "").ToUpperInvariant().Trim().StartsWith("H265"); + return false; } + + return Rtpmap.AsSpan().TrimStart().StartsWith(codec.AsSpan(), StringComparison.OrdinalIgnoreCase); } public bool CheckCompatible() @@ -225,7 +217,7 @@ public SDPAudioVideoMediaFormat(SDPMediaTypesEnum kind, int id, string rtpmap, s ID = id; Rtpmap = rtpmap; Fmtp = fmtp; - _isEmpty = false; + _isNotEmpty = true; } /// @@ -247,7 +239,7 @@ public SDPAudioVideoMediaFormat(SDPMediaTypesEnum kind, int id, string name, int ID = id; Rtpmap = null; Fmtp = fmtp; - _isEmpty = false; + _isNotEmpty = true; Rtpmap = SetRtpmap(name, clockRate, channels); } @@ -264,7 +256,7 @@ public SDPAudioVideoMediaFormat(AudioFormat audioFormat) ID = audioFormat.FormatID; Rtpmap = null; Fmtp = audioFormat.Parameters; - _isEmpty = false; + _isNotEmpty = true; Rtpmap = SetRtpmap(audioFormat.FormatName, audioFormat.RtpClockRate, audioFormat.ChannelCount); } @@ -281,7 +273,7 @@ public SDPAudioVideoMediaFormat(VideoFormat videoFormat) ID = videoFormat.FormatID; Rtpmap = null; Fmtp = videoFormat.Parameters; - _isEmpty = false; + _isNotEmpty = true; Rtpmap = SetRtpmap(videoFormat.FormatName, videoFormat.ClockRate); } @@ -290,9 +282,9 @@ public SDPAudioVideoMediaFormat(TextFormat textFormat) { Kind = SDPMediaTypesEnum.text; ID = textFormat.FormatID; - Rtpmap = null; + Rtpmap = null; Fmtp = textFormat.Parameters; - _isEmpty = false; + _isNotEmpty = true; Rtpmap = SetRtpmap(textFormat.FormatName, textFormat.ClockRate); } @@ -301,7 +293,7 @@ private string SetRtpmap(string name, int clockRate, int channels = DEFAULT_AUDI ? $"{name}/{clockRate}" : (channels == DEFAULT_AUDIO_CHANNEL_COUNT) ? $"{name}/{clockRate}" : $"{name}/{clockRate}/{channels}"; - public bool IsEmpty() => _isEmpty; + public bool IsEmpty() => !_isNotEmpty; public int ClockRate() { if (Kind == SDPMediaTypesEnum.video) @@ -447,7 +439,7 @@ public static bool AreMatch(SDPAudioVideoMediaFormat format1, SDPAudioVideoMedia return true; } return false; - + } /// @@ -600,16 +592,20 @@ public static SDPAudioVideoMediaFormat GetCommonRtpEventFormat(ListIf found the matching format or the empty format if not. public static SDPAudioVideoMediaFormat GetFormatForName(List formats, string formatName) { - if (formats == null || formats.Count == 0) + if (formats != null && formats.Count != 0 && formatName != null) { + foreach (var format in formats) + { + if (string.Equals(format.Name(), formatName, StringComparison.OrdinalIgnoreCase)) + { + return format; + } + } + return Empty; } - else - { - return formats.Any(x => x.Name()?.ToLower() == formatName?.ToLower()) ? - formats.First(x => x.Name()?.ToLower() == formatName?.ToLower()) : - Empty; - } + + return Empty; } } } diff --git a/src/net/SDP/SDPSecurityDescription.cs b/src/net/SDP/SDPSecurityDescription.cs index a8025e57d..b62fb54e6 100644 --- a/src/net/SDP/SDPSecurityDescription.cs +++ b/src/net/SDP/SDPSecurityDescription.cs @@ -388,7 +388,7 @@ private static void parseKeySaltBase64(CryptoSuites cryptoSuite, string base64Ke private static void checkValidKeyInfoCharacters(string keyParameter, string keyInfo) { - foreach (char c in keyInfo.ToCharArray()) + foreach (char c in keyInfo) { if (c < 0x21 || c > 0x7e) { diff --git a/src/net/STUN/STUNDns.cs b/src/net/STUN/STUNDns.cs index 7e316ea60..459891253 100644 --- a/src/net/STUN/STUNDns.cs +++ b/src/net/STUN/STUNDns.cs @@ -185,7 +185,7 @@ private static async Task Resolve(STUNUri uri, QueryType queryType) { ServiceHostEntry srvResult = null; // No explicit port so use a SRV -> (A | AAAA -> A) record lookup. - var result = await _lookupClient.ResolveServiceAsync(uri.Host, uri.Scheme.ToString(), uri.Protocol.ToString().ToLower()).ConfigureAwait(false); + var result = await _lookupClient.ResolveServiceAsync(uri.Host, uri.Scheme.ToString(), uri.Protocol.ToLowerString()).ConfigureAwait(false); if (result == null || result.Count() == 0) { //logger.LogDebug("STUNDns SRV lookup returned no results for {uri}.", uri); diff --git a/src/net/STUN/STUNUri.cs b/src/net/STUN/STUNUri.cs index a13c2a1b4..6e0283562 100644 --- a/src/net/STUN/STUNUri.cs +++ b/src/net/STUN/STUNUri.cs @@ -236,7 +236,7 @@ public override string ToString() { if (Protocol != ProtocolType.Udp) { - return $"{Scheme}{SCHEME_ADDR_SEPARATOR}{Host}?transport={Protocol.ToString().ToLower()}"; + return $"{Scheme}{SCHEME_ADDR_SEPARATOR}{Host}?transport={Protocol.ToLowerString()}"; } else { @@ -247,7 +247,7 @@ public override string ToString() { if (Protocol != ProtocolType.Udp) { - return $"{Scheme}{SCHEME_ADDR_SEPARATOR}{Host}:{Port}?transport={Protocol.ToString().ToLower()}"; + return $"{Scheme}{SCHEME_ADDR_SEPARATOR}{Host}:{Port}?transport={Protocol.ToLowerString()}"; } else { diff --git a/src/net/WebRTC/IRTCPeerConnection.cs b/src/net/WebRTC/IRTCPeerConnection.cs index 142777c40..5f6df9f17 100755 --- a/src/net/WebRTC/IRTCPeerConnection.cs +++ b/src/net/WebRTC/IRTCPeerConnection.cs @@ -169,50 +169,45 @@ public static bool TryParse(string str, out RTCDtlsFingerprint fingerprint) { fingerprint = null; - if (string.IsNullOrEmpty(str)) + if (string.IsNullOrWhiteSpace(str)) { return false; } - else + + ReadOnlySpan span = str.AsSpan().Trim(); + int spaceIndex = span.IndexOf(' '); + if (spaceIndex == -1) { - int spaceIndex = str.IndexOf(' '); - if (spaceIndex == -1) - { - return false; - } - else - { - string algStr = str.Substring(0, spaceIndex); - string val = str.Substring(spaceIndex + 1); - - if (!DtlsUtils.IsHashSupported(algStr)) - { - return false; - } - else - { - fingerprint = new RTCDtlsFingerprint - { - algorithm = algStr, - value = val - }; - return true; - } - } + return false; } + + ReadOnlySpan algorithm = span.Slice(0, spaceIndex); + ReadOnlySpan value = span.Slice(spaceIndex + 1); + + if (!DtlsUtils.IsHashSupported(algorithm)) + { + return false; + } + + fingerprint = new RTCDtlsFingerprint + { + algorithm = algorithm.ToLowerString(), + value = value.ToLowerString() + }; + return true; } } - /// - /// Represents a certificate used to authenticate WebRTC communications. - /// - /// - /// TODO: - /// From https://www.w3.org/TR/webrtc/#methods-4: - /// "Implementations SHOULD store the sensitive keying material in a secure module safe from - /// same-process memory attacks." - /// - [Obsolete("Use RTCCertificate2 instead")] + /// + /// Represents a certificate used to authenticate WebRTC communications. + /// + /// + /// TODO: + /// From https://www.w3.org/TR/webrtc/#methods-4: + /// "Implementations SHOULD store the sensitive keying material in a secure module safe from + /// same-process memory attacks." + /// + [Obsolete("Use RTCCertificate2 instead")] public class RTCCertificate { /// diff --git a/src/net/WebRTC/RTCPeerConnection.cs b/src/net/WebRTC/RTCPeerConnection.cs index 0f871c34e..264c3033d 100755 --- a/src/net/WebRTC/RTCPeerConnection.cs +++ b/src/net/WebRTC/RTCPeerConnection.cs @@ -776,7 +776,6 @@ public SetDescriptionResultEnum setRemoteDescription(RTCSessionDescriptionInit i if (!string.IsNullOrWhiteSpace(dtlsFingerprint)) { - dtlsFingerprint = dtlsFingerprint.Trim().ToLower(); if (RTCDtlsFingerprint.TryParse(dtlsFingerprint, out var remoteFingerprint)) { RemotePeerDtlsFingerprint = remoteFingerprint; @@ -1818,7 +1817,7 @@ private bool DoDtlsHandshake(DtlsSrtpTransport dtlsHandle) var expectedFp = RemotePeerDtlsFingerprint; var remoteFingerprint = DtlsUtils.Fingerprint(expectedFp.algorithm, dtlsHandle.GetRemoteCertificate().GetCertificateAt(0)); - if (remoteFingerprint.value?.ToUpper() != expectedFp.value?.ToUpper()) + if (!string.Equals(remoteFingerprint.value, expectedFp.value, StringComparison.OrdinalIgnoreCase)) { logger.LogWarning("RTCPeerConnection remote certificate fingerprint mismatch, expected {ExpectedFingerprint}, actual {RemoteFingerprint}.", expectedFp, remoteFingerprint); Close("dtls fingerprint mismatch");