Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/SIPSorcery/SIPSorcery.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" />
<PackageReference Include="DnsClient" Version="1.8.0" />
<PackageReference Include="Makaretu.Dns.Multicast" Version="0.27.0" />
<PackageReference Include="Polyfill" Version="10.7.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SIPSorcery.WebSocketSharp" Version="0.0.1" />
<PackageReference Include="System.Net.WebSockets.Client" Version="4.3.2" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.203" PrivateAssets="All" />
Expand All @@ -35,13 +39,17 @@
<PackageReference Include="Microsoft.Bcl.HashCode" Version="6.0.0" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\SIPSorceryMedia.Abstractions\SIPSorceryMedia.Abstractions.csproj" />
</ItemGroup>

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;netcoreapp3.1;net462;net5.0;net6.0;net8.0;net9.0;net10.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<LangVersion>14.0</LangVersion>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<NoWarn>$(NoWarn);SYSLIB0050</NoWarn>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
Expand All @@ -66,11 +74,12 @@
<RepositoryUrl>https://github.com/sipsorcery-org/sipsorcery</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<RepositoryBranch>master</RepositoryBranch>
<PolyArgumentExceptions>true</PolyArgumentExceptions>
<PackageTags>SIP WebRTC VoIP RTP SDP STUN ICE SIPSorcery</PackageTags>
<PackageReleaseNotes>-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.
Expand All @@ -94,7 +103,7 @@
-v8.0.0: RTP header extension improvements (thanks to @ChristopheI). Major version to 8 to reflect highest .net runtime supported.</PackageReleaseNotes>
<NeutralLanguage>en</NeutralLanguage>
<Version>10.0.8</Version>
<AssemblyVersion>10.0.8</AssemblyVersion>
<AssemblyVersion>10.0.8</AssemblyVersion>
<FileVersion>10.0.8</FileVersion>
</PropertyGroup>

Expand Down
3 changes: 1 addition & 2 deletions src/SIPSorcery/app/Media/Sources/AudioExtrasSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
4 changes: 2 additions & 2 deletions src/SIPSorcery/app/SIPPacketMangler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 (?<ipaddress>([:a-fA-F0-9]+))", "c=IN IP6" + publicIPAddress, RegexOptions.Singleline);
string mangledSDP = Regex.Replace(sdpBody, @"c=IN IP6 (?<ipaddress>([:a-fA-F0-9]+))", $"c=IN IP6{publicIPAddress}", RegexOptions.Singleline);
wasMangled = true;

return mangledSDP;
Expand All @@ -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 (?<ipaddress>(\d+\.){3}\d+)", "c=IN IP4 " + publicIPAddress, RegexOptions.Singleline);
string mangledSDP = Regex.Replace(sdpBody, @"c=IN IP4 (?<ipaddress>(\d+\.){3}\d+)", $"c=IN IP4 {publicIPAddress}", RegexOptions.Singleline);
wasMangled = true;

return mangledSDP;
Expand Down
35 changes: 21 additions & 14 deletions src/SIPSorcery/app/SIPUserAgents/SIPCallDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 + @"=(?<delaytime>\d+)");
Match delayCallMatch = Regex.Match(options, $@"{DELAY_CALL_OPTION_KEY}=(?<delaytime>\d+)");
if (delayCallMatch.Success)
{
int.TryParse(delayCallMatch.Result("${delaytime}"), out DelaySeconds);
}

// Parse redirect mode option.
Match redirectModeMatch = Regex.Match(options, REDIRECT_MODE_OPTION_KEY + @"=(?<redirectmode>\w)");
Match redirectModeMatch = Regex.Match(options, $@"{REDIRECT_MODE_OPTION_KEY}=(?<redirectmode>\w)");
if (redirectModeMatch.Success)
{
string redirectMode = redirectModeMatch.Result("${redirectmode}");
Expand All @@ -321,42 +321,42 @@ public void ParseCallOptions(string options)
}

// Parse call duration limit option.
Match callDurationMatch = Regex.Match(options, CALL_DURATION_OPTION_KEY + @"=(?<callduration>\d+)");
Match callDurationMatch = Regex.Match(options, $@"{CALL_DURATION_OPTION_KEY}=(?<callduration>\d+)");
if (callDurationMatch.Success)
{
int.TryParse(callDurationMatch.Result("${callduration}"), out CallDurationLimit);
}

// Parse the mangle option.
Match mangleMatch = Regex.Match(options, MANGLE_MODE_OPTION_KEY + @"=(?<mangle>\w+)");
Match mangleMatch = Regex.Match(options, $@"{MANGLE_MODE_OPTION_KEY}=(?<mangle>\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 + @"=(?<displayname>.+?)(,|$)");
Match fromDisplayNameMatch = Regex.Match(options, $@"{FROM_DISPLAY_NAME_KEY}=(?<displayname>.+?)(,|$)");
if (fromDisplayNameMatch.Success)
{
FromDisplayName = fromDisplayNameMatch.Result("${displayname}").Trim();
}

// Parse the From header URI username option.
Match fromUsernameNameMatch = Regex.Match(options, FROM_USERNAME_KEY + @"=(?<username>.+?)(,|$)");
Match fromUsernameNameMatch = Regex.Match(options, $@"{FROM_USERNAME_KEY}=(?<username>.+?)(,|$)");
if (fromUsernameNameMatch.Success)
{
FromURIUsername = fromUsernameNameMatch.Result("${username}").Trim();
}

// Parse the From header URI host option.
Match fromURIHostMatch = Regex.Match(options, FROM_HOST_KEY + @"=(?<host>.+?)(,|$)");
Match fromURIHostMatch = Regex.Match(options, $@"{FROM_HOST_KEY}=(?<host>.+?)(,|$)");
if (fromURIHostMatch.Success)
{
FromURIHost = fromURIHostMatch.Result("${host}").Trim();
}

// Parse the Transfer behaviour option.
Match transferMatch = Regex.Match(options, TRANSFER_MODE_OPTION_KEY + @"=(?<transfermode>.+?)(,|$)");
Match transferMatch = Regex.Match(options, $@"{TRANSFER_MODE_OPTION_KEY}=(?<transfermode>.+?)(,|$)");
if (transferMatch.Success)
{
string transferMode = transferMatch.Result("${transfermode}");
Expand Down Expand Up @@ -387,28 +387,28 @@ public void ParseCallOptions(string options)
}

// Parse the request caller details option.
Match callerDetailsMatch = Regex.Match(options, REQUEST_CALLER_DETAILS + @"=(?<callerdetails>\w+)");
Match callerDetailsMatch = Regex.Match(options, $@"{REQUEST_CALLER_DETAILS}=(?<callerdetails>\w+)");
if (callerDetailsMatch.Success)
{
bool.TryParse(callerDetailsMatch.Result("${callerdetails}"), out RequestCallerDetails);
}

// Parse the accountcode.
Match accountCodeMatch = Regex.Match(options, ACCOUNT_CODE_KEY + @"=(?<accountCode>\w+)");
Match accountCodeMatch = Regex.Match(options, $@"{ACCOUNT_CODE_KEY}=(?<accountCode>\w+)");
if (accountCodeMatch.Success)
{
AccountCode = accountCodeMatch.Result("${accountCode}");
}

// Parse the rate code.
Match rateCodeMatch = Regex.Match(options, RATE_CODE_KEY + @"=(?<rateCode>\w+)");
Match rateCodeMatch = Regex.Match(options, $@"{RATE_CODE_KEY}=(?<rateCode>\w+)");
if (rateCodeMatch.Success)
{
RateCode = rateCodeMatch.Result("${rateCode}");
}

// Parse the delayed reinvite option.
Match delayedReinviteMatch = Regex.Match(options, DELAYED_REINVITE_KEY + @"=(?<delayedReinvite>\d+)");
Match delayedReinviteMatch = Regex.Match(options, $@"{DELAYED_REINVITE_KEY}=(?<delayedReinvite>\d+)");
if (delayedReinviteMatch.Success)
{
int.TryParse(delayedReinviteMatch.Result("${delayedReinvite}"), out ReinviteDelay);
Expand Down Expand Up @@ -457,7 +457,14 @@ public static List<string> 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;
Expand Down
25 changes: 15 additions & 10 deletions src/SIPSorcery/app/SIPUserAgents/SIPClientUserAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -427,7 +427,7 @@ private Task<SocketError> 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);

Expand Down Expand Up @@ -529,7 +529,7 @@ private Task<SocketError> 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);

Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
Loading
Loading