123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743 |
- using System;
- using System.IO;
- using System.Net.Sockets;
- using System.Net.Security;
- using System.Security.Authentication;
- using System.Security.Cryptography.X509Certificates;
- using System.Threading;
- using System.Collections.Generic;
- using System.Diagnostics;
- namespace System.Net.FtpClient {
-
-
-
-
-
-
- public delegate void FtpSocketStreamSslValidation(FtpSocketStream stream, FtpSslValidationEventArgs e);
-
-
-
- public class FtpSslValidationEventArgs : EventArgs {
- X509Certificate m_certificate = null;
-
-
-
- public X509Certificate Certificate {
- get {
- return m_certificate;
- }
- set {
- m_certificate = value;
- }
- }
- X509Chain m_chain = null;
-
-
-
- public X509Chain Chain {
- get {
- return m_chain;
- }
- set {
- m_chain = value;
- }
- }
- SslPolicyErrors m_policyErrors = SslPolicyErrors.None;
-
-
-
- public SslPolicyErrors PolicyErrors {
- get {
- return m_policyErrors;
- }
- set {
- m_policyErrors = value;
- }
- }
- bool m_accept = false;
-
-
-
-
-
- public bool Accept {
- get {
- return m_accept;
- }
- set {
- m_accept = value;
- }
- }
- }
-
-
-
- public class FtpSocketStream : Stream, IDisposable {
-
-
-
-
-
-
-
-
-
- private DateTime m_lastActivity = DateTime.Now;
- private Socket m_socket = null;
-
-
-
- protected Socket Socket {
- get {
- return m_socket;
- }
- private set {
- m_socket = value;
- }
- }
- int m_socketPollInterval = 15000;
-
-
-
-
-
-
-
-
-
- public int SocketPollInterval {
- get { return m_socketPollInterval; }
- set { m_socketPollInterval = value; }
- }
-
-
-
-
-
-
- internal int SocketDataAvailable {
- get {
- if (m_socket != null)
- return m_socket.Available;
- return 0;
- }
- }
-
-
-
- public bool IsConnected {
- get {
- try {
- if (m_socket == null)
- return false;
- if (!m_socket.Connected) {
- Close();
- return false;
- }
- if (!CanRead || !CanWrite) {
- Close();
- return false;
- }
- if (m_socketPollInterval > 0 && DateTime.Now.Subtract(m_lastActivity).TotalMilliseconds > m_socketPollInterval) {
- FtpTrace.WriteLine("Testing connectivity using Socket.Poll()...");
- if (m_socket.Poll(500000, SelectMode.SelectRead) && m_socket.Available == 0) {
- Close();
- return false;
- }
- }
- }
- catch (SocketException sockex) {
- Close();
- FtpTrace.WriteLine("FtpSocketStream.IsConnected: Caught and discarded SocketException while testing for connectivity: {0}", sockex.ToString());
- return false;
- }
- catch (IOException ioex) {
- Close();
- FtpTrace.WriteLine("FtpSocketStream.IsConnected: Caught and discarded IOException while testing for connectivity: {0}", ioex.ToString());
- return false;
- }
- return true;
- }
- }
-
-
-
- public bool IsEncrypted {
- get {
- return m_sslStream != null;
- }
- }
- NetworkStream m_netStream = null;
-
-
-
- private NetworkStream NetworkStream {
- get {
- return m_netStream;
- }
- set {
- m_netStream = value;
- }
- }
- SslStream m_sslStream = null;
-
-
-
- private SslStream SslStream {
- get {
- return m_sslStream;
- }
- set {
- m_sslStream = value;
- }
- }
-
-
-
- protected Stream BaseStream {
- get {
- if (m_sslStream != null)
- return m_sslStream;
- else if (m_netStream != null)
- return m_netStream;
- return null;
- }
- }
-
-
-
- public override bool CanRead {
- get {
- if (m_netStream != null)
- return m_netStream.CanRead;
- return false;
- }
- }
-
-
-
- public override bool CanSeek {
- get {
- return false;
- }
- }
-
-
-
- public override bool CanWrite {
- get {
- if (m_netStream != null)
- return m_netStream.CanWrite;
- return false;
- }
- }
-
-
-
- public override long Length {
- get {
- return 0;
- }
- }
-
-
-
-
- public override long Position {
- get {
- if (BaseStream != null)
- return BaseStream.Position;
- return 0;
- }
- set {
- throw new InvalidOperationException();
- }
- }
- event FtpSocketStreamSslValidation m_sslvalidate = null;
-
-
-
- public event FtpSocketStreamSslValidation ValidateCertificate {
- add {
- m_sslvalidate += value;
- }
- remove {
- m_sslvalidate -= value;
- }
- }
- int m_readTimeout = Timeout.Infinite;
-
-
-
-
- public override int ReadTimeout {
- get {
- return m_readTimeout;
- }
- set {
- m_readTimeout = value;
- }
- }
- int m_connectTimeout = 30000;
-
-
-
-
-
- public int ConnectTimeout {
- get {
- return m_connectTimeout;
- }
- set {
- m_connectTimeout = value;
- }
- }
-
-
-
- public IPEndPoint LocalEndPoint {
- get {
- if (m_socket == null)
- return null;
- return (IPEndPoint)m_socket.LocalEndPoint;
- }
- }
-
-
-
- public IPEndPoint RemoteEndPoint {
- get {
- if (m_socket == null)
- return null;
- return (IPEndPoint)m_socket.RemoteEndPoint;
- }
- }
-
-
-
-
-
-
-
- protected bool OnValidateCertificate(X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) {
- FtpSocketStreamSslValidation evt = m_sslvalidate;
- if (evt != null) {
- FtpSslValidationEventArgs e = new FtpSslValidationEventArgs() {
- Certificate = certificate,
- Chain = chain,
- PolicyErrors = errors,
- Accept = (errors == SslPolicyErrors.None)
- };
- evt(this, e);
- return e.Accept;
- }
-
-
- return (errors == SslPolicyErrors.None);
- }
-
-
-
-
-
-
- public override long Seek(long offset, SeekOrigin origin) {
- throw new InvalidOperationException();
- }
-
-
-
-
- public override void SetLength(long value) {
- throw new InvalidOperationException();
- }
-
-
-
- public override void Flush() {
- if (!IsConnected)
- throw new InvalidOperationException("The FtpSocketStream object is not connected.");
- if (BaseStream == null)
- throw new InvalidOperationException("The base stream of the FtpSocketStream object is null.");
- BaseStream.Flush();
- }
-
-
-
-
-
- internal int RawSocketRead(byte[] buffer) {
- int read = 0;
- if (m_socket != null && m_socket.Connected) {
- read = m_socket.Receive(buffer, buffer.Length, 0);
- }
- return read;
- }
-
-
-
-
-
-
-
- public override int Read(byte[] buffer, int offset, int count) {
- IAsyncResult ar = null;
- if (BaseStream == null)
- return 0;
- m_lastActivity = DateTime.Now;
- ar = BaseStream.BeginRead(buffer, offset, count, null, null);
- if (!ar.AsyncWaitHandle.WaitOne(m_readTimeout, true)) {
- Close();
- throw new TimeoutException("Timed out trying to read data from the socket stream!");
- }
- return BaseStream.EndRead(ar);
- }
-
-
-
-
- public string ReadLine(System.Text.Encoding encoding) {
- List<byte> data = new List<byte>();
- byte[] buf = new byte[1];
- string line = null;
- while (Read(buf, 0, buf.Length) > 0) {
- data.Add(buf[0]);
- if ((char)buf[0] == '\n') {
- line = encoding.GetString(data.ToArray()).Trim('\r', '\n');
- break;
- }
- }
- return line;
- }
-
-
-
-
-
-
- public override void Write(byte[] buffer, int offset, int count) {
- if (BaseStream == null)
- return;
- BaseStream.Write(buffer, offset, count);
- m_lastActivity = DateTime.Now;
- }
-
-
-
-
-
- public void WriteLine(System.Text.Encoding encoding, string buf) {
- byte[] data;
- data = encoding.GetBytes(string.Format("{0}\r\n", buf));
- Write(data, 0, data.Length);
- }
-
-
-
- public new void Dispose() {
- FtpTrace.WriteLine("Disposing FtpSocketStream...");
- Close();
- }
-
-
-
- public override void Close() {
- if (m_socket != null) {
- try {
- if (m_socket.Connected) {
-
-
-
-
- m_socket.Close();
- }
- #if !NET2
- m_socket.Dispose();
- #endif
- }
- catch (SocketException ex) {
- FtpTrace.WriteLine("Caught and discarded a SocketException while cleaning up the Socket: {0}", ex.ToString());
- }
- finally {
- m_socket = null;
- }
- }
- if (m_netStream != null) {
- try {
- m_netStream.Dispose();
- }
- catch (IOException ex) {
- FtpTrace.WriteLine("Caught and discarded an IOException while cleaning up the NetworkStream: {0}", ex.ToString());
- }
- finally {
- m_netStream = null;
- }
- }
- if (m_sslStream != null) {
- try {
- m_sslStream.Dispose();
- }
- catch (IOException ex) {
- FtpTrace.WriteLine("Caught and discarded an IOException while cleaning up the SslStream: {0}", ex.ToString());
- }
- finally {
- m_sslStream = null;
- }
- }
- }
-
-
-
-
-
-
- public void SetSocketOption(SocketOptionLevel level, SocketOptionName name, bool value) {
- if (m_socket == null)
- throw new InvalidOperationException("The underlying socket is null. Have you established a connection?");
- m_socket.SetSocketOption(level, name, value);
- }
-
-
-
-
-
-
- public void Connect(string host, int port, FtpIpVersion ipVersions) {
- IAsyncResult ar = null;
- IPAddress[] addresses = Dns.GetHostAddresses(host);
- if (ipVersions == 0)
- throw new ArgumentException("The ipVersions parameter must contain at least 1 flag.");
- for (int i = 0; i < addresses.Length; i++) {
- #if DEBUG
- FtpTrace.WriteLine("{0}: {1}", addresses[i].AddressFamily.ToString(), addresses[i].ToString());
- #endif
-
-
-
- if (ipVersions != FtpIpVersion.ANY) {
- switch (addresses[i].AddressFamily) {
- case AddressFamily.InterNetwork:
- if ((ipVersions & FtpIpVersion.IPv4) != FtpIpVersion.IPv4) {
- #if DEBUG
- FtpTrace.WriteLine("SKIPPED!");
- #endif
- continue;
- }
- break;
- case AddressFamily.InterNetworkV6:
- if ((ipVersions & FtpIpVersion.IPv6) != FtpIpVersion.IPv6) {
- #if DEBUG
- FtpTrace.WriteLine("SKIPPED!");
- #endif
- continue;
- }
- break;
- }
- }
- m_socket = new Socket(addresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);
- ar = m_socket.BeginConnect(addresses[i], port, null, null);
- if (!ar.AsyncWaitHandle.WaitOne(m_connectTimeout, true)) {
- Close();
-
-
- if (i + 1 == addresses.Length)
- throw new TimeoutException("Timed out trying to connect!");
- }
- else {
- m_socket.EndConnect(ar);
-
-
- break;
- }
- }
-
-
- if (m_socket == null || !m_socket.Connected) {
- Close();
- throw new IOException("Failed to connect to host.");
- }
- m_netStream = new NetworkStream(m_socket);
- m_lastActivity = DateTime.Now;
- }
-
-
-
-
-
-
- public void ActivateEncryption(string targethost) {
- ActivateEncryption(targethost, null, SslProtocols.Default);
- }
-
-
-
-
-
-
-
- public void ActivateEncryption(string targethost, X509CertificateCollection clientCerts) {
- ActivateEncryption(targethost, clientCerts, SslProtocols.Default);
- }
-
-
-
-
-
-
-
-
- public void ActivateEncryption(string targethost, X509CertificateCollection clientCerts, SslProtocols sslProtocols) {
- if (!IsConnected)
- throw new InvalidOperationException("The FtpSocketStream object is not connected.");
- if (m_netStream == null)
- throw new InvalidOperationException("The base network stream is null.");
- if (m_sslStream != null)
- throw new InvalidOperationException("SSL Encryption has already been enabled on this stream.");
- try {
- DateTime auth_start;
- TimeSpan auth_time_total;
- m_sslStream = new SslStream(NetworkStream, true, new RemoteCertificateValidationCallback(
- delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
- return OnValidateCertificate(certificate, chain, sslPolicyErrors);
- }));
- auth_start = DateTime.Now;
- m_sslStream.AuthenticateAsClient(targethost, clientCerts, sslProtocols, true);
- auth_time_total = DateTime.Now.Subtract(auth_start);
- FtpTrace.WriteLine("Time to activate encryption: {0}h {1}m {2}s, Total Seconds: {3}.",
- auth_time_total.Hours,
- auth_time_total.Minutes,
- auth_time_total.Seconds,
- auth_time_total.TotalSeconds);
- }
- catch (AuthenticationException ex) {
-
-
-
-
- Close();
- throw ex;
- }
- }
-
-
-
-
-
- public void Listen(IPAddress address, int port) {
- if (!IsConnected) {
- if (m_socket == null)
- m_socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
- m_socket.Bind(new IPEndPoint(address, port));
- m_socket.Listen(1);
- }
- }
-
-
-
- public void Accept() {
- if (m_socket != null)
- m_socket = m_socket.Accept();
- }
-
-
-
-
-
-
- public IAsyncResult BeginAccept(AsyncCallback callback, object state) {
- if (m_socket != null)
- return m_socket.BeginAccept(callback, state);
- return null;
- }
-
-
-
-
- public void EndAccept(IAsyncResult ar) {
- if (m_socket != null) {
- m_socket = m_socket.EndAccept(ar);
- m_netStream = new NetworkStream(m_socket);
- }
- }
- }
- }
|