diff --git a/src/SIPSorcery/SIPSorcery.csproj b/src/SIPSorcery/SIPSorcery.csproj
index c45885c8a..b74d46e25 100644
--- a/src/SIPSorcery/SIPSorcery.csproj
+++ b/src/SIPSorcery/SIPSorcery.csproj
@@ -22,6 +22,10 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
@@ -35,13 +39,17 @@
+
+
+
+
netstandard2.0;netstandard2.1;netcoreapp3.1;net462;net5.0;net6.0;net8.0;net9.0;net10.0
- latest
+ 14.0
true
$(NoWarn);SYSLIB0050
True
@@ -66,11 +74,12 @@
https://github.com/sipsorcery-org/sipsorcery
git
master
+ true
SIP WebRTC VoIP RTP SDP STUN ICE SIPSorcery
-v10.0.8: Bug fixes.
-v10.0.7: Network address change fix for Unity.
--v10.0.6: Bug fixes.
--v10.0.5: Stable release. Bug fixes.
+-v10.0.6: Bug fixes.
+-v10.0.5: Stable release. Bug fixes.
-v10.0.4-pre: New SRTP and DTLS implementation (huge thanks to @jimm98y).
-v10.0.3: Removed null SRTP ciphers.
-v10.0.2: Removed use of master key index for SRTP.
@@ -94,7 +103,7 @@
-v8.0.0: RTP header extension improvements (thanks to @ChristopheI). Major version to 8 to reflect highest .net runtime supported.
en
10.0.8
- 10.0.8
+ 10.0.8
10.0.8
diff --git a/src/SIPSorcery/app/Media/Sources/AudioExtrasSource.cs b/src/SIPSorcery/app/Media/Sources/AudioExtrasSource.cs
index aa7f51dcf..f07533aa4 100644
--- a/src/SIPSorcery/app/Media/Sources/AudioExtrasSource.cs
+++ b/src/SIPSorcery/app/Media/Sources/AudioExtrasSource.cs
@@ -159,8 +159,7 @@ public int AudioSamplePeriodMilliseconds
{
if (value < AUDIO_SAMPLE_PERIOD_MILLISECONDS_MIN || value > AUDIO_SAMPLE_PERIOD_MILLISECONDS_MAX)
{
- throw new ApplicationException("Invalid value for the audio sample period. Must be between " +
- $"{AUDIO_SAMPLE_PERIOD_MILLISECONDS_MIN} and {AUDIO_SAMPLE_PERIOD_MILLISECONDS_MAX}ms.");
+ throw new ApplicationException($"Invalid value for the audio sample period. Must be between {AUDIO_SAMPLE_PERIOD_MILLISECONDS_MIN} and {AUDIO_SAMPLE_PERIOD_MILLISECONDS_MAX}ms.");
}
else
{
diff --git a/src/SIPSorcery/app/SIPPacketMangler.cs b/src/SIPSorcery/app/SIPPacketMangler.cs
index 8e2ddf1ba..80e6c57b0 100644
--- a/src/SIPSorcery/app/SIPPacketMangler.cs
+++ b/src/SIPSorcery/app/SIPPacketMangler.cs
@@ -55,7 +55,7 @@ public static string MangleSDP(string sdpBody, string publicIPAddress, out bool
&& pubaddr.AddressFamily == AddressFamily.InterNetworkV6
&& addr.AddressFamily == AddressFamily.InterNetworkV6)
{
- string mangledSDP = Regex.Replace(sdpBody, @"c=IN IP6 (?([:a-fA-F0-9]+))", "c=IN IP6" + publicIPAddress, RegexOptions.Singleline);
+ string mangledSDP = Regex.Replace(sdpBody, @"c=IN IP6 (?([:a-fA-F0-9]+))", $"c=IN IP6{publicIPAddress}", RegexOptions.Singleline);
wasMangled = true;
return mangledSDP;
@@ -65,7 +65,7 @@ public static string MangleSDP(string sdpBody, string publicIPAddress, out bool
&& addr.AddressFamily == AddressFamily.InterNetwork)
{
//logger.LogDebug("MangleSDP replacing private " + sdpAddress + " with " + publicIPAddress + ".");
- string mangledSDP = Regex.Replace(sdpBody, @"c=IN IP4 (?(\d+\.){3}\d+)", "c=IN IP4 " + publicIPAddress, RegexOptions.Singleline);
+ string mangledSDP = Regex.Replace(sdpBody, @"c=IN IP4 (?(\d+\.){3}\d+)", $"c=IN IP4 {publicIPAddress}", RegexOptions.Singleline);
wasMangled = true;
return mangledSDP;
diff --git a/src/SIPSorcery/app/SIPUserAgents/SIPCallDescriptor.cs b/src/SIPSorcery/app/SIPUserAgents/SIPCallDescriptor.cs
index b10540f13..d610db82a 100644
--- a/src/SIPSorcery/app/SIPUserAgents/SIPCallDescriptor.cs
+++ b/src/SIPSorcery/app/SIPUserAgents/SIPCallDescriptor.cs
@@ -160,7 +160,7 @@ public class SIPCallDescriptor
public SIPCallDescriptor(ISIPAccount toSIPAccount, string uri, string fromHeader, string contentType, string content)
{
ToSIPAccount = toSIPAccount;
- Uri = uri ?? toSIPAccount.SIPUsername + "@" + toSIPAccount.SIPDomain;
+ Uri = uri ?? $"{toSIPAccount.SIPUsername}@{toSIPAccount.SIPDomain}";
From = fromHeader;
ContentType = contentType;
Content = content;
@@ -291,14 +291,14 @@ public void ParseCallOptions(string options)
options = options.Trim('[', ']');
// Parse delay time option.
- Match delayCallMatch = Regex.Match(options, DELAY_CALL_OPTION_KEY + @"=(?\d+)");
+ Match delayCallMatch = Regex.Match(options, $@"{DELAY_CALL_OPTION_KEY}=(?\d+)");
if (delayCallMatch.Success)
{
int.TryParse(delayCallMatch.Result("${delaytime}"), out DelaySeconds);
}
// Parse redirect mode option.
- Match redirectModeMatch = Regex.Match(options, REDIRECT_MODE_OPTION_KEY + @"=(?\w)");
+ Match redirectModeMatch = Regex.Match(options, $@"{REDIRECT_MODE_OPTION_KEY}=(?\w)");
if (redirectModeMatch.Success)
{
string redirectMode = redirectModeMatch.Result("${redirectmode}");
@@ -321,42 +321,42 @@ public void ParseCallOptions(string options)
}
// Parse call duration limit option.
- Match callDurationMatch = Regex.Match(options, CALL_DURATION_OPTION_KEY + @"=(?\d+)");
+ Match callDurationMatch = Regex.Match(options, $@"{CALL_DURATION_OPTION_KEY}=(?\d+)");
if (callDurationMatch.Success)
{
int.TryParse(callDurationMatch.Result("${callduration}"), out CallDurationLimit);
}
// Parse the mangle option.
- Match mangleMatch = Regex.Match(options, MANGLE_MODE_OPTION_KEY + @"=(?\w+)");
+ Match mangleMatch = Regex.Match(options, $@"{MANGLE_MODE_OPTION_KEY}=(?\w+)");
if (mangleMatch.Success)
{
bool.TryParse(mangleMatch.Result("${mangle}"), out MangleResponseSDP);
}
// Parse the From header display name option.
- Match fromDisplayNameMatch = Regex.Match(options, FROM_DISPLAY_NAME_KEY + @"=(?.+?)(,|$)");
+ Match fromDisplayNameMatch = Regex.Match(options, $@"{FROM_DISPLAY_NAME_KEY}=(?.+?)(,|$)");
if (fromDisplayNameMatch.Success)
{
FromDisplayName = fromDisplayNameMatch.Result("${displayname}").Trim();
}
// Parse the From header URI username option.
- Match fromUsernameNameMatch = Regex.Match(options, FROM_USERNAME_KEY + @"=(?.+?)(,|$)");
+ Match fromUsernameNameMatch = Regex.Match(options, $@"{FROM_USERNAME_KEY}=(?.+?)(,|$)");
if (fromUsernameNameMatch.Success)
{
FromURIUsername = fromUsernameNameMatch.Result("${username}").Trim();
}
// Parse the From header URI host option.
- Match fromURIHostMatch = Regex.Match(options, FROM_HOST_KEY + @"=(?.+?)(,|$)");
+ Match fromURIHostMatch = Regex.Match(options, $@"{FROM_HOST_KEY}=(?.+?)(,|$)");
if (fromURIHostMatch.Success)
{
FromURIHost = fromURIHostMatch.Result("${host}").Trim();
}
// Parse the Transfer behaviour option.
- Match transferMatch = Regex.Match(options, TRANSFER_MODE_OPTION_KEY + @"=(?.+?)(,|$)");
+ Match transferMatch = Regex.Match(options, $@"{TRANSFER_MODE_OPTION_KEY}=(?.+?)(,|$)");
if (transferMatch.Success)
{
string transferMode = transferMatch.Result("${transfermode}");
@@ -387,28 +387,28 @@ public void ParseCallOptions(string options)
}
// Parse the request caller details option.
- Match callerDetailsMatch = Regex.Match(options, REQUEST_CALLER_DETAILS + @"=(?\w+)");
+ Match callerDetailsMatch = Regex.Match(options, $@"{REQUEST_CALLER_DETAILS}=(?\w+)");
if (callerDetailsMatch.Success)
{
bool.TryParse(callerDetailsMatch.Result("${callerdetails}"), out RequestCallerDetails);
}
// Parse the accountcode.
- Match accountCodeMatch = Regex.Match(options, ACCOUNT_CODE_KEY + @"=(?\w+)");
+ Match accountCodeMatch = Regex.Match(options, $@"{ACCOUNT_CODE_KEY}=(?\w+)");
if (accountCodeMatch.Success)
{
AccountCode = accountCodeMatch.Result("${accountCode}");
}
// Parse the rate code.
- Match rateCodeMatch = Regex.Match(options, RATE_CODE_KEY + @"=(?\w+)");
+ Match rateCodeMatch = Regex.Match(options, $@"{RATE_CODE_KEY}=(?\w+)");
if (rateCodeMatch.Success)
{
RateCode = rateCodeMatch.Result("${rateCode}");
}
// Parse the delayed reinvite option.
- Match delayedReinviteMatch = Regex.Match(options, DELAYED_REINVITE_KEY + @"=(?\d+)");
+ Match delayedReinviteMatch = Regex.Match(options, $@"{DELAYED_REINVITE_KEY}=(?\d+)");
if (delayedReinviteMatch.Success)
{
int.TryParse(delayedReinviteMatch.Result("${delayedReinvite}"), out ReinviteDelay);
@@ -457,7 +457,14 @@ public static List ParseCustomHeaders(string customHeaders)
//string headerName = customHeader.Substring(0, colonIndex).Trim();
//string headerValue = (customHeader.Length > colonIndex) ? customHeader.Substring(colonIndex + 1).Trim() : String.Empty;
- if (Regex.Match(customHeader.Trim(), "^(Via|From|Contact|CSeq|Call-ID|Max-Forwards|Content-Length)$", RegexOptions.IgnoreCase).Success)
+ var trimmedCustomHeader = customHeader.AsSpan().Trim();
+ if (trimmedCustomHeader.Equals(SIPHeaders.SIP_HEADER_VIA, StringComparison.OrdinalIgnoreCase) ||
+ trimmedCustomHeader.Equals(SIPHeaders.SIP_HEADER_FROM, StringComparison.OrdinalIgnoreCase) ||
+ trimmedCustomHeader.Equals(SIPHeaders.SIP_HEADER_CONTACT, StringComparison.OrdinalIgnoreCase) ||
+ trimmedCustomHeader.Equals(SIPHeaders.SIP_HEADER_CSEQ, StringComparison.OrdinalIgnoreCase) ||
+ trimmedCustomHeader.Equals(SIPHeaders.SIP_HEADER_CALLID, StringComparison.OrdinalIgnoreCase) ||
+ trimmedCustomHeader.Equals(SIPHeaders.SIP_HEADER_MAXFORWARDS, StringComparison.OrdinalIgnoreCase) ||
+ trimmedCustomHeader.Equals(SIPHeaders.SIP_HEADER_CONTENTLENGTH, StringComparison.OrdinalIgnoreCase))
{
logger.LogWarning("ParseCustomHeaders skipping custom header due to an non-permitted string in header name, {CustomHeader}.", customHeader);
continue;
diff --git a/src/SIPSorcery/app/SIPUserAgents/SIPClientUserAgent.cs b/src/SIPSorcery/app/SIPUserAgents/SIPClientUserAgent.cs
index f03060926..ffda6e131 100644
--- a/src/SIPSorcery/app/SIPUserAgents/SIPClientUserAgent.cs
+++ b/src/SIPSorcery/app/SIPUserAgents/SIPClientUserAgent.cs
@@ -286,7 +286,7 @@ public void Cancel(string reason = null)
// If auth header is included inside INVITE request, we re-include them inside CANCEL request
if (m_serverTransaction.TransactionRequest.Header.HasAuthenticationHeader)
{
- string username = (m_sipCallDescriptor.AuthUsername == null || m_sipCallDescriptor.AuthUsername.Trim().Length <= 0 ? m_sipCallDescriptor.Username : m_sipCallDescriptor.AuthUsername);
+ var username = string.IsNullOrWhiteSpace(m_sipCallDescriptor.AuthUsername) ? m_sipCallDescriptor.Username : m_sipCallDescriptor.AuthUsername;
SIPAuthorisationDigest authDigest = m_serverTransaction.TransactionRequest.Header.AuthenticationHeaders.First().SIPDigest;
authDigest.SetCredentials(username, m_sipCallDescriptor.Password, m_sipCallDescriptor.Uri, SIPMethodsEnum.CANCEL.ToString());
@@ -332,7 +332,7 @@ public void Hangup(string reason = null)
//SIPRequest byeRequest = GetByeRequest(m_serverTransaction.TransactionFinalResponse, m_sipDialogue.RemoteTarget);
SIPRequest byeRequest = m_sipDialogue.GetInDialogRequest(SIPMethodsEnum.BYE);
byeRequest.SetSendFromHints(m_serverTransaction.TransactionRequest.LocalSIPEndPoint);
-
+
if (!string.IsNullOrEmpty(reason))
{
// The REASON header gets pre-appended automatically in the SIPHeader class as "Reason: " when ToString() is called on the SIP Header class.
@@ -427,7 +427,7 @@ private Task ServerFinalResponseReceived(SIPEndPoint localSIPEndPoi
m_serverAuthAttempts = 1;
// Resend INVITE with credentials.
- string username = (m_sipCallDescriptor.AuthUsername != null && m_sipCallDescriptor.AuthUsername.Trim().Length > 0) ? m_sipCallDescriptor.AuthUsername : m_sipCallDescriptor.Username;
+ var username = !string.IsNullOrWhiteSpace(m_sipCallDescriptor.AuthUsername) ? m_sipCallDescriptor.AuthUsername : m_sipCallDescriptor.Username;
var authRequest = m_serverTransaction.TransactionRequest.DuplicateAndAuthenticate(sipResponse.Header.AuthenticationHeaders,
username, m_sipCallDescriptor.Password);
@@ -529,7 +529,7 @@ private Task ByeServerFinalResponseReceived(SIPEndPoint localSIPEnd
if (sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised)
{
- string username = (m_sipCallDescriptor.AuthUsername == null || m_sipCallDescriptor.AuthUsername.Trim().Length <= 0 ? m_sipCallDescriptor.Username : m_sipCallDescriptor.AuthUsername);
+ var username = string.IsNullOrWhiteSpace(m_sipCallDescriptor.AuthUsername) ? m_sipCallDescriptor.Username : m_sipCallDescriptor.AuthUsername;
var authRequest = transaction.TransactionRequest.DuplicateAndAuthenticate(sipResponse.Header.AuthenticationHeaders,
username, m_sipCallDescriptor.Password);
@@ -560,8 +560,9 @@ private SIPRequest GetInviteRequest(SIPCallDescriptor sipCallDescriptor, string
inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
inviteHeader.UserAgent = SIPConstants.SipUserAgentVersionString;
inviteHeader.Routes = routeSet;
- inviteHeader.Supported = SIPExtensionHeaders.REPLACES + ", " + SIPExtensionHeaders.NO_REFER_SUB
- + ((PrackSupported == true) ? ", " + SIPExtensionHeaders.PRACK : "");
+ inviteHeader.Supported = PrackSupported == true
+ ? $"{SIPExtensionHeaders.REPLACES}, {SIPExtensionHeaders.NO_REFER_SUB}, {SIPExtensionHeaders.PRACK}"
+ : $"{SIPExtensionHeaders.REPLACES}, {SIPExtensionHeaders.NO_REFER_SUB}";
inviteRequest.Header = inviteHeader;
@@ -587,13 +588,17 @@ private SIPRequest GetInviteRequest(SIPCallDescriptor sipCallDescriptor, string
{
continue;
}
- else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_USERAGENT))
+
+ var customHeaderSpan = customHeader.AsSpan().Trim();
+ if (customHeaderSpan.StartsWith(SIPHeaders.SIP_HEADER_USERAGENT, StringComparison.Ordinal))
{
- inviteRequest.Header.UserAgent = customHeader.Substring(customHeader.IndexOf(":") + 1).Trim();
+ inviteRequest.Header.UserAgent = customHeader.Substring(customHeader.IndexOf(':') + 1).Trim();
}
- else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_TO + ":"))
+ else if (customHeaderSpan.StartsWith(SIPHeaders.SIP_HEADER_TO, StringComparison.Ordinal) &&
+ customHeaderSpan.Length > SIPHeaders.SIP_HEADER_TO.Length &&
+ customHeaderSpan[SIPHeaders.SIP_HEADER_TO.Length] == ':')
{
- var customToHeader = SIPUserField.ParseSIPUserField(customHeader.Substring(customHeader.IndexOf(":") + 1).Trim());
+ var customToHeader = SIPUserField.ParseSIPUserField(customHeader.Substring(customHeader.IndexOf(':') + 1).Trim());
if (customToHeader != null)
{
inviteRequest.Header.To.ToUserField = customToHeader;
diff --git a/src/SIPSorcery/app/SIPUserAgents/SIPNonInviteClientUserAgent.cs b/src/SIPSorcery/app/SIPUserAgents/SIPNonInviteClientUserAgent.cs
index 4626fceac..ca8551896 100644
--- a/src/SIPSorcery/app/SIPUserAgents/SIPNonInviteClientUserAgent.cs
+++ b/src/SIPSorcery/app/SIPUserAgents/SIPNonInviteClientUserAgent.cs
@@ -159,7 +159,7 @@ private SIPRequest GetRequest(SIPMethodsEnum method)
{
continue;
}
- else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_USERAGENT))
+ else if (customHeader.AsSpan().Trim().StartsWith(SIPHeaders.SIP_HEADER_USERAGENT, StringComparison.Ordinal))
{
request.Header.UserAgent = customHeader.Substring(customHeader.IndexOf(":") + 1).Trim();
}
diff --git a/src/SIPSorcery/app/SIPUserAgents/SIPNotifierClient.cs b/src/SIPSorcery/app/SIPUserAgents/SIPNotifierClient.cs
index fd856d26d..7661689d6 100644
--- a/src/SIPSorcery/app/SIPUserAgents/SIPNotifierClient.cs
+++ b/src/SIPSorcery/app/SIPUserAgents/SIPNotifierClient.cs
@@ -285,7 +285,7 @@ public void Subscribe(SIPURI subscribeURI, long expiry, SIPEventPackagesEnum sip
catch (Exception excp)
{
logger.LogError(excp, "Exception SIPNotifierClient Subscribe. {ErrorMessage}", excp.Message);
- SubscriptionFailed?.Invoke(m_resourceURI, SIPResponseStatusCodesEnum.InternalServerError, "Exception Subscribing. " + excp.Message);
+ SubscriptionFailed?.Invoke(m_resourceURI, SIPResponseStatusCodesEnum.InternalServerError, $"Exception Subscribing. {excp.Message}");
m_waitForSubscribeResponse.Set();
}
}
@@ -311,21 +311,21 @@ private Task SubscribeTransactionFinalResponseReceived(SIPEndPoint
else if (sipResponse.Status == SIPResponseStatusCodesEnum.Forbidden)
{
// The subscription is never going to succeed so cancel it.
- SubscriptionFailed?.Invoke(m_resourceURI, sipResponse.Status, "A Forbidden response was received on a subscribe attempt to " + m_resourceURI.ToString() + " for user " + m_authUsername + ".");
+ SubscriptionFailed?.Invoke(m_resourceURI, sipResponse.Status, $"A Forbidden response was received on a subscribe attempt to {m_resourceURI.ToString()} for user {m_authUsername}.");
m_exit = true;
m_waitForSubscribeResponse.Set();
}
else if (sipResponse.Status == SIPResponseStatusCodesEnum.BadEvent)
{
// The subscription is never going to succeed so cancel it.
- SubscriptionFailed?.Invoke(m_resourceURI, sipResponse.Status, "A BadEvent response was received on a subscribe attempt to " + m_resourceURI.ToString() + " for event package " + m_sipEventPackage.ToString() + ".");
+ SubscriptionFailed?.Invoke(m_resourceURI, sipResponse.Status, $"A BadEvent response was received on a subscribe attempt to {m_resourceURI.ToString()} for event package {m_sipEventPackage.ToString()}.");
m_exit = true;
m_waitForSubscribeResponse.Set();
}
else if (sipResponse.Status == SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist)
{
// The notifier server does not have a record for the existing subscription.
- SubscriptionFailed?.Invoke(m_resourceURI, sipResponse.Status, "Subscribe failed with response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + ".");
+ SubscriptionFailed?.Invoke(m_resourceURI, sipResponse.Status, $"Subscribe failed with response {sipResponse.StatusCode} {sipResponse.ReasonPhrase}.");
m_waitForSubscribeResponse.Set();
}
else if (sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised)
@@ -388,7 +388,7 @@ private Task SubscribeTransactionFinalResponseReceived(SIPEndPoint
}
else
{
- SubscriptionFailed?.Invoke(m_resourceURI, sipResponse.Status, "Subscribe failed with response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + ".");
+ SubscriptionFailed?.Invoke(m_resourceURI, sipResponse.Status, $"Subscribe failed with response {sipResponse.StatusCode} {sipResponse.ReasonPhrase}.");
m_waitForSubscribeResponse.Set();
}
@@ -397,7 +397,7 @@ private Task SubscribeTransactionFinalResponseReceived(SIPEndPoint
catch (Exception excp)
{
logger.LogError(excp, "Exception SubscribeTransactionFinalResponseReceived. {ErrorMessage}", excp.Message);
- SubscriptionFailed?.Invoke(m_resourceURI, SIPResponseStatusCodesEnum.InternalServerError, "Exception processing subscribe response. " + excp.Message);
+ SubscriptionFailed?.Invoke(m_resourceURI, SIPResponseStatusCodesEnum.InternalServerError, $"Exception processing subscribe response. {excp.Message}");
m_waitForSubscribeResponse.Set();
return Task.FromResult(SocketError.Fault);
diff --git a/src/SIPSorcery/app/SIPUserAgents/SIPRegistrationUserAgent.cs b/src/SIPSorcery/app/SIPUserAgents/SIPRegistrationUserAgent.cs
index 1bd89e716..469861dca 100644
--- a/src/SIPSorcery/app/SIPUserAgents/SIPRegistrationUserAgent.cs
+++ b/src/SIPSorcery/app/SIPUserAgents/SIPRegistrationUserAgent.cs
@@ -246,7 +246,7 @@ private void DoRegistration(object state)
if (!m_exit && RegistrationTemporaryFailure != null)
{
- RegistrationTemporaryFailure(m_sipAccountAOR, null, "Registration to " + m_registrarHost + " for " + m_sipAccountAOR.ToString() + " timed out.");
+ RegistrationTemporaryFailure(m_sipAccountAOR, null, $"Registration to {m_registrarHost} for {m_sipAccountAOR.ToString()} timed out.");
}
}
@@ -414,7 +414,7 @@ private void SendInitialRegister()
catch (Exception excp)
{
logger.LogError(excp, "Exception SendInitialRegister to {RegistrarHost}.", m_registrarHost);
- RegistrationFailed?.Invoke(m_sipAccountAOR, null, "Exception SendInitialRegister to " + m_registrarHost + ". " + excp.Message);
+ RegistrationFailed?.Invoke(m_sipAccountAOR, null, $"Exception SendInitialRegister to {m_registrarHost}. {excp.Message}");
}
}
@@ -471,7 +471,7 @@ private void ServerResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint re
{
logger.LogWarning("SIPRegistrationAgent could not resolve {RegistrarHost}.", m_registrarHost);
- RegistrationFailed?.Invoke(m_sipAccountAOR, sipResponse, "Could not resolve " + m_registrarHost + ".");
+ RegistrationFailed?.Invoke(m_sipAccountAOR, sipResponse, $"Could not resolve {m_registrarHost}.");
}
else
{
@@ -522,7 +522,7 @@ private void ServerResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint re
logger.LogWarning("Registration unequivocal failure with {Status} for {SIPAccountAOR}. No further registration attempts will be made: {Exit}.", sipResponse.Status, m_sipAccountAOR, m_exit);
string reasonPhrase = (sipResponse.ReasonPhrase.IsNullOrBlank()) ? sipResponse.Status.ToString() : sipResponse.ReasonPhrase;
- RegistrationFailed?.Invoke(m_sipAccountAOR, sipResponse, "Registration failed with " + (int)sipResponse.Status + " " + reasonPhrase + ".");
+ RegistrationFailed?.Invoke(m_sipAccountAOR, sipResponse, $"Registration failed with {(int)sipResponse.Status} {reasonPhrase}.");
m_waitForRegistrationMRE.Set();
}
@@ -585,7 +585,7 @@ private void AuthResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remo
logger.LogWarning("Registration unequivocal failure with {Status} for {SipAccountAOR}{Action}.", sipResponse.Status, m_sipAccountAOR, (m_exit ? " ,no further registration attempts will be made" : ""));
string reasonPhrase = (sipResponse.ReasonPhrase.IsNullOrBlank()) ? sipResponse.Status.ToString() : sipResponse.ReasonPhrase;
- RegistrationFailed?.Invoke(m_sipAccountAOR, sipResponse, "Registration failed with " + (int)sipResponse.Status + " " + reasonPhrase + ".");
+ RegistrationFailed?.Invoke(m_sipAccountAOR, sipResponse, $"Registration failed with {(int)sipResponse.Status} {reasonPhrase}.");
m_waitForRegistrationMRE.Set();
}
@@ -596,7 +596,7 @@ private void AuthResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remo
logger.LogWarning("Registration unequivocal failure with {Status} for {SipAccountAOR}{Action}.", sipResponse.Status, m_sipAccountAOR, (m_exit ? " ,no further registration attempts will be made" : ""));
string reasonPhrase = (sipResponse.ReasonPhrase.IsNullOrBlank()) ? sipResponse.Status.ToString() : sipResponse.ReasonPhrase;
- RegistrationFailed?.Invoke(m_sipAccountAOR, sipResponse, "Registration failed with " + (int)sipResponse.Status + " " + reasonPhrase + ".");
+ RegistrationFailed?.Invoke(m_sipAccountAOR, sipResponse, $"Registration failed with {(int)sipResponse.Status} {reasonPhrase}.");
m_waitForRegistrationMRE.Set();
}
@@ -604,7 +604,7 @@ private void AuthResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remo
{
logger.LogWarning("Registration failed with {Status} for {SipAccountAOR}.", sipResponse.Status, m_sipAccountAOR);
m_isRegistered = false;
- RegistrationTemporaryFailure?.Invoke(m_sipAccountAOR, sipResponse, "Registration failed with " + sipResponse.Status + ".");
+ RegistrationTemporaryFailure?.Invoke(m_sipAccountAOR, sipResponse, $"Registration failed with {sipResponse.Status}.");
m_waitForRegistrationMRE.Set();
}
}
diff --git a/src/SIPSorcery/app/SIPUserAgents/SIPServerUserAgent.cs b/src/SIPSorcery/app/SIPUserAgents/SIPServerUserAgent.cs
index 4c2715f46..be8b72252 100644
--- a/src/SIPSorcery/app/SIPUserAgents/SIPServerUserAgent.cs
+++ b/src/SIPSorcery/app/SIPUserAgents/SIPServerUserAgent.cs
@@ -357,7 +357,7 @@ public void Reject(SIPResponseStatusCodesEnum failureStatus, string reasonPhrase
{
//UASStateChanged?.Invoke(this, failureStatus, reasonPhrase);
- string failureReason = (!reasonPhrase.IsNullOrBlank()) ? " and " + reasonPhrase : null;
+ string failureReason = (!reasonPhrase.IsNullOrBlank()) ? $" and {reasonPhrase}" : null;
logger.LogWarning("UAS call failed with a response status of {FailureStatus}{FailureReason}.", (int)failureStatus, failureReason);
SIPResponse failureResponse = SIPResponse.GetResponse(m_uasTransaction.TransactionRequest, failureStatus, reasonPhrase);
diff --git a/src/SIPSorcery/app/SIPUserAgents/SIPUserAgent.cs b/src/SIPSorcery/app/SIPUserAgents/SIPUserAgent.cs
index 71d640398..22c9aa8b2 100644
--- a/src/SIPSorcery/app/SIPUserAgents/SIPUserAgent.cs
+++ b/src/SIPSorcery/app/SIPUserAgents/SIPUserAgent.cs
@@ -1400,7 +1400,7 @@ private void SendReInviteRequest(SDP sdp)
reinviteRequest.Header.UserAgent = SIPConstants.SipUserAgentVersionString;
reinviteRequest.Header.ContentType = m_sdpContentType;
reinviteRequest.Body = sdp.ToString();
- reinviteRequest.Header.Supported = SIPExtensionHeaders.REPLACES + ", " + SIPExtensionHeaders.NO_REFER_SUB + ", " + SIPExtensionHeaders.PRACK;
+ reinviteRequest.Header.Supported = $"{SIPExtensionHeaders.REPLACES}, {SIPExtensionHeaders.NO_REFER_SUB}, {SIPExtensionHeaders.PRACK}";
if (m_uac != null)
{
diff --git a/src/SIPSorcery/core/SIP/SIPAuthorisationDigest.cs b/src/SIPSorcery/core/SIP/SIPAuthorisationDigest.cs
index d16022b27..5b7a3fb05 100644
--- a/src/SIPSorcery/core/SIP/SIPAuthorisationDigest.cs
+++ b/src/SIPSorcery/core/SIP/SIPAuthorisationDigest.cs
@@ -16,8 +16,8 @@
using System;
using System.Security.Cryptography;
using System.Text;
-using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
+using Polyfills;
using SIPSorcery.Sys;
namespace SIPSorcery.SIP
@@ -85,69 +85,72 @@ public static SIPAuthorisationDigest ParseAuthorisationDigest(SIPAuthorisationHe
{
SIPAuthorisationDigest authRequest = new SIPAuthorisationDigest(authorisationType);
- string noDigestHeader = Regex.Replace(authorisationRequest, $@"^\s*{METHOD}\s*", "", RegexOptions.IgnoreCase);
- string[] headerFields = noDigestHeader.Split(',');
+ ArgumentNullException.ThrowIfNull(authorisationRequest);
- if (headerFields != null && headerFields.Length > 0)
+ var headerFields = authorisationRequest.AsSpan().TrimStart();
+ if (headerFields.StartsWith(METHOD, StringComparison.OrdinalIgnoreCase))
{
- foreach (string headerField in headerFields)
+ headerFields = headerFields.Slice(METHOD.Length).TrimStart();
+ }
+
+ Span headerKeyValueRange = stackalloc Range[2];
+ foreach (var headerFieldRange in headerFields.Split(','))
+ {
+ var headerField = headerFields[headerFieldRange];
+
+ if (headerField.Split(headerKeyValueRange, '=') == 2)
{
- int equalsIndex = headerField.IndexOf('=');
+ var headerName = headerField[headerKeyValueRange[0]].Trim().ToString();
+ var headerValue = headerField[headerKeyValueRange[1]].ToString().Trim(m_headerFieldRemoveChars);
- if (equalsIndex != -1 && equalsIndex < headerField.Length)
+ if (string.Equals(headerName, AuthHeaders.AUTH_REALM_KEY, StringComparison.OrdinalIgnoreCase))
+ {
+ authRequest.Realm = headerValue;
+ }
+ else if (string.Equals(headerName, AuthHeaders.AUTH_NONCE_KEY, StringComparison.OrdinalIgnoreCase))
+ {
+ authRequest.Nonce = headerValue;
+ }
+ else if (string.Equals(headerName, AuthHeaders.AUTH_USERNAME_KEY, StringComparison.OrdinalIgnoreCase))
+ {
+ authRequest.Username = headerValue;
+ }
+ else if (string.Equals(headerName, AuthHeaders.AUTH_RESPONSE_KEY, StringComparison.OrdinalIgnoreCase))
+ {
+ authRequest.Response = headerValue;
+ }
+ else if (string.Equals(headerName, AuthHeaders.AUTH_URI_KEY, StringComparison.OrdinalIgnoreCase))
+ {
+ authRequest.URI = headerValue;
+ }
+ else if (string.Equals(headerName, AuthHeaders.AUTH_CNONCE_KEY, StringComparison.OrdinalIgnoreCase))
+ {
+ authRequest.Cnonce = headerValue;
+ }
+ else if (string.Equals(headerName, AuthHeaders.AUTH_NONCECOUNT_KEY, StringComparison.OrdinalIgnoreCase))
+ {
+ Int32.TryParse(headerValue, out authRequest.NonceCount);
+ }
+ else if (string.Equals(headerName, AuthHeaders.AUTH_QOP_KEY, StringComparison.OrdinalIgnoreCase))
+ {
+ authRequest.Qop = headerValue.ToLower();
+ }
+ else if (string.Equals(headerName, AuthHeaders.AUTH_OPAQUE_KEY, StringComparison.OrdinalIgnoreCase))
+ {
+ authRequest.Opaque = headerValue;
+ }
+ else if (string.Equals(headerName, AuthHeaders.AUTH_ALGORITHM_KEY, StringComparison.OrdinalIgnoreCase))
{
- string headerName = headerField.Substring(0, equalsIndex).Trim();
- string headerValue = headerField.Substring(equalsIndex + 1).Trim(m_headerFieldRemoveChars);
+ //authRequest.Algorithhm = headerValue;
- if (Regex.Match(headerName, "^" + AuthHeaders.AUTH_REALM_KEY + "$", RegexOptions.IgnoreCase).Success)
- {
- authRequest.Realm = headerValue;
- }
- else if (Regex.Match(headerName, "^" + AuthHeaders.AUTH_NONCE_KEY + "$", RegexOptions.IgnoreCase).Success)
- {
- authRequest.Nonce = headerValue;
- }
- else if (Regex.Match(headerName, "^" + AuthHeaders.AUTH_USERNAME_KEY + "$", RegexOptions.IgnoreCase).Success)
- {
- authRequest.Username = headerValue;
- }
- else if (Regex.Match(headerName, "^" + AuthHeaders.AUTH_RESPONSE_KEY + "$", RegexOptions.IgnoreCase).Success)
- {
- authRequest.Response = headerValue;
- }
- else if (Regex.Match(headerName, "^" + AuthHeaders.AUTH_URI_KEY + "$", RegexOptions.IgnoreCase).Success)
- {
- authRequest.URI = headerValue;
- }
- else if (Regex.Match(headerName, "^" + AuthHeaders.AUTH_CNONCE_KEY + "$", RegexOptions.IgnoreCase).Success)
+ if (Enum.TryParse(headerValue.Replace("-", ""), true, out var alg))
{
- authRequest.Cnonce = headerValue;
+ authRequest.DigestAlgorithm = alg;
}
- else if (Regex.Match(headerName, "^" + AuthHeaders.AUTH_NONCECOUNT_KEY + "$", RegexOptions.IgnoreCase).Success)
+ else
{
- Int32.TryParse(headerValue, out authRequest.NonceCount);
- }
- else if (Regex.Match(headerName, "^" + AuthHeaders.AUTH_QOP_KEY + "$", RegexOptions.IgnoreCase).Success)
- {
- authRequest.Qop = headerValue.ToLower();
- }
- else if (Regex.Match(headerName, "^" + AuthHeaders.AUTH_OPAQUE_KEY + "$", RegexOptions.IgnoreCase).Success)
- {
- authRequest.Opaque = headerValue;
- }
- else if (Regex.Match(headerName, "^" + AuthHeaders.AUTH_ALGORITHM_KEY + "$", RegexOptions.IgnoreCase).Success)
- {
- //authRequest.Algorithhm = headerValue;
-
- if (Enum.TryParse(headerValue.Replace("-",""), true, out var alg))
- {
- authRequest.DigestAlgorithm = alg;
- }
- else
- {
- logger.LogWarning("SIPAuthorisationDigest did not recognised digest algorithm value of {DigestAlgorithms}, defaulting to {DigestAlgorithmsEnumMD5}.", headerValue, DigestAlgorithmsEnum.MD5);
- authRequest.DigestAlgorithm = DigestAlgorithmsEnum.MD5;
- }
+ logger.LogWarning("SIPAuthorisationDigest did not recognised digest algorithm value of {DigestAlgorithms}, defaulting to {DigestAlgorithmsEnumMD5}.", headerValue, DigestAlgorithmsEnum.MD5);
+ authRequest.DigestAlgorithm = DigestAlgorithmsEnum.MD5;
}
}
}
@@ -211,7 +214,7 @@ public string GetDigest()
NonceCount = (NonceCount != 0) ? NonceCount : NONCE_DEFAULT_COUNT;
nonceCountStr = GetPaddedNonceCount(NonceCount);
- if (Cnonce == null || Cnonce.Trim().Length == 0)
+ if (string.IsNullOrWhiteSpace(Cnonce))
{
Cnonce = Crypto.GetRandomInt().ToString();
}
@@ -256,22 +259,84 @@ public string GetDigest()
public override string ToString()
{
- string authHeader = AuthHeaders.AUTH_DIGEST_KEY + " ";
-
- authHeader += (Username != null && Username.Trim().Length != 0) ? AuthHeaders.AUTH_USERNAME_KEY + "=\"" + Username + "\"" : null;
- authHeader += (authHeader.IndexOf('=') != -1) ? "," + AuthHeaders.AUTH_REALM_KEY + "=\"" + Realm + "\"" : AuthHeaders.AUTH_REALM_KEY + "=\"" + Realm + "\"";
- authHeader += (Nonce != null) ? "," + AuthHeaders.AUTH_NONCE_KEY + "=\"" + Nonce + "\"" : null;
- authHeader += (URI != null && URI.Trim().Length != 0) ? "," + AuthHeaders.AUTH_URI_KEY + "=\"" + URI + "\"" : null;
- authHeader += (Response != null && Response.Length != 0) ? "," + AuthHeaders.AUTH_RESPONSE_KEY + "=\"" + Response + "\"" : null;
- authHeader += (Cnonce != null) ? "," + AuthHeaders.AUTH_CNONCE_KEY + "=\"" + Cnonce + "\"" : null;
- authHeader += (NonceCount != 0) ? "," + AuthHeaders.AUTH_NONCECOUNT_KEY + "=" + GetPaddedNonceCount(NonceCount) : null;
- authHeader += (Qop != null) ? "," + AuthHeaders.AUTH_QOP_KEY + "=" + Qop : null;
- authHeader += (Opaque != null) ? "," + AuthHeaders.AUTH_OPAQUE_KEY + "=\"" + Opaque + "\"" : null;
+ var authHeader = new StringBuilder();
+ var hasParameter = false;
+
+ void AppendSeparator()
+ {
+ if (hasParameter)
+ {
+ authHeader.Append(',');
+ }
+ else
+ {
+ hasParameter = true;
+ }
+ }
+
+ void AppendQuotedParameter(string key, string value)
+ {
+ AppendSeparator();
+ authHeader.Append(key).Append("=\"").Append(value).Append('"');
+ }
+
+ void AppendParameter(string key, string value)
+ {
+ AppendSeparator();
+ authHeader.Append(key).Append('=').Append(value);
+ }
+
+ authHeader.Append(AuthHeaders.AUTH_DIGEST_KEY).Append(' ');
+
+ if (!string.IsNullOrWhiteSpace(Username))
+ {
+ AppendQuotedParameter(AuthHeaders.AUTH_USERNAME_KEY, Username);
+ }
+
+ AppendQuotedParameter(AuthHeaders.AUTH_REALM_KEY, Realm);
+
+ if (Nonce != null)
+ {
+ AppendQuotedParameter(AuthHeaders.AUTH_NONCE_KEY, Nonce);
+ }
+
+ if (!string.IsNullOrWhiteSpace(URI))
+ {
+ AppendQuotedParameter(AuthHeaders.AUTH_URI_KEY, URI);
+ }
+
+ if (Response != null && Response.Length != 0)
+ {
+ AppendQuotedParameter(AuthHeaders.AUTH_RESPONSE_KEY, Response);
+ }
+
+ if (Cnonce != null)
+ {
+ AppendQuotedParameter(AuthHeaders.AUTH_CNONCE_KEY, Cnonce);
+ }
+
+ if (NonceCount != 0)
+ {
+ AppendParameter(AuthHeaders.AUTH_NONCECOUNT_KEY, GetPaddedNonceCount(NonceCount));
+ }
+
+ if (Qop != null)
+ {
+ AppendParameter(AuthHeaders.AUTH_QOP_KEY, Qop);
+ }
+
+ if (Opaque != null)
+ {
+ AppendQuotedParameter(AuthHeaders.AUTH_OPAQUE_KEY, Opaque);
+ }
string algorithmID = (DigestAlgorithm == DigestAlgorithmsEnum.SHA256) ? SHA256_ALGORITHM_ID : DigestAlgorithm.ToString();
- authHeader += (Response != null) ? "," + AuthHeaders.AUTH_ALGORITHM_KEY + "=" + algorithmID : null;
+ if (Response != null)
+ {
+ AppendParameter(AuthHeaders.AUTH_ALGORITHM_KEY, algorithmID);
+ }
- return authHeader;
+ return authHeader.ToString();
}
public SIPAuthorisationDigest CopyOf()
@@ -294,7 +359,7 @@ public void IncrementNonceCount()
private string GetPaddedNonceCount(int count)
{
- return "00000000".Substring(0, 8 - NonceCount.ToString().Length) + count;
+ return $"{"00000000".Substring(0, 8 - NonceCount.ToString().Length)}{count}";
}
}
@@ -309,8 +374,7 @@ public static string DigestCalcHA1(
string password,
DigestAlgorithmsEnum hashAlg = DigestAlgorithmsEnum.MD5)
{
- string a1 = String.Format("{0}:{1}:{2}", username, realm, password);
- return GetHashHex(hashAlg, a1);
+ return GetHashHex(hashAlg, $"{username}:{realm}:{password}");
}
///
@@ -321,9 +385,7 @@ public static string DigestCalcHA2(
string uri,
DigestAlgorithmsEnum hashAlg = DigestAlgorithmsEnum.MD5)
{
- string A2 = String.Format("{0}:{1}", method, uri);
-
- return GetHashHex(hashAlg, A2);
+ return GetHashHex(hashAlg, $"{method}:{uri}");
}
public static string DigestCalcResponse(
@@ -352,28 +414,13 @@ public static string DigestCalcResponse(
string method,
DigestAlgorithmsEnum hashAlg = DigestAlgorithmsEnum.MD5)
{
- string HA2 = DigestCalcHA2(method, uri, hashAlg);
-
- string unhashedDigest = null;
+ var HA2 = DigestCalcHA2(method, uri, hashAlg);
if (nonceCount != null && cnonce != null && qop != null)
{
- unhashedDigest = String.Format("{0}:{1}:{2}:{3}:{4}:{5}",
- ha1,
- nonce,
- nonceCount,
- cnonce,
- qop,
- HA2);
- }
- else
- {
- unhashedDigest = String.Format("{0}:{1}:{2}",
- ha1,
- nonce,
- HA2);
+ return GetHashHex(hashAlg, $"{ha1}:{nonce}:{nonceCount}:{cnonce}:{qop}:{HA2}");
}
- return GetHashHex(hashAlg, unhashedDigest);
+ return GetHashHex(hashAlg, $"{ha1}:{nonce}:{HA2}");
}
public static string GetHashHex(DigestAlgorithmsEnum hashAlg, string val)
diff --git a/src/SIPSorcery/core/SIP/SIPConstants.cs b/src/SIPSorcery/core/SIP/SIPConstants.cs
index 0258b5151..79c3bb696 100644
--- a/src/SIPSorcery/core/SIP/SIPConstants.cs
+++ b/src/SIPSorcery/core/SIP/SIPConstants.cs
@@ -17,6 +17,7 @@
using System.Collections.Generic;
using System.Reflection;
using System.Text;
+using Polyfills;
using SIPSorcery.Sys;
// ReSharper disable InconsistentNaming
@@ -37,10 +38,9 @@ public static class SIPConstants
/// The maximum size supported for an incoming SIP message.
///
///
- /// From https://tools.ietf.org/html/rfc3261#section-18.1.1:
- /// However, implementations MUST be able to handle messages up to the maximum
- /// datagram packet size.For UDP, this size is 65,535 bytes, including
- /// IP and UDP headers.
+ /// From https://tools.ietf.org/html/rfc3261#section-18.1.1: However, implementations MUST be able to handle
+ /// messages up to the maximum datagram packet size.For UDP, this size is 65,535 bytes, including IP and UDP
+ /// headers.
///
public const int SIP_MAXIMUM_RECEIVE_LENGTH = 65535;
@@ -84,7 +84,7 @@ public static string SipUserAgentVersionString
public static Encoding DEFAULT_ENCODING = Encoding.UTF8;
///
- /// Gets the default SIP port for the protocol.
+ /// Gets the default SIP port for the protocol.
///
/// The transport layer protocol to get the port for.
/// The default port to use.
@@ -118,26 +118,26 @@ public enum SIPMessageTypesEnum
public static class SIPTimings
{
///
- /// Value of the SIP defined timer T1 in milliseconds and is the time for the first retransmit.
- /// Should not need to be adjusted in normal circumstances.
+ /// Value of the SIP defined timer T1 in milliseconds and is the time for the first retransmit. Should not need
+ /// to be adjusted in normal circumstances.
///
public static int T1 = 500;
///
- /// Value of the SIP defined timer T2 in milliseconds and is the maximum time between retransmits.
- /// Should not need to be adjusted in normal circumstances.
+ /// Value of the SIP defined timer T2 in milliseconds and is the maximum time between retransmits. Should not
+ /// need to be adjusted in normal circumstances.
///
public static int T2 = 4000;
///
- /// Value of the SIP defined timer T6 in milliseconds and is the period after which a transaction
- /// has timed out. Should not need to be adjusted in normal circumstances.
+ /// Value of the SIP defined timer T6 in milliseconds and is the period after which a transaction has timed out.
+ /// Should not need to be adjusted in normal circumstances.
///
public static int T6 = 64 * T1;
///
- /// The number of milliseconds a transaction can stay in the proceeding state
- /// (i.e. an INVITE will ring for) before the call is given up and timed out.
+ /// The number of milliseconds a transaction can stay in the proceeding state (i.e. an INVITE will ring for)
+ /// before the call is given up and timed out.
///
public static int MAX_RING_TIME = 180000;
}
@@ -160,12 +160,11 @@ public static SIPSchemesEnum GetSchemeType(string schemeType)
public static bool IsAllowedScheme(string schemeType)
{
return Enum.TryParse(schemeType, true, out _);
- }
- }
+ }
+ }
///
- /// A list of the transport layer protocols that are supported (the network layers
- /// supported are IPv4 and IPv6).
+ /// A list of the transport layer protocols that are supported (the network layers supported are IPv4 and IPv6).
///
public enum SIPProtocolsEnum
{
@@ -173,8 +172,8 @@ public enum SIPProtocolsEnum
/// User Datagram Protocol.
///
udp = 1,
- /// .
- /// Transmission Control Protocol
+ ///
+ /// . Transmission Control Protocol
///
tcp = 2,
///
@@ -206,11 +205,11 @@ public static SIPProtocolsEnum GetProtocolTypeFromId(int protocolTypeId)
public static bool IsAllowedProtocol(string protocol)
{
return Enum.TryParse(protocol, true, out _);
- }
+ }
///
- /// Returns true for connectionless transport protocols, such as UDP, and false for
- /// connection oriented protocols.
+ /// Returns true for connectionless transport protocols, such as UDP, and false for connection oriented
+ /// protocols.
///
/// The protocol to check.
/// True if the protocol is connectionless.
@@ -495,22 +494,11 @@ public static class SIPMIMETypes
///
/// For SIP URI user portion the reserved characters below need to be escaped.
- ///
///
- ///
+ ///
///
- ///
- /// For SIP URI parameters different characters are unreserved (just to make life difficult).
- ///
- ///
+ /// For SIP URI parameters different characters are unreserved (just to make life difficult).
+ ///
///
///
public static class SIPEscape
@@ -582,9 +570,9 @@ public static string SIPURIParameterUnescape(string escapedString)
}
}
- ///
+ ///
/// List of SIP extensions to RFC3262.
- ///
+ ///
public enum SIPExtensions
{
None = 0,
@@ -596,8 +584,8 @@ public enum SIPExtensions
}
///
- /// Constants that can be placed in the SIP Supported or Required headers to indicate support or mandate for
- /// a particular SIP extension.
+ /// Constants that can be placed in the SIP Supported or Required headers to indicate support or mandate for a
+ /// particular SIP extension.
///
public static class SIPExtensionHeaders
{
@@ -608,49 +596,77 @@ public static class SIPExtensionHeaders
public const string MULTIPLE_REFER = "multiple-refer";
///
- /// Parses a string containing a list of SIP extensions into a list of extensions that this library
- /// understands.
+ /// Parses a string containing a list of SIP extensions into a list of extensions that this library understands.
///
/// The string containing the list of extensions to parse.
/// A comma separated list of the unsupported extensions.
- /// A list of extensions that were understood and a boolean indicating whether any unknown extensions were present.
+ ///
+ /// 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;
- if (String.IsNullOrEmpty(extensionList) == false)
+ if (!string.IsNullOrEmpty(extensionList))
{
- string[] extensions = extensionList.Trim().Split(',');
+ var firstUnknown = ReadOnlySpan.Empty;
+ var unknownSb = default(StringBuilder);
+ var extensions = extensionList.AsSpan().Trim();
- foreach (string extension in extensions)
+ foreach (var extensionRange in extensions.Split(','))
{
- if (String.IsNullOrEmpty(extension) == false)
+ var extension = extensions[extensionRange];
+
+ var trimmedExtension = extension.Trim();
+ switch (trimmedExtension)
{
- string trimmedExtension = extension.Trim().ToLower();
- switch (trimmedExtension)
- {
- 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);
+ case var x when PRACK.Equals(x, StringComparison.OrdinalIgnoreCase):
+ knownExtensions.Add(SIPExtensions.Prack);
+ break;
+ case var x when NO_REFER_SUB.Equals(x, StringComparison.OrdinalIgnoreCase):
+ knownExtensions.Add(SIPExtensions.NoReferSub);
+ break;
+ case var x when REPLACES.Equals(x, StringComparison.OrdinalIgnoreCase):
+ knownExtensions.Add(SIPExtensions.Replaces);
+ break;
+ case var x when SIPREC.Equals(x, StringComparison.OrdinalIgnoreCase):
+ knownExtensions.Add(SIPExtensions.SipRec);
+ break;
+ case var x when MULTIPLE_REFER.Equals(x, StringComparison.OrdinalIgnoreCase):
+ knownExtensions.Add(SIPExtensions.MultipleRefer);
+ break;
+ default:
+ if (trimmedExtension.IsEmpty)
+ {
break;
- default:
- unknownExtensions += (unknownExtensions != null) ? $",{extension.Trim()}" : extension.Trim();
- break;
- }
+ }
+
+ if (unknownSb is not null)
+ {
+ unknownSb.Append(',').Append(trimmedExtension);
+ }
+ else if (firstUnknown.IsEmpty)
+ {
+ firstUnknown = trimmedExtension;
+ }
+ else
+ {
+ unknownSb = new StringBuilder().Append(firstUnknown).Append(',').Append(trimmedExtension);
+ }
+ break;
}
}
+
+ if (unknownSb is not null)
+ {
+ unknownExtensions = unknownSb.ToString();
+ }
+ else if (!firstUnknown.IsEmpty)
+ {
+ unknownExtensions = firstUnknown.ToString();
+ }
}
return knownExtensions;
diff --git a/src/SIPSorcery/core/SIP/SIPDialogue.cs b/src/SIPSorcery/core/SIP/SIPDialogue.cs
index 5b2c2c768..03fe079d1 100644
--- a/src/SIPSorcery/core/SIP/SIPDialogue.cs
+++ b/src/SIPSorcery/core/SIP/SIPDialogue.cs
@@ -86,14 +86,14 @@ public string DialogueName
string dialogueName = "L(??)";
if (LocalUserField != null && !LocalUserField.URI.User.IsNullOrBlank())
{
- dialogueName = "L(" + LocalUserField.URI.ToString() + ")";
+ dialogueName = $"L({LocalUserField.URI.ToString()})";
}
dialogueName += "-";
if (RemoteUserField != null && !RemoteUserField.URI.User.IsNullOrBlank())
{
- dialogueName += "R(" + RemoteUserField.URI.ToString() + ")";
+ dialogueName += $"R({RemoteUserField.URI.ToString()})";
}
else
{
diff --git a/src/SIPSorcery/core/SIP/SIPEndPoint.cs b/src/SIPSorcery/core/SIP/SIPEndPoint.cs
index 6460d26aa..efd9ae5af 100644
--- a/src/SIPSorcery/core/SIP/SIPEndPoint.cs
+++ b/src/SIPSorcery/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);
}
@@ -219,7 +219,7 @@ public override string ToString()
{
if (Address == null)
{
- return Protocol + ":empty";
+ return $"{Protocol}:empty";
}
else
{
diff --git a/src/SIPSorcery/core/SIP/SIPHeader.cs b/src/SIPSorcery/core/SIP/SIPHeader.cs
index f1b976356..52aaa924a 100644
--- a/src/SIPSorcery/core/SIP/SIPHeader.cs
+++ b/src/SIPSorcery/core/SIP/SIPHeader.cs
@@ -19,8 +19,8 @@
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Text;
-using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
+using Polyfills;
using SIPSorcery.Sys;
namespace SIPSorcery.SIP
@@ -128,7 +128,7 @@ public string ContactAddress // This the address placed into the Via
{
if (ipEndPoint.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
{
- return "[" + ipEndPoint.Address.ToString() + "]";
+ return $"[{ipEndPoint.Address}]";
}
else
{
@@ -143,7 +143,7 @@ public string ContactAddress // This the address placed into the Via
}
else if (Port != 0)
{
- return Host + ":" + Port;
+ return $"{Host}:{Port}";
}
else
{
@@ -179,7 +179,7 @@ public string ReceivedFromAddress // This is the socket the request was re
}
else
{
- return Host + ":" + ReceivedFromPort;
+ return $"{Host}:{ReceivedFromPort}";
}
}
else if (Port != 0)
@@ -191,7 +191,7 @@ public string ReceivedFromAddress // This is the socket the request was re
}
else
{
- return Host + ":" + Port;
+ return $"{Host}:{Port}";
}
}
else
@@ -247,7 +247,7 @@ public static SIPViaHeader[] ParseSIPViaHeader(string viaHeaderStr)
foreach (string viaHeaderStrItem in viaHeaders)
{
- if (viaHeaderStrItem == null || viaHeaderStrItem.Trim().Length == 0)
+ if (string.IsNullOrWhiteSpace(viaHeaderStrItem))
{
throw new SIPValidationException(SIPValidationFieldsEnum.ViaHeader, "No Contact address.");
}
@@ -263,11 +263,13 @@ public static SIPViaHeader[] ParseSIPViaHeader(string viaHeaderStr)
}
else
{
- string versionAndTransport = header.Substring(0, firstSpacePosn);
- viaHeader.Version = versionAndTransport.Substring(0, versionAndTransport.LastIndexOf('/'));
- viaHeader.Transport = SIPProtocolsType.GetProtocolType(versionAndTransport.Substring(versionAndTransport.LastIndexOf('/') + 1));
+ var headerSpan = header.AsSpan();
+ var versionAndTransport = headerSpan.Slice(0, firstSpacePosn);
+ var transportDelimiterIndex = versionAndTransport.LastIndexOf('/');
+ viaHeader.Version = versionAndTransport.Slice(0, transportDelimiterIndex).ToString();
+ viaHeader.Transport = SIPProtocolsType.GetProtocolType(versionAndTransport.Slice(transportDelimiterIndex + 1).ToString());
- string nextField = header.Substring(firstSpacePosn, header.Length - firstSpacePosn).Trim();
+ var nextField = headerSpan.Slice(firstSpacePosn).Trim().ToString();
int delimIndex = nextField.IndexOf(';');
string contactAddress = null;
@@ -275,7 +277,7 @@ public static SIPViaHeader[] ParseSIPViaHeader(string viaHeaderStr)
// Some user agents include branch but have the semi-colon missing, that's easy to cope with by replacing "branch" with ";branch".
if (delimIndex == -1 && nextField.Contains(m_branchKey))
{
- nextField = nextField.Replace(m_branchKey, ";" + m_branchKey);
+ nextField = nextField.Replace(m_branchKey, $";{m_branchKey}");
delimIndex = nextField.IndexOf(';');
}
@@ -288,11 +290,11 @@ public static SIPViaHeader[] ParseSIPViaHeader(string viaHeaderStr)
}
else
{
- contactAddress = nextField.Substring(0, delimIndex).Trim();
+ contactAddress = nextField.AsSpan(0, delimIndex).Trim().ToString();
viaHeader.ViaParameters = new SIPParameters(nextField.Substring(delimIndex, nextField.Length - delimIndex), m_paramDelimChar);
}
- if (contactAddress == null || contactAddress.Trim().Length == 0)
+ if (string.IsNullOrWhiteSpace(contactAddress))
{
// Check that the branch parameter is present, without it the Via header is illegal.
//if (!viaHeader.ViaParameters.Has(m_branchKey))
@@ -353,12 +355,9 @@ public static SIPViaHeader[] ParseSIPViaHeader(string viaHeaderStr)
}
}
- public new string ToString()
+ public override string ToString()
{
- string sipViaHeader = SIPHeaders.SIP_HEADER_VIA + ": " + this.Version + "/" + this.Transport.ToString().ToUpper() + " " + ContactAddress;
- sipViaHeader += (ViaParameters != null && ViaParameters.Count > 0) ? ViaParameters.ToString() : null;
-
- return sipViaHeader;
+ return $"{SIPHeaders.SIP_HEADER_VIA}: {this.Version}/{this.Transport.ToString().ToUpper()} {ContactAddress}{((ViaParameters != null && ViaParameters.Count > 0) ? ViaParameters.ToString() : null)}";
}
}
@@ -408,7 +407,7 @@ public string FromTag
get { return FromParameters.Get(PARAMETER_TAG); }
set
{
- if (value != null && value.Trim().Length > 0)
+ if (!string.IsNullOrWhiteSpace(value))
{
FromParameters.Set(PARAMETER_TAG, value);
}
@@ -477,7 +476,7 @@ public override string ToString()
public string FriendlyDescription()
{
string caller = FromURI.ToAOR();
- caller = (!string.IsNullOrEmpty(FromName)) ? FromName + " " + caller : caller;
+ caller = (!string.IsNullOrEmpty(FromName)) ? $"{FromName} {caller}" : caller;
return caller;
}
}
@@ -516,7 +515,7 @@ public string ToTag
get { return ToParameters.Get(PARAMETER_TAG); }
set
{
- if (value != null && value.Trim().Length > 0)
+ if (!string.IsNullOrWhiteSpace(value))
{
ToParameters.Set(PARAMETER_TAG, value);
}
@@ -680,7 +679,7 @@ public static List ParseContactHeader(string contactHeaderStr)
{
try
{
- if (contactHeaderStr == null || contactHeaderStr.Trim().Length == 0)
+ if (string.IsNullOrWhiteSpace(contactHeaderStr))
{
return null;
}
@@ -728,7 +727,7 @@ public static List ParseContactHeader(string contactHeaderStr)
}
catch (Exception excp)
{
- throw new SIPValidationException(SIPValidationFieldsEnum.ContactHeader, "Contact header invalid, parse failed. " + excp.Message);
+ throw new SIPValidationException(SIPValidationFieldsEnum.ContactHeader, $"Contact header invalid, parse failed. {excp.Message}");
}
}
@@ -869,7 +868,7 @@ public static SIPAuthenticationHeader ParseSIPAuthenticationHeader(SIPAuthorisat
}
catch
{
- throw new ApplicationException("Error parsing SIP authentication header request, " + headerValue);
+ throw new ApplicationException($"Error parsing SIP authentication header request, {headerValue}");
}
}
@@ -879,23 +878,23 @@ private static string BuildAuthorisationHeaderName(SIPAuthorisationHeadersEnum a
string authHeader = null;
if (authorisationHeaderType == SIPAuthorisationHeadersEnum.Authorize)
{
- authHeader = SIPHeaders.SIP_HEADER_AUTHORIZATION + ": ";
+ authHeader = $"{SIPHeaders.SIP_HEADER_AUTHORIZATION}: ";
}
else if (authorisationHeaderType == SIPAuthorisationHeadersEnum.ProxyAuthenticate)
{
- authHeader = SIPHeaders.SIP_HEADER_PROXYAUTHENTICATION + ": ";
+ authHeader = $"{SIPHeaders.SIP_HEADER_PROXYAUTHENTICATION}: ";
}
else if (authorisationHeaderType == SIPAuthorisationHeadersEnum.ProxyAuthorization)
{
- authHeader = SIPHeaders.SIP_HEADER_PROXYAUTHORIZATION + ": ";
+ authHeader = $"{SIPHeaders.SIP_HEADER_PROXYAUTHORIZATION}: ";
}
else if (authorisationHeaderType == SIPAuthorisationHeadersEnum.WWWAuthenticate)
{
- authHeader = SIPHeaders.SIP_HEADER_WWWAUTHENTICATE + ": ";
+ authHeader = $"{SIPHeaders.SIP_HEADER_WWWAUTHENTICATE}: ";
}
else
{
- authHeader = SIPHeaders.SIP_HEADER_AUTHORIZATION + ": ";
+ authHeader = $"{SIPHeaders.SIP_HEADER_AUTHORIZATION}: ";
}
return authHeader;
@@ -1127,7 +1126,7 @@ public void PushRoute(string host)
public void PushRoute(IPEndPoint socket, SIPSchemesEnum scheme, SIPProtocolsEnum protcol)
{
- m_sipRoutes.Insert(0, new SIPRoute(scheme + ":" + socket.ToString(), true));
+ m_sipRoutes.Insert(0, new SIPRoute($"{scheme}:{socket.ToString()}", true));
}
public void AddBottomRoute(SIPRoute route)
@@ -1153,7 +1152,8 @@ public void RemoveBottomRoute()
if (m_sipRoutes.Count > 0)
{
m_sipRoutes.RemoveAt(m_sipRoutes.Count - 1);
- };
+ }
+ ;
}
public SIPRouteSet Reversed()
@@ -1191,19 +1191,25 @@ public void ReplaceRoute(string origSocket, string replacementSocket)
}
}
- public new string ToString()
+ public override string ToString()
{
- string routeStr = null;
-
if (m_sipRoutes != null && m_sipRoutes.Count > 0)
{
+ var routeStr = new StringBuilder();
for (int routeIndex = 0; routeIndex < m_sipRoutes.Count; routeIndex++)
{
- routeStr += (routeStr != null) ? "," + m_sipRoutes[routeIndex].ToString() : m_sipRoutes[routeIndex].ToString();
+ if (routeIndex > 0)
+ {
+ routeStr.Append(',');
+ }
+
+ routeStr.Append(m_sipRoutes[routeIndex].ToString());
}
+
+ return routeStr.ToString();
}
- return routeStr;
+ return null;
}
}
@@ -1305,19 +1311,20 @@ public void PushViaHeader(SIPViaHeader viaHeader)
m_viaHeaders.Insert(0, viaHeader);
}
- public new string ToString()
+ public override string ToString()
{
- string viaStr = null;
-
if (m_viaHeaders != null && m_viaHeaders.Count > 0)
{
+ var viaStr = new StringBuilder();
for (int viaIndex = 0; viaIndex < m_viaHeaders.Count; viaIndex++)
{
- viaStr += (m_viaHeaders[viaIndex]).ToString() + m_CRLF;
+ viaStr.Append(m_viaHeaders[viaIndex].ToString()).Append(m_CRLF);
}
+
+ return viaStr.ToString();
}
- return viaStr;
+ return null;
}
}
@@ -1411,7 +1418,7 @@ public static List ParseHeader(string headerStr)
}
catch
{
- throw new SIPValidationException(SIPValidationFieldsEnum.Unknown, "One of the SIP SIPMultiUriHeaders was invalid, header: " + headerStr);
+ throw new SIPValidationException(SIPValidationFieldsEnum.Unknown, $"One of the SIP SIPMultiUriHeaders was invalid, header: {headerStr}");
}
}
@@ -1428,7 +1435,7 @@ public override string ToString()
public string FriendlyDescription()
{
string caller = URI.ToAOR();
- caller = (!string.IsNullOrEmpty(Name)) ? Name + " " + caller : caller;
+ caller = (!string.IsNullOrEmpty(Name)) ? $"{Name} {caller}" : caller;
return caller;
}
}
@@ -1573,7 +1580,7 @@ private void Initialise(List contact, SIPFromHeader from, SIPT
throw new ApplicationException("The To header cannot be empty when creating a new SIP header.");
}
- if (callId == null || callId.Trim().Length == 0)
+ if (string.IsNullOrWhiteSpace(callId))
{
throw new ApplicationException("The CallId header cannot be empty when creating a new SIP header.");
}
@@ -1595,13 +1602,71 @@ private void Initialise(List contact, SIPFromHeader from, SIPT
public static string[] SplitHeaders(string message)
{
+ static string NormalizeFoldedHeaderLines(string headerBlock)
+ {
+ var normalised = default(StringBuilder);
+ var segmentStart = 0;
+ var position = 0;
+
+ while (position < headerBlock.Length)
+ {
+ if (position + 2 < headerBlock.Length &&
+ headerBlock[position] == '\r' &&
+ headerBlock[position + 1] == '\n' &&
+ char.IsWhiteSpace(headerBlock[position + 2]))
+ {
+ normalised ??= new StringBuilder(headerBlock.Length);
+ normalised.Append(headerBlock, segmentStart, position - segmentStart);
+ normalised.Append(' ');
+
+ position += 2;
+ while (position < headerBlock.Length && char.IsWhiteSpace(headerBlock[position]))
+ {
+ position++;
+ }
+
+ segmentStart = position;
+ continue;
+ }
+
+ if (position + 1 < headerBlock.Length &&
+ headerBlock[position] == '\r' &&
+ headerBlock[position + 1] == ' ')
+ {
+ normalised ??= new StringBuilder(headerBlock.Length);
+ normalised.Append(headerBlock, segmentStart, position - segmentStart);
+ normalised.Append(m_CRLF);
+
+ position += 2;
+ segmentStart = position;
+ continue;
+ }
+
+ position++;
+ }
+
+ if (normalised is null)
+ {
+ return headerBlock;
+ }
+
+ normalised.Append(headerBlock, segmentStart, headerBlock.Length - segmentStart);
+ return normalised.ToString();
+ }
+
// SIP headers can be extended across lines if the first character of the next line is at least on whitespace character.
- message = Regex.Replace(message, m_CRLF + @"\s+", " ", RegexOptions.Singleline);
+ // Some user agents couldn't get the \r\n bit right; normalise those at the same time.
+ message = NormalizeFoldedHeaderLines(message);
+
+ var headers = new List();
+ var messageSpan = message.AsSpan();
- // Some user agents couldn't get the \r\n bit right.
- message = Regex.Replace(message, "\r ", m_CRLF, RegexOptions.Singleline);
+ foreach (var headerRange in messageSpan.Split(m_CRLF.AsSpan()))
+ {
+ headers.Add(messageSpan[headerRange].ToString());
+ }
- return Regex.Split(message, m_CRLF);
+ return headers.ToArray();
}
public static SIPHeader ParseSIPHeaders(string[] headersCollection)
@@ -1626,15 +1691,15 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
string headerValue = null;
// If the first character of a line is whitespace it's a continuation of the previous line.
- if (headerLine.StartsWith(" "))
+ if (headerLine.StartsWith(" ", StringComparison.Ordinal))
{
headerName = lastHeader;
headerValue = headerLine.Trim();
}
else
{
- headerLine = headerLine.Trim();
- int delimiterIndex = headerLine.IndexOf(SIPConstants.HEADER_DELIMITER_CHAR);
+ var headerLineSpan = headerLine.AsSpan().Trim();
+ var delimiterIndex = headerLineSpan.IndexOf(SIPConstants.HEADER_DELIMITER_CHAR);
if (delimiterIndex == -1)
{
@@ -1642,17 +1707,44 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
continue;
}
- headerName = headerLine.Substring(0, delimiterIndex).Trim();
- headerValue = headerLine.Substring(delimiterIndex + 1).Trim();
+ headerLine = headerLineSpan.ToString();
+ headerName = headerLineSpan.Slice(0, delimiterIndex).Trim().ToString();
+ headerValue = headerLineSpan.Slice(delimiterIndex + 1).Trim().ToString();
}
try
{
- string headerNameLower = headerName.ToLower();
+ static bool TryGetSpaceSeparatedToken(ReadOnlySpan value, int tokenIndex, out ReadOnlySpan token)
+ {
+ token = value;
+
+ for (var i = 0; i < tokenIndex; i++)
+ {
+ var separatorIndex = token.IndexOf(' ');
+ if (separatorIndex == -1)
+ {
+ token = default;
+ return false;
+ }
+
+ token = token.Slice(separatorIndex + 1);
+ }
+
+ var nextSeparatorIndex = token.IndexOf(' ');
+ if (nextSeparatorIndex != -1)
+ {
+ token = token.Slice(0, nextSeparatorIndex);
+ }
+
+ return true;
+ }
+
+ bool IsHeaderName(string knownHeaderName) =>
+ string.Equals(headerName, knownHeaderName, StringComparison.OrdinalIgnoreCase);
#region Via
- if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_VIA ||
- headerNameLower == SIPHeaders.SIP_HEADER_VIA.ToLower())
+ if (IsHeaderName(SIPHeaders.SIP_COMPACTHEADER_VIA) ||
+ IsHeaderName(SIPHeaders.SIP_HEADER_VIA))
{
//sipHeader.RawVia += headerValue;
@@ -1668,32 +1760,32 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
}
#endregion
#region CallId
- else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_CALLID ||
- headerNameLower == SIPHeaders.SIP_HEADER_CALLID.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_COMPACTHEADER_CALLID) ||
+ IsHeaderName(SIPHeaders.SIP_HEADER_CALLID))
{
sipHeader.CallId = headerValue;
}
#endregion
#region CSeq
- else if (headerNameLower == SIPHeaders.SIP_HEADER_CSEQ.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_CSEQ))
{
//sipHeader.RawCSeq += headerValue;
- string[] cseqFields = headerValue.Split(' ');
- if (cseqFields == null || cseqFields.Length == 0)
+ var cseqFields = headerValue.AsSpan();
+ if (!TryGetSpaceSeparatedToken(cseqFields, 0, out var cseqNumber))
{
logger.LogWarning("The " + SIPHeaders.SIP_HEADER_CSEQ + " was empty.");
}
else
{
- if (!Int32.TryParse(cseqFields[0], out sipHeader.CSeq))
+ if (!int.TryParse(cseqNumber, out sipHeader.CSeq))
{
logger.LogWarning(SIPHeaders.SIP_HEADER_CSEQ + " did not contain a valid integer, {HeaderLine}.", headerLine);
}
- if (cseqFields != null && cseqFields.Length > 1)
+ if (TryGetSpaceSeparatedToken(cseqFields, 1, out var cseqMethod))
{
- sipHeader.CSeqMethod = SIPMethods.GetMethod(cseqFields[1]);
+ sipHeader.CSeqMethod = SIPMethods.GetMethod(cseqMethod.ToString());
}
else
{
@@ -1703,7 +1795,7 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
}
#endregion
#region Expires
- else if (headerNameLower == SIPHeaders.SIP_HEADER_EXPIRES.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_EXPIRES))
{
//sipHeader.RawExpires += headerValue;
@@ -1714,7 +1806,7 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
}
#endregion
#region Min-Expires
- else if (headerNameLower == SIPHeaders.SIP_HEADER_MINEXPIRES.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_MINEXPIRES))
{
if (!Int64.TryParse(headerValue, out sipHeader.MinExpires))
{
@@ -1723,8 +1815,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 (IsHeaderName(SIPHeaders.SIP_COMPACTHEADER_CONTACT) ||
+ IsHeaderName(SIPHeaders.SIP_HEADER_CONTACT))
{
List contacts = SIPContactHeader.ParseContactHeader(headerValue);
if (contacts != null && contacts.Count > 0)
@@ -1734,56 +1826,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 (IsHeaderName(SIPHeaders.SIP_COMPACTHEADER_FROM) ||
+ IsHeaderName(SIPHeaders.SIP_HEADER_FROM))
{
//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 (IsHeaderName(SIPHeaders.SIP_COMPACTHEADER_TO) ||
+ IsHeaderName(SIPHeaders.SIP_HEADER_TO))
{
//sipHeader.RawTo = headerValue;
sipHeader.To = SIPToHeader.ParseToHeader(headerValue);
}
#endregion
#region WWWAuthenticate
- else if (headerNameLower == SIPHeaders.SIP_HEADER_WWWAUTHENTICATE.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_WWWAUTHENTICATE))
{
//sipHeader.RawAuthentication = headerValue;
sipHeader.AuthenticationHeaders.Add(SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.WWWAuthenticate, headerValue));
}
#endregion
#region Authorization
- else if (headerNameLower == SIPHeaders.SIP_HEADER_AUTHORIZATION.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_AUTHORIZATION))
{
//sipHeader.RawAuthentication = headerValue;
sipHeader.AuthenticationHeaders.Add(SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.Authorize, headerValue));
}
#endregion
#region ProxyAuthentication
- else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXYAUTHENTICATION.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_PROXYAUTHENTICATION))
{
//sipHeader.RawAuthentication = headerValue;
sipHeader.AuthenticationHeaders.Add(SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.ProxyAuthenticate, headerValue));
}
#endregion
#region ProxyAuthorization
- else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXYAUTHORIZATION.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_PROXYAUTHORIZATION))
{
sipHeader.AuthenticationHeaders.Add(SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.ProxyAuthorization, headerValue));
}
#endregion
#region UserAgent
- else if (headerNameLower == SIPHeaders.SIP_HEADER_USERAGENT.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_USERAGENT))
{
sipHeader.UserAgent = headerValue;
}
#endregion
#region MaxForwards
- else if (headerNameLower == SIPHeaders.SIP_HEADER_MAXFORWARDS.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_MAXFORWARDS))
{
if (!Int32.TryParse(headerValue, out sipHeader.MaxForwards))
{
@@ -1792,8 +1884,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 (IsHeaderName(SIPHeaders.SIP_COMPACTHEADER_CONTENTLENGTH) ||
+ IsHeaderName(SIPHeaders.SIP_HEADER_CONTENTLENGTH))
{
if (!Int32.TryParse(headerValue, out sipHeader.ContentLength))
{
@@ -1802,20 +1894,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 (IsHeaderName(SIPHeaders.SIP_COMPACTHEADER_CONTENTTYPE) ||
+ IsHeaderName(SIPHeaders.SIP_HEADER_CONTENTTYPE))
{
sipHeader.ContentType = headerValue;
}
#endregion
#region Accept
- else if (headerNameLower == SIPHeaders.SIP_HEADER_ACCEPT.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_ACCEPT))
{
sipHeader.Accept = headerValue;
}
#endregion
#region Route
- else if (headerNameLower == SIPHeaders.SIP_HEADER_ROUTE.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_ROUTE))
{
SIPRouteSet routeSet = SIPRouteSet.ParseSIPRouteSet(headerValue);
if (routeSet != null)
@@ -1828,7 +1920,7 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
}
#endregion
#region RecordRoute
- else if (headerNameLower == SIPHeaders.SIP_HEADER_RECORDROUTE.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_RECORDROUTE))
{
SIPRouteSet recordRouteSet = SIPRouteSet.ParseSIPRouteSet(headerValue);
if (recordRouteSet != null)
@@ -1841,37 +1933,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 (IsHeaderName(SIPHeaders.SIP_HEADER_ALLOW_EVENTS) || IsHeaderName(SIPHeaders.SIP_COMPACTHEADER_ALLOWEVENTS))
{
sipHeader.AllowEvents = headerValue;
}
#endregion
#region Event
- else if (headerNameLower == SIPHeaders.SIP_HEADER_EVENT.ToLower() || headerNameLower == SIPHeaders.SIP_COMPACTHEADER_EVENT)
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_EVENT) || IsHeaderName(SIPHeaders.SIP_COMPACTHEADER_EVENT))
{
sipHeader.Event = headerValue;
}
#endregion
#region SubscriptionState.
- else if (headerNameLower == SIPHeaders.SIP_HEADER_SUBSCRIPTION_STATE.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_SUBSCRIPTION_STATE))
{
sipHeader.SubscriptionState = headerValue;
}
#endregion
#region Timestamp.
- else if (headerNameLower == SIPHeaders.SIP_HEADER_TIMESTAMP.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_TIMESTAMP))
{
sipHeader.Timestamp = headerValue;
}
#endregion
#region Date.
- else if (headerNameLower == SIPHeaders.SIP_HEADER_DATE.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_DATE))
{
sipHeader.Date = headerValue;
}
#endregion
#region Refer-Sub.
- else if (headerNameLower == SIPHeaders.SIP_HEADER_REFERSUB.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_REFERSUB))
{
if (sipHeader.ReferSub == null)
{
@@ -1884,8 +1976,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 (IsHeaderName(SIPHeaders.SIP_HEADER_REFERTO) ||
+ IsHeaderName(SIPHeaders.SIP_COMPACTHEADER_REFERTO))
{
if (sipHeader.ReferTo == null)
{
@@ -1898,19 +1990,19 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
}
#endregion
#region Referred-By.
- else if (headerNameLower == SIPHeaders.SIP_HEADER_REFERREDBY.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_REFERREDBY))
{
sipHeader.ReferredBy = headerValue;
}
#endregion
#region Replaces.
- else if (headerNameLower == SIPHeaders.SIP_HEADER_REPLACES.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_REPLACES))
{
sipHeader.Replaces = headerValue;
}
#endregion
#region Require.
- else if (headerNameLower == SIPHeaders.SIP_HEADER_REQUIRE.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_REQUIRE))
{
sipHeader.Require = headerValue;
@@ -1921,32 +2013,32 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
}
#endregion
#region Reason.
- else if (headerNameLower == SIPHeaders.SIP_HEADER_REASON.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_REASON))
{
sipHeader.Reason = headerValue;
}
#endregion
#region Proxy-ReceivedFrom.
- else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_RECEIVEDFROM.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_PROXY_RECEIVEDFROM))
{
sipHeader.ProxyReceivedFrom = headerValue;
}
#endregion
#region Proxy-ReceivedOn.
- else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_RECEIVEDON.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_PROXY_RECEIVEDON))
{
sipHeader.ProxyReceivedOn = headerValue;
}
#endregion
#region Proxy-SendFrom.
- else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_SENDFROM.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_PROXY_SENDFROM))
{
sipHeader.ProxySendFrom = headerValue;
}
#endregion
#region Supported
- else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_SUPPORTED ||
- headerNameLower == SIPHeaders.SIP_HEADER_SUPPORTED.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_COMPACTHEADER_SUPPORTED) ||
+ IsHeaderName(SIPHeaders.SIP_HEADER_SUPPORTED))
{
sipHeader.Supported = headerValue;
@@ -1957,149 +2049,149 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
}
#endregion
#region Authentication-Info
- else if (headerNameLower == SIPHeaders.SIP_HEADER_AUTHENTICATIONINFO.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_AUTHENTICATIONINFO))
{
sipHeader.AuthenticationInfo = headerValue;
}
#endregion
#region Accept-Encoding
- else if (headerNameLower == SIPHeaders.SIP_HEADER_ACCEPTENCODING.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_ACCEPTENCODING))
{
sipHeader.AcceptEncoding = headerValue;
}
#endregion
#region Accept-Language
- else if (headerNameLower == SIPHeaders.SIP_HEADER_ACCEPTLANGUAGE.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_ACCEPTLANGUAGE))
{
sipHeader.AcceptLanguage = headerValue;
}
#endregion
#region Alert-Info
- else if (headerNameLower == SIPHeaders.SIP_HEADER_ALERTINFO.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_ALERTINFO))
{
sipHeader.AlertInfo = headerValue;
}
#endregion
#region Allow
- else if (headerNameLower == SIPHeaders.SIP_HEADER_ALLOW.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_ALLOW))
{
sipHeader.Allow = headerValue;
}
#endregion
#region Call-Info
- else if (headerNameLower == SIPHeaders.SIP_HEADER_CALLINFO.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_CALLINFO))
{
sipHeader.CallInfo = headerValue;
}
#endregion
#region Content-Disposition
- else if (headerNameLower == SIPHeaders.SIP_HEADER_CONTENT_DISPOSITION.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_CONTENT_DISPOSITION))
{
sipHeader.ContentDisposition = headerValue;
}
#endregion
#region Content-Encoding
- else if (headerNameLower == SIPHeaders.SIP_HEADER_CONTENT_ENCODING.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_CONTENT_ENCODING))
{
sipHeader.ContentEncoding = headerValue;
}
#endregion
#region Content-Language
- else if (headerNameLower == SIPHeaders.SIP_HEADER_CONTENT_LANGUAGE.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_CONTENT_LANGUAGE))
{
sipHeader.ContentLanguage = headerValue;
}
#endregion
#region Error-Info
- else if (headerNameLower == SIPHeaders.SIP_HEADER_ERROR_INFO.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_ERROR_INFO))
{
sipHeader.ErrorInfo = headerValue;
}
#endregion
#region In-Reply-To
- else if (headerNameLower == SIPHeaders.SIP_HEADER_IN_REPLY_TO.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_IN_REPLY_TO))
{
sipHeader.InReplyTo = headerValue;
}
#endregion
#region MIME-Version
- else if (headerNameLower == SIPHeaders.SIP_HEADER_MIME_VERSION.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_MIME_VERSION))
{
sipHeader.MIMEVersion = headerValue;
}
#endregion
#region Organization
- else if (headerNameLower == SIPHeaders.SIP_HEADER_ORGANIZATION.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_ORGANIZATION))
{
sipHeader.Organization = headerValue;
}
#endregion
#region Priority
- else if (headerNameLower == SIPHeaders.SIP_HEADER_PRIORITY.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_PRIORITY))
{
sipHeader.Priority = headerValue;
}
#endregion
#region Proxy-Require
- else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_REQUIRE.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_PROXY_REQUIRE))
{
sipHeader.ProxyRequire = headerValue;
}
#endregion
#region Reply-To
- else if (headerNameLower == SIPHeaders.SIP_HEADER_REPLY_TO.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_REPLY_TO))
{
sipHeader.ReplyTo = headerValue;
}
#endregion
#region Retry-After
- else if (headerNameLower == SIPHeaders.SIP_HEADER_RETRY_AFTER.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_RETRY_AFTER))
{
sipHeader.RetryAfter = headerValue;
}
#endregion
#region Subject
- else if (headerNameLower == SIPHeaders.SIP_HEADER_SUBJECT.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_SUBJECT))
{
sipHeader.Subject = headerValue;
}
#endregion
#region Unsupported
- else if (headerNameLower == SIPHeaders.SIP_HEADER_UNSUPPORTED.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_UNSUPPORTED))
{
sipHeader.Unsupported = headerValue;
}
#endregion
#region Warning
- else if (headerNameLower == SIPHeaders.SIP_HEADER_WARNING.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_WARNING))
{
sipHeader.Warning = headerValue;
}
#endregion
#region ETag
- else if (headerNameLower == SIPHeaders.SIP_HEADER_ETAG.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_ETAG))
{
sipHeader.ETag = headerValue;
}
#endregion
#region RAck
- else if (headerNameLower == SIPHeaders.SIP_HEADER_RELIABLE_ACK.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_RELIABLE_ACK))
{
- string[] rackFields = headerValue.Split(' ');
- if (rackFields?.Length == 0)
+ var rackFields = headerValue.AsSpan();
+ if (!TryGetSpaceSeparatedToken(rackFields, 0, out var rackRSeq))
{
logger.LogWarning("The " + SIPHeaders.SIP_HEADER_RELIABLE_ACK + " was empty.");
}
else
{
- if (!Int32.TryParse(rackFields[0], out sipHeader.RAckRSeq))
+ if (!int.TryParse(rackRSeq, out sipHeader.RAckRSeq))
{
logger.LogWarning(SIPHeaders.SIP_HEADER_RELIABLE_ACK + " did not contain a valid integer for the RSeq being acknowledged, {HeaderLine}", headerLine);
}
- if (rackFields?.Length > 1)
+ if (TryGetSpaceSeparatedToken(rackFields, 1, out var rackCSeq))
{
- if (!Int32.TryParse(rackFields[1], out sipHeader.RAckCSeq))
+ if (!int.TryParse(rackCSeq, out sipHeader.RAckCSeq))
{
logger.LogWarning(SIPHeaders.SIP_HEADER_RELIABLE_ACK + " did not contain a valid integer for the CSeq being acknowledged, {HeaderLine}", headerLine);
}
@@ -2109,9 +2201,9 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
logger.LogWarning("There was no " + SIPHeaders.SIP_HEADER_RELIABLE_ACK + " method, {HeaderLine}", headerLine);
}
- if (rackFields?.Length > 2)
+ if (TryGetSpaceSeparatedToken(rackFields, 2, out var rackCSeqMethod))
{
- sipHeader.RAckCSeqMethod = SIPMethods.GetMethod(rackFields[2]);
+ sipHeader.RAckCSeqMethod = SIPMethods.GetMethod(rackCSeqMethod.ToString());
}
else
{
@@ -2121,7 +2213,7 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
}
#endregion
#region RSeq
- else if (headerNameLower == SIPHeaders.SIP_HEADER_RELIABLE_SEQ.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_RELIABLE_SEQ))
{
if (!Int32.TryParse(headerValue, out sipHeader.RSeq))
{
@@ -2130,25 +2222,25 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
}
#endregion
#region Server
- else if (headerNameLower == SIPHeaders.SIP_HEADER_SERVER.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_SERVER))
{
sipHeader.Server = headerValue;
}
#endregion
#region P-Asserted-Indentity
- else if (headerNameLower == SIPHeaders.SIP_HEADER_PASSERTED_IDENTITY.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_PASSERTED_IDENTITY))
{
sipHeader.PassertedIdentity.AddRange(SIPUriHeader.ParseHeader(headerValue));
}
#endregion
#region History-Info
- else if (headerNameLower == SIPHeaders.SIP_HEADER_HISTORY_INFO.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_HISTORY_INFO))
{
sipHeader.HistoryInfo.AddRange(SIPUriHeader.ParseHeader(headerValue));
}
#endregion
#region Diversion
- else if (headerNameLower == SIPHeaders.SIP_HEADER_DIVERSION.ToLower())
+ else if (IsHeaderName(SIPHeaders.SIP_HEADER_DIVERSION))
{
sipHeader.Diversion.AddRange(SIPUriHeader.ParseHeader(headerValue));
}
@@ -2199,35 +2291,49 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
/// Puts the SIP headers together into a string ready for transmission.
///
/// String representing the SIP headers.
- public new string ToString()
+ public override string ToString()
{
try
{
- StringBuilder headersBuilder = new StringBuilder();
+ var headersBuilder = new StringBuilder();
+
+ void AppendHeader(string headerName, T headerValue) =>
+ headersBuilder.Append($"{headerName}: {headerValue}{m_CRLF}");
headersBuilder.Append(Vias.ToString());
- string cseqField = null;
- if (this.CSeq >= 0)
+ if (To != null)
{
- cseqField = (this.CSeqMethod != SIPMethodsEnum.NONE) ? this.CSeq + " " + this.CSeqMethod.ToString() : this.CSeq.ToString();
+ AppendHeader(SIPHeaders.SIP_HEADER_TO, this.To);
}
- headersBuilder.Append((To != null) ? SIPHeaders.SIP_HEADER_TO + ": " + this.To.ToString() + m_CRLF : null);
- headersBuilder.Append((From != null) ? SIPHeaders.SIP_HEADER_FROM + ": " + this.From.ToString() + m_CRLF : null);
- headersBuilder.Append((CallId != null) ? SIPHeaders.SIP_HEADER_CALLID + ": " + this.CallId + m_CRLF : null);
- headersBuilder.Append((CSeq >= 0) ? SIPHeaders.SIP_HEADER_CSEQ + ": " + cseqField + m_CRLF : null);
+ if (From != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_FROM, this.From);
+ }
+
+ if (CallId != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_CALLID, this.CallId);
+ }
+
+ if (CSeq >= 0)
+ {
+ AppendHeader(
+ SIPHeaders.SIP_HEADER_CSEQ,
+ this.CSeqMethod != SIPMethodsEnum.NONE ? $"{this.CSeq} {this.CSeqMethod}" : this.CSeq.ToString());
+ }
#region Appending Contact header.
if (Contact != null && Contact.Count == 1)
{
- headersBuilder.Append(SIPHeaders.SIP_HEADER_CONTACT + ": " + Contact[0].ToString() + m_CRLF);
+ AppendHeader(SIPHeaders.SIP_HEADER_CONTACT, Contact[0]);
}
else if (Contact != null && Contact.Count > 1)
{
StringBuilder contactsBuilder = new StringBuilder();
- contactsBuilder.Append(SIPHeaders.SIP_HEADER_CONTACT + ": ");
+ contactsBuilder.Append($"{SIPHeaders.SIP_HEADER_CONTACT}: ");
bool firstContact = true;
foreach (SIPContactHeader contactHeader in Contact)
@@ -2238,29 +2344,76 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
}
else
{
- contactsBuilder.Append("," + contactHeader.ToString());
+ contactsBuilder.Append($",{contactHeader}");
}
firstContact = false;
}
- headersBuilder.Append(contactsBuilder.ToString() + m_CRLF);
+ headersBuilder.Append(contactsBuilder).Append(m_CRLF);
}
#endregion
- headersBuilder.Append((MaxForwards >= 0) ? SIPHeaders.SIP_HEADER_MAXFORWARDS + ": " + this.MaxForwards + m_CRLF : null);
- headersBuilder.Append((Routes != null && Routes.Length > 0) ? SIPHeaders.SIP_HEADER_ROUTE + ": " + Routes.ToString() + m_CRLF : null);
- headersBuilder.Append((RecordRoutes != null && RecordRoutes.Length > 0) ? SIPHeaders.SIP_HEADER_RECORDROUTE + ": " + RecordRoutes.ToString() + m_CRLF : null);
- headersBuilder.Append((UserAgent != null && UserAgent.Trim().Length != 0) ? SIPHeaders.SIP_HEADER_USERAGENT + ": " + this.UserAgent + m_CRLF : null);
- headersBuilder.Append((Expires != -1) ? SIPHeaders.SIP_HEADER_EXPIRES + ": " + this.Expires + m_CRLF : null);
- headersBuilder.Append((MinExpires != -1) ? SIPHeaders.SIP_HEADER_MINEXPIRES + ": " + this.MinExpires + m_CRLF : null);
- headersBuilder.Append((Accept != null) ? SIPHeaders.SIP_HEADER_ACCEPT + ": " + this.Accept + m_CRLF : null);
- headersBuilder.Append((AcceptEncoding != null) ? SIPHeaders.SIP_HEADER_ACCEPTENCODING + ": " + this.AcceptEncoding + m_CRLF : null);
- headersBuilder.Append((AcceptLanguage != null) ? SIPHeaders.SIP_HEADER_ACCEPTLANGUAGE + ": " + this.AcceptLanguage + m_CRLF : null);
- headersBuilder.Append((Allow != null) ? SIPHeaders.SIP_HEADER_ALLOW + ": " + this.Allow + m_CRLF : null);
- headersBuilder.Append((AlertInfo != null) ? SIPHeaders.SIP_HEADER_ALERTINFO + ": " + this.AlertInfo + m_CRLF : null);
- headersBuilder.Append((AuthenticationInfo != null) ? SIPHeaders.SIP_HEADER_AUTHENTICATIONINFO + ": " + this.AuthenticationInfo + m_CRLF : null);
+ if (MaxForwards >= 0)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_MAXFORWARDS, this.MaxForwards);
+ }
+
+ if (Routes != null && Routes.Length > 0)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_ROUTE, Routes);
+ }
+
+ if (RecordRoutes != null && RecordRoutes.Length > 0)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_RECORDROUTE, RecordRoutes);
+ }
+
+ if (!string.IsNullOrWhiteSpace(UserAgent))
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_USERAGENT, this.UserAgent);
+ }
+
+ if (Expires != -1)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_EXPIRES, this.Expires);
+ }
+
+ if (MinExpires != -1)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_MINEXPIRES, this.MinExpires);
+ }
+
+ if (Accept != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_ACCEPT, this.Accept);
+ }
+
+ if (AcceptEncoding != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_ACCEPTENCODING, this.AcceptEncoding);
+ }
+
+ if (AcceptLanguage != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_ACCEPTLANGUAGE, this.AcceptLanguage);
+ }
+
+ if (Allow != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_ALLOW, this.Allow);
+ }
+
+ if (AlertInfo != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_ALERTINFO, this.AlertInfo);
+ }
+
+ if (AuthenticationInfo != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_AUTHENTICATIONINFO, this.AuthenticationInfo);
+ }
if (AuthenticationHeaders.Count > 0)
{
@@ -2269,72 +2422,202 @@ public static SIPHeader ParseSIPHeaders(string[] headersCollection)
var value = authHeader.ToString();
if (value != null)
{
- headersBuilder.Append(authHeader.ToString() + m_CRLF);
+ headersBuilder.Append(value).Append(m_CRLF);
}
}
}
- headersBuilder.Append((CallInfo != null) ? SIPHeaders.SIP_HEADER_CALLINFO + ": " + this.CallInfo + m_CRLF : null);
- headersBuilder.Append((ContentDisposition != null) ? SIPHeaders.SIP_HEADER_CONTENT_DISPOSITION + ": " + this.ContentDisposition + m_CRLF : null);
- headersBuilder.Append((ContentEncoding != null) ? SIPHeaders.SIP_HEADER_CONTENT_ENCODING + ": " + this.ContentEncoding + m_CRLF : null);
- headersBuilder.Append((ContentLanguage != null) ? SIPHeaders.SIP_HEADER_CONTENT_LANGUAGE + ": " + this.ContentLanguage + m_CRLF : null);
- headersBuilder.Append((Date != null) ? SIPHeaders.SIP_HEADER_DATE + ": " + Date + m_CRLF : null);
- headersBuilder.Append((ErrorInfo != null) ? SIPHeaders.SIP_HEADER_ERROR_INFO + ": " + this.ErrorInfo + m_CRLF : null);
- headersBuilder.Append((InReplyTo != null) ? SIPHeaders.SIP_HEADER_IN_REPLY_TO + ": " + this.InReplyTo + m_CRLF : null);
- headersBuilder.Append((Organization != null) ? SIPHeaders.SIP_HEADER_ORGANIZATION + ": " + this.Organization + m_CRLF : null);
- headersBuilder.Append((Priority != null) ? SIPHeaders.SIP_HEADER_PRIORITY + ": " + Priority + m_CRLF : null);
- headersBuilder.Append((ProxyRequire != null) ? SIPHeaders.SIP_HEADER_PROXY_REQUIRE + ": " + this.ProxyRequire + m_CRLF : null);
- headersBuilder.Append((ReplyTo != null) ? SIPHeaders.SIP_HEADER_REPLY_TO + ": " + this.ReplyTo + m_CRLF : null);
- headersBuilder.Append((Require != null) ? SIPHeaders.SIP_HEADER_REQUIRE + ": " + Require + m_CRLF : null);
- headersBuilder.Append((RetryAfter != null) ? SIPHeaders.SIP_HEADER_RETRY_AFTER + ": " + this.RetryAfter + m_CRLF : null);
- headersBuilder.Append((Server != null && Server.Trim().Length != 0) ? SIPHeaders.SIP_HEADER_SERVER + ": " + this.Server + m_CRLF : null);
- headersBuilder.Append((Subject != null) ? SIPHeaders.SIP_HEADER_SUBJECT + ": " + Subject + m_CRLF : null);
- headersBuilder.Append((Supported != null) ? SIPHeaders.SIP_HEADER_SUPPORTED + ": " + Supported + m_CRLF : null);
- headersBuilder.Append((Timestamp != null) ? SIPHeaders.SIP_HEADER_TIMESTAMP + ": " + Timestamp + m_CRLF : null);
- headersBuilder.Append((Unsupported != null) ? SIPHeaders.SIP_HEADER_UNSUPPORTED + ": " + Unsupported + m_CRLF : null);
- headersBuilder.Append((Warning != null) ? SIPHeaders.SIP_HEADER_WARNING + ": " + Warning + m_CRLF : null);
- headersBuilder.Append((ETag != null) ? SIPHeaders.SIP_HEADER_ETAG + ": " + ETag + m_CRLF : null);
- headersBuilder.Append(SIPHeaders.SIP_HEADER_CONTENTLENGTH + ": " + this.ContentLength + m_CRLF);
- if (this.ContentType != null && this.ContentType.Trim().Length > 0)
- {
- headersBuilder.Append(SIPHeaders.SIP_HEADER_CONTENTTYPE + ": " + this.ContentType + m_CRLF);
+ if (CallInfo != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_CALLINFO, this.CallInfo);
+ }
+
+ if (ContentDisposition != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_CONTENT_DISPOSITION, this.ContentDisposition);
+ }
+
+ if (ContentEncoding != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_CONTENT_ENCODING, this.ContentEncoding);
+ }
+
+ if (ContentLanguage != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_CONTENT_LANGUAGE, this.ContentLanguage);
+ }
+
+ if (Date != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_DATE, Date);
+ }
+
+ if (ErrorInfo != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_ERROR_INFO, this.ErrorInfo);
+ }
+
+ if (InReplyTo != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_IN_REPLY_TO, this.InReplyTo);
+ }
+
+ if (Organization != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_ORGANIZATION, this.Organization);
+ }
+
+ if (Priority != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_PRIORITY, Priority);
+ }
+
+ if (ProxyRequire != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_PROXY_REQUIRE, this.ProxyRequire);
+ }
+
+ if (ReplyTo != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_REPLY_TO, this.ReplyTo);
+ }
+
+ if (Require != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_REQUIRE, Require);
+ }
+
+ if (RetryAfter != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_RETRY_AFTER, this.RetryAfter);
+ }
+
+ if (!string.IsNullOrWhiteSpace(Server))
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_SERVER, this.Server);
+ }
+
+ if (Subject != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_SUBJECT, Subject);
+ }
+
+ if (Supported != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_SUPPORTED, Supported);
+ }
+
+ if (Timestamp != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_TIMESTAMP, Timestamp);
+ }
+
+ if (Unsupported != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_UNSUPPORTED, Unsupported);
+ }
+
+ if (Warning != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_WARNING, Warning);
+ }
+
+ if (ETag != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_ETAG, ETag);
+ }
+
+ AppendHeader(SIPHeaders.SIP_HEADER_CONTENTLENGTH, this.ContentLength);
+ if (!string.IsNullOrWhiteSpace(this.ContentType))
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_CONTENTTYPE, this.ContentType);
}
// Non-core SIP headers.
- headersBuilder.Append((AllowEvents != null) ? SIPHeaders.SIP_HEADER_ALLOW_EVENTS + ": " + AllowEvents + m_CRLF : null);
- headersBuilder.Append((Event != null) ? SIPHeaders.SIP_HEADER_EVENT + ": " + Event + m_CRLF : null);
- headersBuilder.Append((SubscriptionState != null) ? SIPHeaders.SIP_HEADER_SUBSCRIPTION_STATE + ": " + SubscriptionState + m_CRLF : null);
- headersBuilder.Append((ReferSub != null) ? SIPHeaders.SIP_HEADER_REFERSUB + ": " + ReferSub + m_CRLF : null);
- headersBuilder.Append((ReferTo != null) ? SIPHeaders.SIP_HEADER_REFERTO + ": " + ReferTo + m_CRLF : null);
- headersBuilder.Append((ReferredBy != null) ? SIPHeaders.SIP_HEADER_REFERREDBY + ": " + ReferredBy + m_CRLF : null);
- headersBuilder.Append((Replaces != null) ? SIPHeaders.SIP_HEADER_REPLACES + ": " + Replaces + m_CRLF : null);
- headersBuilder.Append((Reason != null) ? SIPHeaders.SIP_HEADER_REASON + ": " + Reason + m_CRLF : null);
- headersBuilder.Append((RSeq != -1) ? SIPHeaders.SIP_HEADER_RELIABLE_SEQ + ": " + RSeq + m_CRLF : null);
- headersBuilder.Append((RAckRSeq != -1) ? SIPHeaders.SIP_HEADER_RELIABLE_ACK + ": " + RAckRSeq + " " + RAckCSeq + " " + RAckCSeqMethod + m_CRLF : null);
+ if (AllowEvents != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_ALLOW_EVENTS, AllowEvents);
+ }
+
+ if (Event != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_EVENT, Event);
+ }
+
+ if (SubscriptionState != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_SUBSCRIPTION_STATE, SubscriptionState);
+ }
+
+ if (ReferSub != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_REFERSUB, ReferSub);
+ }
+
+ if (ReferTo != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_REFERTO, ReferTo);
+ }
+
+ if (ReferredBy != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_REFERREDBY, ReferredBy);
+ }
+
+ if (Replaces != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_REPLACES, Replaces);
+ }
+
+ if (Reason != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_REASON, Reason);
+ }
+
+ if (RSeq != -1)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_RELIABLE_SEQ, RSeq);
+ }
+
+ if (RAckRSeq != -1)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_RELIABLE_ACK, $"{RAckRSeq} {RAckCSeq} {RAckCSeqMethod}");
+ }
foreach (var PAI in PassertedIdentity)
{
- headersBuilder.Append(SIPHeaders.SIP_HEADER_PASSERTED_IDENTITY + ": " + PAI + m_CRLF);
+ AppendHeader(SIPHeaders.SIP_HEADER_PASSERTED_IDENTITY, PAI);
}
foreach (var HistInfo in HistoryInfo)
{
- headersBuilder.Append(SIPHeaders.SIP_HEADER_HISTORY_INFO + ": " + HistInfo + m_CRLF);
+ AppendHeader(SIPHeaders.SIP_HEADER_HISTORY_INFO, HistInfo);
}
foreach (var DiversionHeader in Diversion)
{
- headersBuilder.Append(SIPHeaders.SIP_HEADER_DIVERSION + ": " + DiversionHeader + m_CRLF);
+ AppendHeader(SIPHeaders.SIP_HEADER_DIVERSION, DiversionHeader);
}
// Custom SIP headers.
- headersBuilder.Append((ProxyReceivedFrom != null) ? SIPHeaders.SIP_HEADER_PROXY_RECEIVEDFROM + ": " + ProxyReceivedFrom + m_CRLF : null);
- headersBuilder.Append((ProxyReceivedOn != null) ? SIPHeaders.SIP_HEADER_PROXY_RECEIVEDON + ": " + ProxyReceivedOn + m_CRLF : null);
- headersBuilder.Append((ProxySendFrom != null) ? SIPHeaders.SIP_HEADER_PROXY_SENDFROM + ": " + ProxySendFrom + m_CRLF : null);
+ if (ProxyReceivedFrom != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_PROXY_RECEIVEDFROM, ProxyReceivedFrom);
+ }
+
+ if (ProxyReceivedOn != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_PROXY_RECEIVEDON, ProxyReceivedOn);
+ }
+
+ if (ProxySendFrom != null)
+ {
+ AppendHeader(SIPHeaders.SIP_HEADER_PROXY_SENDFROM, ProxySendFrom);
+ }
// Unknown SIP headers
foreach (string unknownHeader in UnknownHeaders)
{
- headersBuilder.Append(unknownHeader + m_CRLF);
+ headersBuilder.Append(unknownHeader).Append(m_CRLF);
}
return headersBuilder.ToString();
@@ -2356,7 +2639,7 @@ private void Validate()
public void SetDateHeader()
{
- Date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss ") + "GMT";
+ Date = $"{DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss ")}GMT";
}
public void SetDateHeader(bool useLocalTime, string timeFormat)
@@ -2395,11 +2678,12 @@ public string GetUnknownHeaderValue(string unknownHeaderName)
continue;
}
- string headerName = trimmedHeader.Substring(0, delimiterIndex).Trim();
+ var trimmedHeaderSpan = trimmedHeader.AsSpan();
+ var headerName = trimmedHeaderSpan.Slice(0, delimiterIndex).Trim().ToString();
- if (headerName.ToLower() == unknownHeaderName.ToLower())
+ if (string.Equals(headerName, unknownHeaderName, StringComparison.OrdinalIgnoreCase))
{
- return trimmedHeader.Substring(delimiterIndex + 1).Trim();
+ return trimmedHeaderSpan.Slice(delimiterIndex + 1).Trim().ToString();
}
}
diff --git a/src/SIPSorcery/core/SIP/SIPParameters.cs b/src/SIPSorcery/core/SIP/SIPParameters.cs
index 5496f1cac..6924686b4 100644
--- a/src/SIPSorcery/core/SIP/SIPParameters.cs
+++ b/src/SIPSorcery/core/SIP/SIPParameters.cs
@@ -19,7 +19,9 @@
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
+using System.Text;
using Microsoft.Extensions.Logging;
+using Polyfills;
using SIPSorcery.Sys;
namespace SIPSorcery.SIP
@@ -85,14 +87,125 @@ private void Initialise(string sipString, char delimiter)
{
TagDelimiter = delimiter;
- string[] keyValuePairs = GetKeyValuePairsFromQuoted(sipString, delimiter);
+ void AddKeyValuePair(ReadOnlySpan keyValuePair, Span keyValueRange)
+ {
+ if (keyValuePair.Trim().Length > 0)
+ {
+ if (keyValuePair.Split(keyValueRange, TAG_NAME_VALUE_SEPERATOR) == 2)
+ {
+ var keyName = keyValuePair[keyValueRange[0]].Trim().ToString();
- if (keyValuePairs != null && keyValuePairs.Length > 0)
+ // If this is not the parameter that is being removed put it back on.
+ if (!m_dictionary.ContainsKey(keyName))
+ {
+ m_dictionary.TryAdd(keyName, keyValuePair[keyValueRange[1]].Trim().ToString());
+ }
+ }
+ else
+ {
+ // Keys with no values are valid in SIP so they get added to the collection with a null value.
+ var keyName = keyValuePair.ToString();
+ if (!m_dictionary.ContainsKey(keyName))
+ {
+ m_dictionary.TryAdd(keyName, null);
+ }
+ }
+ }
+ }
+
+ static int IndexOfDelimiterOrQuote(ReadOnlySpan value, int startIndex, char delimiter)
{
- foreach (string keyValuePair in keyValuePairs)
+ var remaining = value.Slice(startIndex);
+ var delimiterIndex = remaining.IndexOf(delimiter);
+ var quoteIndex = remaining.IndexOf(QUOTE);
+
+ if (delimiterIndex == -1)
+ {
+ return quoteIndex == -1 ? -1 : startIndex + quoteIndex;
+ }
+
+ if (quoteIndex == -1)
{
- AddKeyValuePair(keyValuePair, m_dictionary);
+ return startIndex + delimiterIndex;
}
+
+ return startIndex + Math.Min(delimiterIndex, quoteIndex);
+ }
+
+ var sipParameters = sipString.AsSpan();
+ if (sipParameters.Trim().Length == 0)
+ {
+ return;
+ }
+
+ Span keyValueRange = stackalloc Range[2];
+ if (sipParameters.IndexOf(delimiter) == -1)
+ {
+ AddKeyValuePair(sipParameters, keyValueRange);
+ return;
+ }
+
+ var startParameterPosn = 0;
+ var inParameterPosn = 0;
+ var inQuotedStr = false;
+
+ while (inParameterPosn != -1 && inParameterPosn < sipParameters.Length)
+ {
+ inParameterPosn = IndexOfDelimiterOrQuote(sipParameters, inParameterPosn, delimiter);
+
+ // Determine if the delimiter position represents the end of the parameter or is in a quoted string.
+ if (inParameterPosn != -1)
+ {
+ if (inParameterPosn <= startParameterPosn && sipParameters[inParameterPosn] == delimiter)
+ {
+ // Initial or doubled up Parameter delimiter character, ignore and move on.
+ inQuotedStr = false;
+ inParameterPosn++;
+ startParameterPosn = inParameterPosn;
+ }
+ else if (sipParameters[inParameterPosn] == QUOTE)
+ {
+ if (inQuotedStr && inParameterPosn > 0 && sipParameters[inParameterPosn - 1] != BACK_SLASH)
+ {
+ // If in a quoted string and this quote has not been escaped close the quoted string.
+ inQuotedStr = false;
+ }
+ else if (inQuotedStr && inParameterPosn > 0 && sipParameters[inParameterPosn - 1] == BACK_SLASH)
+ {
+ // Do nothing, quote has been escaped in a quoted string.
+ }
+ else if (!inQuotedStr)
+ {
+ // Start quoted string.
+ inQuotedStr = true;
+ }
+
+ inParameterPosn++;
+ }
+ else
+ {
+ if (!inQuotedStr)
+ {
+ // Parameter delimiter found and not in quoted string therefore this is a parameter separator.
+ AddKeyValuePair(sipParameters.Slice(startParameterPosn, inParameterPosn - startParameterPosn), keyValueRange);
+
+ inParameterPosn++;
+ startParameterPosn = inParameterPosn;
+ }
+ else
+ {
+ // Do nothing, separator character is within a quoted string.
+ inParameterPosn++;
+ }
+ }
+ }
+ }
+
+ // Add the last parameter.
+ if (startParameterPosn < sipParameters.Length)
+ {
+ // Parameter delimiter found and not in quoted string therefore this is a parameter separator.
+ AddKeyValuePair(sipParameters.Slice(startParameterPosn), keyValueRange);
}
}
@@ -102,7 +215,7 @@ public static string[] GetKeyValuePairsFromQuoted(string quotedString, char deli
{
List keyValuePairList = new List();
- if (quotedString == null || quotedString.Trim().Length == 0)
+ if (string.IsNullOrWhiteSpace(quotedString))
{
return null;
}
@@ -112,13 +225,32 @@ public static string[] GetKeyValuePairsFromQuoted(string quotedString, char deli
}
else
{
+ static int IndexOfDelimiterOrQuote(ReadOnlySpan value, int startIndex, char delimiter)
+ {
+ var remaining = value.Slice(startIndex);
+ var delimiterIndex = remaining.IndexOf(delimiter);
+ var quoteIndex = remaining.IndexOf(QUOTE);
+
+ if (delimiterIndex == -1)
+ {
+ return quoteIndex == -1 ? -1 : startIndex + quoteIndex;
+ }
+
+ if (quoteIndex == -1)
+ {
+ return startIndex + delimiterIndex;
+ }
+
+ return startIndex + Math.Min(delimiterIndex, quoteIndex);
+ }
+
int startParameterPosn = 0;
int inParameterPosn = 0;
bool inQuotedStr = false;
while (inParameterPosn != -1 && inParameterPosn < quotedString.Length)
{
- inParameterPosn = quotedString.IndexOfAny(new char[] { delimiter, QUOTE }, inParameterPosn);
+ inParameterPosn = IndexOfDelimiterOrQuote(quotedString.AsSpan(), inParameterPosn, delimiter);
// Determine if the delimiter position represents the end of the parameter or is in a quoted string.
if (inParameterPosn != -1)
@@ -187,32 +319,6 @@ public static string[] GetKeyValuePairsFromQuoted(string quotedString, char deli
}
}
- private void AddKeyValuePair(string keyValuePair, ConcurrentDictionary dictionary)
- {
- if (keyValuePair != null && keyValuePair.Trim().Length > 0)
- {
- int seperatorPosn = keyValuePair.IndexOf(TAG_NAME_VALUE_SEPERATOR);
- if (seperatorPosn != -1)
- {
- string keyName = keyValuePair.Substring(0, seperatorPosn).Trim();
-
- // If this is not the parameter that is being removed put it back on.
- if (!dictionary.ContainsKey(keyName))
- {
- dictionary.TryAdd(keyName, keyValuePair.Substring(seperatorPosn + 1).Trim());
- }
- }
- else
- {
- // Keys with no values are valid in SIP so they get added to the collection with a null value.
- if (!dictionary.ContainsKey(keyValuePair))
- {
- dictionary.TryAdd(keyValuePair, null);
- }
- }
- }
- }
-
public void Set(string name, string value)
{
if (m_dictionary.ContainsKey(name))
@@ -290,24 +396,23 @@ public string[] GetKeys()
public override string ToString()
{
- string paramStr = null;
+ var paramStr = default(StringBuilder);
if (m_dictionary != null)
{
foreach (KeyValuePair param in m_dictionary)
{
- if (param.Value != null && param.Value.Trim().Length > 0)
- {
- paramStr += TagDelimiter + param.Key + TAG_NAME_VALUE_SEPERATOR + SIPEscape.SIPURIParameterEscape(param.Value);
- }
- else
+ paramStr ??= new StringBuilder();
+ paramStr.Append(TagDelimiter).Append(param.Key);
+
+ if (!string.IsNullOrWhiteSpace(param.Value))
{
- paramStr += TagDelimiter + param.Key;
+ paramStr.Append(TAG_NAME_VALUE_SEPERATOR).Append(SIPEscape.SIPURIParameterEscape(param.Value));
}
}
}
- return paramStr;
+ return paramStr?.ToString();
}
public override int GetHashCode()
diff --git a/src/SIPSorcery/core/SIP/SIPRequest.cs b/src/SIPSorcery/core/SIP/SIPRequest.cs
index 2c63bbaeb..16d3663f6 100644
--- a/src/SIPSorcery/core/SIP/SIPRequest.cs
+++ b/src/SIPSorcery/core/SIP/SIPRequest.cs
@@ -47,11 +47,11 @@ public string StatusLine
get
{
string methodStr = (Method != SIPMethodsEnum.UNKNOWN) ? Method.ToString() : UnknownMethod;
- return methodStr + " " + URI.ToString() + " " + SIPVersion;
+ return $"{methodStr} {URI.ToString()} {SIPVersion}";
}
}
- private SIPRequest(Encoding sipEncoding, Encoding sipBodyEncoding) : this(SIPMethodsEnum.NONE, SIPURI.None,sipEncoding,sipBodyEncoding)
+ private SIPRequest(Encoding sipEncoding, Encoding sipBodyEncoding) : this(SIPMethodsEnum.NONE, SIPURI.None, sipEncoding, sipBodyEncoding)
{
}
@@ -59,18 +59,18 @@ private SIPRequest()
{
}
- public SIPRequest(SIPMethodsEnum method, string uri):this(method, SIPURI.ParseSIPURI(uri))
+ public SIPRequest(SIPMethodsEnum method, string uri) : this(method, SIPURI.ParseSIPURI(uri))
{
}
- public SIPRequest(SIPMethodsEnum method, SIPURI uri)
+ public SIPRequest(SIPMethodsEnum method, SIPURI uri)
{
Method = method;
URI = uri;
SIPVersion = m_sipFullVersion;
}
- public SIPRequest(SIPMethodsEnum method, SIPURI uri,Encoding sipEncoding,Encoding sipBodyEncoding):base(sipEncoding,sipBodyEncoding)
+ public SIPRequest(SIPMethodsEnum method, SIPURI uri, Encoding sipEncoding, Encoding sipBodyEncoding) : base(sipEncoding, sipBodyEncoding)
{
Method = method;
URI = uri;
@@ -80,19 +80,17 @@ public SIPRequest(SIPMethodsEnum method, SIPURI uri,Encoding sipEncoding,Encodin
public static SIPRequest ParseSIPRequest(SIPMessageBuffer sipMessage) =>
ParseSIPRequest(sipMessage, SIPConstants.DEFAULT_ENCODING, SIPConstants.DEFAULT_ENCODING);
- public static SIPRequest ParseSIPRequest(SIPMessageBuffer sipMessage,Encoding sipEncoding,Encoding sipBodyEncoding)
+ public static SIPRequest ParseSIPRequest(SIPMessageBuffer sipMessage, Encoding sipEncoding, Encoding sipBodyEncoding)
{
try
{
- SIPRequest sipRequest = new SIPRequest(sipEncoding,sipBodyEncoding);
+ SIPRequest sipRequest = new SIPRequest(sipEncoding, sipBodyEncoding);
sipRequest.LocalSIPEndPoint = sipMessage.LocalSIPEndPoint;
sipRequest.RemoteSIPEndPoint = sipMessage.RemoteSIPEndPoint;
- string statusLine = sipMessage.FirstLine;
-
- int firstSpacePosn = statusLine.IndexOf(" ");
-
- string method = statusLine.Substring(0, firstSpacePosn).Trim();
+ var statusLine = sipMessage.FirstLine.AsSpan();
+ var firstSpacePosn = statusLine.IndexOf(' ');
+ var method = statusLine.Slice(0, firstSpacePosn).Trim().ToString();
sipRequest.Method = SIPMethods.GetMethod(method);
if (sipRequest.Method == SIPMethodsEnum.UNKNOWN)
{
@@ -100,15 +98,15 @@ public static SIPRequest ParseSIPRequest(SIPMessageBuffer sipMessage,Encoding si
logger.LogWarning("Unknown SIP method received {UnknownMethod}.", sipRequest.UnknownMethod);
}
- statusLine = statusLine.Substring(firstSpacePosn).Trim();
- int secondSpacePosn = statusLine.IndexOf(" ");
+ statusLine = statusLine.Slice(firstSpacePosn).Trim();
+ var secondSpacePosn = statusLine.IndexOf(' ');
if (secondSpacePosn != -1)
{
- string uriStr = statusLine.Substring(0, secondSpacePosn);
+ var uriStr = statusLine.Slice(0, secondSpacePosn).ToString();
sipRequest.URI = SIPURI.ParseSIPURI(uriStr);
- sipRequest.SIPVersion = statusLine.Substring(secondSpacePosn, statusLine.Length - secondSpacePosn).Trim();
+ sipRequest.SIPVersion = statusLine.Slice(secondSpacePosn).Trim().ToString();
sipRequest.Header = SIPHeader.ParseSIPHeaders(sipMessage.SIPHeaders);
sipRequest.BodyBuffer = sipMessage.Body;
@@ -133,12 +131,12 @@ public static SIPRequest ParseSIPRequest(SIPMessageBuffer sipMessage,Encoding si
public static SIPRequest ParseSIPRequest(string sipMessageStr) =>
ParseSIPRequest(sipMessageStr, SIPConstants.DEFAULT_ENCODING, SIPConstants.DEFAULT_ENCODING);
- public static SIPRequest ParseSIPRequest(string sipMessageStr,Encoding sipEncoding,Encoding sipBodyEncoding)
+ public static SIPRequest ParseSIPRequest(string sipMessageStr, Encoding sipEncoding, Encoding sipBodyEncoding)
{
try
{
- SIPMessageBuffer sipMessageBuffer = SIPMessageBuffer.ParseSIPMessage(sipMessageStr, sipEncoding,sipBodyEncoding, null, null);
- return SIPRequest.ParseSIPRequest(sipMessageBuffer,sipEncoding,sipBodyEncoding);
+ SIPMessageBuffer sipMessageBuffer = SIPMessageBuffer.ParseSIPMessage(sipMessageStr, sipEncoding, sipBodyEncoding, null, null);
+ return SIPRequest.ParseSIPRequest(sipMessageBuffer, sipEncoding, sipBodyEncoding);
}
catch (SIPValidationException)
{
@@ -370,7 +368,7 @@ public SIPRequest DuplicateAndAuthenticate(List authent
var md5AuthHeader = SIPAuthChallenge.GetAuthenticationHeader(authenticationChallenges, this.URI, this.Method, username, password);
dupRequest.Header.AuthenticationHeaders.Add(md5AuthHeader);
}
-
+
return dupRequest;
}
}
diff --git a/src/SIPSorcery/core/SIP/SIPResponse.cs b/src/SIPSorcery/core/SIP/SIPResponse.cs
index cc60a0af1..14be4b894 100644
--- a/src/SIPSorcery/core/SIP/SIPResponse.cs
+++ b/src/SIPSorcery/core/SIP/SIPResponse.cs
@@ -65,14 +65,14 @@ public bool IsSuccessStatusCode
///
public string ShortDescription
{
- get { return Header?.CSeqMethod + " " + StatusCode + " " + ReasonPhrase; }
+ get { return $"{Header?.CSeqMethod} {StatusCode} {ReasonPhrase}"; }
}
private SIPResponse(
Encoding sipEncoding,
- Encoding sipBodyEncoding) : this(SIPResponseStatusCodesEnum.None, string.Empty,sipEncoding,sipBodyEncoding)
+ Encoding sipBodyEncoding) : this(SIPResponseStatusCodesEnum.None, string.Empty, sipEncoding, sipBodyEncoding)
{ }
- private SIPResponse():this(SIPResponseStatusCodesEnum.None,string.Empty)
+ private SIPResponse() : this(SIPResponseStatusCodesEnum.None, string.Empty)
{ }
public SIPResponse(
@@ -97,7 +97,7 @@ public SIPResponse(
SIPResponseStatusCodesEnum responseStatus,
string reasonPhrase,
Encoding sipEncoding,
- Encoding sipBodyEncoding):base(sipEncoding,sipBodyEncoding)
+ Encoding sipBodyEncoding) : base(sipEncoding, sipBodyEncoding)
{
SIPVersion = m_sipFullVersion;
StatusCode = (int)responseStatus;
@@ -116,22 +116,21 @@ public static SIPResponse ParseSIPResponse(SIPMessageBuffer sipMessageBuffer) =>
///
///
/// A new SIP response object.
- public static SIPResponse ParseSIPResponse(SIPMessageBuffer sipMessageBuffer,Encoding sipEncoding,Encoding sipBodyEncoding)
+ public static SIPResponse ParseSIPResponse(SIPMessageBuffer sipMessageBuffer, Encoding sipEncoding, Encoding sipBodyEncoding)
{
try
{
- SIPResponse sipResponse = new SIPResponse(sipEncoding,sipBodyEncoding);
+ SIPResponse sipResponse = new SIPResponse(sipEncoding, sipBodyEncoding);
sipResponse.LocalSIPEndPoint = sipMessageBuffer.LocalSIPEndPoint;
sipResponse.RemoteSIPEndPoint = sipMessageBuffer.RemoteSIPEndPoint;
- string statusLine = sipMessageBuffer.FirstLine;
+ var statusLine = sipMessageBuffer.FirstLine.AsSpan();
+ var firstSpacePosn = statusLine.IndexOf(' ');
- int firstSpacePosn = statusLine.IndexOf(" ");
-
- sipResponse.SIPVersion = statusLine.Substring(0, firstSpacePosn).Trim();
- statusLine = statusLine.Substring(firstSpacePosn).Trim();
- sipResponse.StatusCode = Convert.ToInt32(statusLine.Substring(0, 3));
+ sipResponse.SIPVersion = statusLine.Slice(0, firstSpacePosn).Trim().ToString();
+ statusLine = statusLine.Slice(firstSpacePosn).Trim();
+ sipResponse.StatusCode = Convert.ToInt32(statusLine.Slice(0, 3).ToString());
sipResponse.Status = SIPResponseStatusCodes.GetStatusTypeForCode(sipResponse.StatusCode);
- sipResponse.ReasonPhrase = statusLine.Substring(3).Trim();
+ sipResponse.ReasonPhrase = statusLine.Slice(3).Trim().ToString();
sipResponse.Header = SIPHeader.ParseSIPHeaders(sipMessageBuffer.SIPHeaders);
sipResponse.BodyBuffer = sipMessageBuffer.Body;
@@ -144,7 +143,7 @@ public static SIPResponse ParseSIPResponse(SIPMessageBuffer sipMessageBuffer,Enc
}
catch (Exception excp)
{
- logger.LogError(excp, "Exception ParseSIPResponse: {SipMessage}. {ErrorMessage}", sipMessageBuffer.RawMessage, excp.Message);
+ logger.LogError(excp, "Exception ParseSIPResponse: {SipMessage}. {ErrorMessage}", sipMessageBuffer.RawMessage, excp.Message);
throw new SIPValidationException(SIPValidationFieldsEnum.Response, "Error parsing SIP Response");
}
}
@@ -159,12 +158,12 @@ public static SIPResponse ParseSIPResponse(string sipMessageStr) =>
///
///
/// A new SIP response object.
- public static SIPResponse ParseSIPResponse(string sipMessageStr,Encoding sipEncoding, Encoding sipBodyEncoding)
+ public static SIPResponse ParseSIPResponse(string sipMessageStr, Encoding sipEncoding, Encoding sipBodyEncoding)
{
try
{
SIPMessageBuffer sipMessage = SIPMessageBuffer.ParseSIPMessage(sipMessageStr, sipEncoding, sipBodyEncoding, null, null);
- return SIPResponse.ParseSIPResponse(sipMessage, sipEncoding,sipBodyEncoding);
+ return SIPResponse.ParseSIPResponse(sipMessage, sipEncoding, sipBodyEncoding);
}
catch (SIPValidationException)
{
@@ -183,11 +182,10 @@ public static SIPResponse ParseSIPResponse(string sipMessageStr,Encoding sipEnco
/// A string representation of the SIP response.
public override string ToString()
{
- string reasonPhrase = (!ReasonPhrase.IsNullOrBlank()) ? " " + ReasonPhrase : null;
+ string reasonPhrase = (!ReasonPhrase.IsNullOrBlank()) ? $" {ReasonPhrase}" : null;
- string message =
- SIPVersion + " " + StatusCode + reasonPhrase + m_CRLF +
- this.Header.ToString();
+ var message =
+ $"{SIPVersion} {StatusCode}{reasonPhrase}{m_CRLF}{Header}";
if (Body != null)
{
@@ -334,8 +332,8 @@ public static SIPResponse GetResponse(SIPEndPoint localSIPEndPoint, SIPEndPoint
public byte[] GetBytes()
{
- string reasonPhrase = (!ReasonPhrase.IsNullOrBlank()) ? " " + ReasonPhrase : null;
- string firstLine = SIPVersion + " " + StatusCode + reasonPhrase + m_CRLF;
+ string reasonPhrase = (!ReasonPhrase.IsNullOrBlank()) ? $" {ReasonPhrase}" : null;
+ string firstLine = $"{SIPVersion} {StatusCode}{reasonPhrase}{m_CRLF}";
return base.GetBytes(firstLine);
}
}
diff --git a/src/SIPSorcery/core/SIP/SIPTransport.cs b/src/SIPSorcery/core/SIP/SIPTransport.cs
index c2d6ce2bf..a49e1b931 100644
--- a/src/SIPSorcery/core/SIP/SIPTransport.cs
+++ b/src/SIPSorcery/core/SIP/SIPTransport.cs
@@ -827,7 +827,7 @@ private SIPHeader AdjustHeadersForEndPoint(SIPEndPoint sendFromSIPEndPoint, SIPH
if (IPAddress.TryParse(ContactHost, out _))
{
// If the custom host is an IP address include the port number that's being used for the send.
- copy.Contact.Single().ContactURI.Host = ContactHost + ":" + sendFromEndPoint.Port.ToString();
+ copy.Contact.Single().ContactURI.Host = $"{ContactHost}:{sendFromEndPoint.Port.ToString()}";
}
else
{
@@ -920,8 +920,8 @@ private Task SIPMessageReceived(
// Treat all messages that don't match STUN requests as SIP.
if (buffer.Length > SIPConstants.SIP_MAXIMUM_RECEIVE_LENGTH)
{
- string rawErrorMessage = m_sipEncoding.GetString(buffer, 0, 1024) + "\r\n..truncated";
- SIPBadRequestInTraceEvent?.Invoke(localEndPoint, remoteEndPoint, "SIP message too large, " + buffer.Length + " bytes, maximum allowed is " + SIPConstants.SIP_MAXIMUM_RECEIVE_LENGTH + " bytes.", SIPValidationFieldsEnum.Request, rawErrorMessage);
+ string rawErrorMessage = $"{m_sipEncoding.GetString(buffer, 0, 1024)}\r\n..truncated";
+ SIPBadRequestInTraceEvent?.Invoke(localEndPoint, remoteEndPoint, $"SIP message too large, {buffer.Length} bytes, maximum allowed is {SIPConstants.SIP_MAXIMUM_RECEIVE_LENGTH} bytes.", SIPValidationFieldsEnum.Request, rawErrorMessage);
SIPResponse tooLargeResponse = SIPResponse.GetResponse(localEndPoint, remoteEndPoint, SIPResponseStatusCodesEnum.MessageTooLarge, null);
return SendResponseAsync(tooLargeResponse);
}
@@ -1012,7 +1012,7 @@ private Task SIPMessageReceived(
}
else
{
- SIPBadRequestInTraceEvent?.Invoke(localEndPoint, remoteEndPoint, "ACK received on " + requestTransaction.TransactionState + " transaction, ignoring.", SIPValidationFieldsEnum.Request, null);
+ SIPBadRequestInTraceEvent?.Invoke(localEndPoint, remoteEndPoint, $"ACK received on {requestTransaction.TransactionState} transaction, ignoring.", SIPValidationFieldsEnum.Request, null);
}
}
else if (sipRequest.Method == SIPMethodsEnum.PRACK)
@@ -1107,7 +1107,7 @@ private Task SIPMessageReceived(
catch (Exception excp)
{
logger.LogError(excp, "Exception SIPMessageReceived. {ErrorMessage}", excp.Message);
- SIPBadRequestInTraceEvent?.Invoke(localEndPoint, remoteEndPoint, "Exception SIPTransport. " + excp.Message, SIPValidationFieldsEnum.Unknown, rawSIPMessage);
+ SIPBadRequestInTraceEvent?.Invoke(localEndPoint, remoteEndPoint, $"Exception SIPTransport. {excp.Message}", SIPValidationFieldsEnum.Unknown, rawSIPMessage);
return Task.FromResult(SocketError.Fault);
}
}
diff --git a/src/SIPSorcery/core/SIP/SIPURI.cs b/src/SIPSorcery/core/SIP/SIPURI.cs
index 2558eae58..6406c8b7f 100644
--- a/src/SIPSorcery/core/SIP/SIPURI.cs
+++ b/src/SIPSorcery/core/SIP/SIPURI.cs
@@ -124,8 +124,8 @@ public string CanonicalAddress
{
get
{
- string canonicalAddress = Scheme + ":";
- canonicalAddress += !String.IsNullOrEmpty(User) ? User + "@" : null;
+ string canonicalAddress = $"{Scheme}:";
+ canonicalAddress += !String.IsNullOrEmpty(User) ? $"{User}@" : null;
// First expression is for IPv6 addresses with a port and tel: URIs.
// Second expression is for IPv4 addresses and hostnames with a port.
@@ -137,7 +137,7 @@ public string CanonicalAddress
}
else
{
- canonicalAddress += Host + ":" + SIPConstants.GetDefaultPort(Protocol);
+ canonicalAddress += $"{Host}:{SIPConstants.GetDefaultPort(Protocol)}";
}
return canonicalAddress;
@@ -182,7 +182,7 @@ public string MAddrOrHost
{
return MAddrOrHostAddress;
}
- return MAddrOrHostAddress + ":" + this.HostPort;
+ return $"{MAddrOrHostAddress}:{this.HostPort}";
}
}
@@ -294,7 +294,7 @@ public void ParseUserParameters()
{
// in case there is a ';' we check wheter there is a '=' in the first part,
// if so we assume there is nothing but params
- if (User.Substring(0, UserParamsPosn).IndexOf(TAG_NAME_VALUE_SEPERATOR) != -1)
+ if (User.AsSpan(0, UserParamsPosn).IndexOf(TAG_NAME_VALUE_SEPERATOR) != -1)
{
UserParameters = new SIPParameters(User, PARAM_TAG_DELIMITER);
UserWithoutParameters = "";
@@ -358,7 +358,7 @@ public static SIPURI ParseSIPURI(string uri)
}
catch
{
- throw new SIPValidationException(SIPValidationFieldsEnum.URI, SIPResponseStatusCodesEnum.UnsupportedURIScheme, "SIP scheme " + uri.Substring(0, colonPosn) + " was not understood");
+ throw new SIPValidationException(SIPValidationFieldsEnum.URI, SIPResponseStatusCodesEnum.UnsupportedURIScheme, $"SIP scheme {uri.Substring(0, colonPosn)} was not understood");
}
string uriHostPortion = uri.Substring(colonPosn + 1);
@@ -448,15 +448,15 @@ public static SIPURI ParseSIPURI(string uri)
public static SIPURI ParseSIPURIRelaxed(string partialURI)
{
- if (partialURI == null || partialURI.Trim().Length == 0)
+ if (string.IsNullOrWhiteSpace(partialURI))
{
return null;
}
else
{
- string regexSchemePattern = "^(" + SIPSchemesEnum.sip + "|" + SIPSchemesEnum.sips + "):";
+ string regexSchemePattern = $"^({SIPSchemesEnum.sip}|{SIPSchemesEnum.sips}):";
- if (Regex.Match(partialURI, regexSchemePattern + @"\S+").Success)
+ if (Regex.Match(partialURI, $@"{regexSchemePattern}\S+").Success)
{
// The partial uri is already valid.
return SIPURI.ParseSIPURI(partialURI);
@@ -577,7 +577,7 @@ public SIPEndPoint ToSIPEndPoint()
private void ParseParamsAndHeaders(string paramsAndHeaders)
{
- if (paramsAndHeaders != null && paramsAndHeaders.Trim().Length > 0)
+ if (!string.IsNullOrWhiteSpace(paramsAndHeaders))
{
int headerDelimPosn = paramsAndHeaders.IndexOf(HEADER_START_DELIMITER);
diff --git a/src/SIPSorcery/core/SIP/SIPUserField.cs b/src/SIPSorcery/core/SIP/SIPUserField.cs
index 6e606aa4d..1335c8596 100644
--- a/src/SIPSorcery/core/SIP/SIPUserField.cs
+++ b/src/SIPSorcery/core/SIP/SIPUserField.cs
@@ -103,7 +103,7 @@ public static SIPUserField ParseSIPUserField(string userFieldStr)
if (paramDelimPosn != -1)
{
- string paramStr = trimUserField.Substring(paramDelimPosn + 1).Trim();
+ var paramStr = trimUserField.AsSpan(paramDelimPosn + 1).Trim().ToString();
userField.Parameters = new SIPParameters(paramStr, PARAM_TAG_DELIMITER);
uriStr = trimUserField.Substring(0, paramDelimPosn);
}
@@ -114,7 +114,7 @@ public static SIPUserField ParseSIPUserField(string userFieldStr)
{
if (position > 0)
{
- userField.Name = trimUserField.Substring(0, position).Trim().Trim('"');
+ userField.Name = trimUserField.AsSpan(0, position).Trim().ToString().Trim('"');
trimUserField = trimUserField.Substring(position, trimUserField.Length - position);
}
@@ -124,7 +124,7 @@ public static SIPUserField ParseSIPUserField(string userFieldStr)
{
addrSpecLen = position - 1;
- string paramStr = trimUserField.Substring(position + 1).Trim();
+ var paramStr = trimUserField.AsSpan(position + 1).Trim().ToString();
userField.Parameters = new SIPParameters(paramStr, PARAM_TAG_DELIMITER);
string addrSpec = trimUserField.Substring(1, addrSpecLen);
@@ -133,7 +133,7 @@ public static SIPUserField ParseSIPUserField(string userFieldStr)
}
else
{
- throw new SIPValidationException(SIPValidationFieldsEnum.ContactHeader, "A SIPUserField was missing the right quote, " + userFieldStr + ".");
+ throw new SIPValidationException(SIPValidationFieldsEnum.ContactHeader, $"A SIPUserField was missing the right quote, {userFieldStr}.");
}
}
@@ -157,10 +157,10 @@ public override string ToString()
userFieldStr = Name + " ";
}*/
- userFieldStr = "\"" + Name + "\" ";
+ userFieldStr = $"\"{Name}\" ";
}
- userFieldStr += "<" + URI.ToString() + ">" + Parameters.ToString();
+ userFieldStr += $"<{URI.ToString()}>{Parameters.ToString()}";
return userFieldStr;
}
@@ -179,10 +179,10 @@ public string ToParameterlessString()
if (Name != null)
{
- userFieldStr = "\"" + Name + "\" ";
+ userFieldStr = $"\"{Name}\" ";
}
- userFieldStr += "<" + URI.ToParameterlessString() + ">";
+ userFieldStr += $"<{URI.ToParameterlessString()}>";
return userFieldStr;
}
diff --git a/src/SIPSorcery/sys/TypeExtensions.cs b/src/SIPSorcery/sys/TypeExtensions.cs
index 69d24596c..51935f203 100644
--- a/src/SIPSorcery/sys/TypeExtensions.cs
+++ b/src/SIPSorcery/sys/TypeExtensions.cs
@@ -206,12 +206,6 @@ public static byte[] ParseHexStr(string hexStr)
return buffer.ToArray();
}
- public static void Deconstruct(this KeyValuePair tuple, out T1 key, out T2 value)
- {
- key = tuple.Key;
- value = tuple.Value;
- }
-
public static bool IsPrivate(this IPAddress address)
{
return IPSocket.IsPrivateAddress(address.ToString());
diff --git a/test/integration/SIPSorcery.IntegrationTests.csproj b/test/integration/SIPSorcery.IntegrationTests.csproj
index 07159f7f1..f28b36958 100755
--- a/test/integration/SIPSorcery.IntegrationTests.csproj
+++ b/test/integration/SIPSorcery.IntegrationTests.csproj
@@ -20,10 +20,6 @@
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
diff --git a/test/unit/SIPSorcery.UnitTests.csproj b/test/unit/SIPSorcery.UnitTests.csproj
index 484c45b6e..07bed7bae 100755
--- a/test/unit/SIPSorcery.UnitTests.csproj
+++ b/test/unit/SIPSorcery.UnitTests.csproj
@@ -14,10 +14,6 @@
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
diff --git a/test/unit/core/SIP/SIPAuthorisationDigestUnitTest.cs b/test/unit/core/SIP/SIPAuthorisationDigestUnitTest.cs
index 39ebfcded..c60fc1261 100644
--- a/test/unit/core/SIP/SIPAuthorisationDigestUnitTest.cs
+++ b/test/unit/core/SIP/SIPAuthorisationDigestUnitTest.cs
@@ -433,7 +433,7 @@ public void SIPRequestAuthRoundTripWithSHA256DIgest()
authResult = SIPRequestAuthenticator.AuthenticateSIPRequest(SIPEndPoint.Empty, SIPEndPoint.Empty, authReq, account);
Assert.True(authResult.Authenticated);
- }
+ }
///
/// A base64 nonce that ends with '=' padding must be preserved verbatim. The header is split