Xamarin Public Jenkins (auto-signing) 64ac736ec5 Imported Upstream version 6.0.0.172
Former-commit-id: f3cc9b82f3e5bd8f0fd3ebc098f789556b44e9cd
2019-04-12 14:10:50 +00:00

404 lines
9.8 KiB
C#

//
// System.Net.ServicePoint
//
// Authors:
// Lawrence Pit (loz@cable.a2000.nl)
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
//
// (c) 2002 Lawrence Pit
// (c) 2003 Ximian, Inc. (http://www.ximian.com)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Collections;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
namespace System.Net
{
public class ServicePoint
{
readonly Uri uri;
DateTime lastDnsResolve;
Version protocolVersion;
IPHostEntry host;
bool usesProxy;
bool sendContinue = true;
bool useConnect;
object hostE = new object ();
bool useNagle;
BindIPEndPoint endPointCallback = null;
bool tcp_keepalive;
int tcp_keepalive_time;
int tcp_keepalive_interval;
bool disposed;
int connectionLeaseTimeout = -1;
int receiveBufferSize = -1;
// Constructors
internal ServicePoint (ServicePointManager.SPKey key, Uri uri, int connectionLimit, int maxIdleTime)
{
Key = key;
this.uri = uri;
this.connectionLimit = connectionLimit;
this.maxIdleTime = maxIdleTime;
Scheduler = new ServicePointScheduler (this, connectionLimit, maxIdleTime);
}
internal ServicePointManager.SPKey Key {
get;
}
ServicePointScheduler Scheduler {
get; set;
}
// Properties
public Uri Address {
get { return uri; }
}
public BindIPEndPoint BindIPEndPointDelegate {
get { return endPointCallback; }
set { endPointCallback = value; }
}
public int ConnectionLeaseTimeout {
get { return connectionLeaseTimeout; }
set
{
if (value < Timeout.Infinite)
throw new ArgumentOutOfRangeException (nameof (value));
connectionLeaseTimeout = value;
}
}
int connectionLimit;
int maxIdleTime;
public int ConnectionLimit {
get { return connectionLimit; }
set {
connectionLimit = value;
if (!disposed)
Scheduler.ConnectionLimit = value;
}
}
public string ConnectionName {
get { return uri.Scheme; }
}
public int CurrentConnections {
get {
return disposed ? 0 : Scheduler.CurrentConnections;
}
}
public DateTime IdleSince {
get {
if (disposed)
return DateTime.MinValue;
return Scheduler.IdleSince.ToLocalTime ();
}
}
public int MaxIdleTime {
get { return maxIdleTime; }
set {
maxIdleTime = value;
if (!disposed)
Scheduler.MaxIdleTime = value;
}
}
public virtual Version ProtocolVersion {
get { return protocolVersion; }
}
public int ReceiveBufferSize {
get { return receiveBufferSize; }
set
{
if (value < -1)
throw new ArgumentOutOfRangeException (nameof (value));
receiveBufferSize = value;
}
}
public bool SupportsPipelining {
get { return HttpVersion.Version11.Equals (protocolVersion); }
}
public bool Expect100Continue {
get { return SendContinue; }
set { SendContinue = value; }
}
public bool UseNagleAlgorithm {
get { return useNagle; }
set { useNagle = value; }
}
internal bool SendContinue {
get {
return sendContinue &&
(protocolVersion == null || protocolVersion == HttpVersion.Version11);
}
set { sendContinue = value; }
}
// Methods
public void SetTcpKeepAlive (bool enabled, int keepAliveTime, int keepAliveInterval)
{
if (enabled) {
if (keepAliveTime <= 0)
throw new ArgumentOutOfRangeException ("keepAliveTime", "Must be greater than 0");
if (keepAliveInterval <= 0)
throw new ArgumentOutOfRangeException ("keepAliveInterval", "Must be greater than 0");
}
tcp_keepalive = enabled;
tcp_keepalive_time = keepAliveTime;
tcp_keepalive_interval = keepAliveInterval;
}
internal void KeepAliveSetup (Socket socket)
{
if (!tcp_keepalive)
return;
byte[] bytes = new byte[12];
PutBytes (bytes, (uint)(tcp_keepalive ? 1 : 0), 0);
PutBytes (bytes, (uint)tcp_keepalive_time, 4);
PutBytes (bytes, (uint)tcp_keepalive_interval, 8);
socket.IOControl (IOControlCode.KeepAliveValues, bytes, null);
}
static void PutBytes (byte[] bytes, uint v, int offset)
{
if (BitConverter.IsLittleEndian) {
bytes[offset] = (byte)(v & 0x000000ff);
bytes[offset + 1] = (byte)((v & 0x0000ff00) >> 8);
bytes[offset + 2] = (byte)((v & 0x00ff0000) >> 16);
bytes[offset + 3] = (byte)((v & 0xff000000) >> 24);
} else {
bytes[offset + 3] = (byte)(v & 0x000000ff);
bytes[offset + 2] = (byte)((v & 0x0000ff00) >> 8);
bytes[offset + 1] = (byte)((v & 0x00ff0000) >> 16);
bytes[offset] = (byte)((v & 0xff000000) >> 24);
}
}
// Internal Methods
internal bool UsesProxy {
get { return usesProxy; }
set { usesProxy = value; }
}
internal bool UseConnect {
get { return useConnect; }
set { useConnect = value; }
}
private bool HasTimedOut {
get {
int timeout = ServicePointManager.DnsRefreshTimeout;
return timeout != Timeout.Infinite &&
(lastDnsResolve + TimeSpan.FromMilliseconds (timeout)) < DateTime.UtcNow;
}
}
internal IPHostEntry HostEntry {
get {
lock (hostE) {
string uriHost = uri.Host;
// Cannot do DNS resolution on literal IP addresses
if (uri.HostNameType == UriHostNameType.IPv6 || uri.HostNameType == UriHostNameType.IPv4) {
if (host != null)
return host;
if (uri.HostNameType == UriHostNameType.IPv6) {
// Remove square brackets
uriHost = uriHost.Substring (1, uriHost.Length - 2);
}
// Creates IPHostEntry
host = new IPHostEntry ();
host.AddressList = new IPAddress[] { IPAddress.Parse (uriHost) };
return host;
}
if (!HasTimedOut && host != null)
return host;
lastDnsResolve = DateTime.UtcNow;
try {
host = Dns.GetHostEntry (uriHost);
} catch {
return null;
}
}
return host;
}
}
internal void SetVersion (Version version)
{
protocolVersion = version;
}
internal void SendRequest (WebOperation operation, string groupName)
{
lock (this) {
if (disposed)
throw new ObjectDisposedException (typeof (ServicePoint).FullName);
Scheduler.SendRequest (operation, groupName);
}
}
public bool CloseConnectionGroup (string connectionGroupName)
{
lock (this) {
if (disposed)
return true;
return Scheduler.CloseConnectionGroup (connectionGroupName);
}
}
internal void FreeServicePoint ()
{
disposed = true;
Scheduler = null;
}
//
// Copied from the referencesource
//
object m_ServerCertificateOrBytes;
object m_ClientCertificateOrBytes;
/// <devdoc>
/// <para>
/// Gets the certificate received for this <see cref='System.Net.ServicePoint'/>.
/// </para>
/// </devdoc>
public X509Certificate Certificate {
get {
object chkCert = m_ServerCertificateOrBytes;
if (chkCert != null && chkCert.GetType() == typeof(byte[]))
return (X509Certificate)(m_ServerCertificateOrBytes = new X509Certificate((byte[]) chkCert));
else
return chkCert as X509Certificate;
}
}
internal void UpdateServerCertificate(X509Certificate certificate)
{
if (certificate != null)
m_ServerCertificateOrBytes = certificate.GetRawCertData();
else
m_ServerCertificateOrBytes = null;
}
/// <devdoc>
/// <para>
/// Gets the Client Certificate sent by us to the Server.
/// </para>
/// </devdoc>
public X509Certificate ClientCertificate {
get {
object chkCert = m_ClientCertificateOrBytes;
if (chkCert != null && chkCert.GetType() == typeof(byte[]))
return (X509Certificate)(m_ClientCertificateOrBytes = new X509Certificate((byte[]) chkCert));
else
return chkCert as X509Certificate;
}
}
internal void UpdateClientCertificate(X509Certificate certificate)
{
if (certificate != null)
m_ClientCertificateOrBytes = certificate.GetRawCertData();
else
m_ClientCertificateOrBytes = null;
}
internal bool CallEndPointDelegate (Socket sock, IPEndPoint remote)
{
if (endPointCallback == null)
return true;
int count = 0;
for (;;) {
IPEndPoint local = null;
try {
local = endPointCallback (this,
remote, count);
} catch {
// This is to differentiate from an
// OverflowException, which should propagate.
return false;
}
if (local == null)
return true;
try {
sock.Bind (local);
} catch (SocketException) {
// This is intentional; the docs say
// that if the Bind fails, we keep
// going until there is an
// OverflowException on the retry
// count.
checked { ++count; }
continue;
}
return true;
}
}
internal Socket GetConnection(PooledStream PooledStream, object owner, bool async, out IPAddress address, ref Socket abortSocket, ref Socket abortSocket6)
{
throw new NotImplementedException ();
}
}
}