Example #1
0
        public ForwardingConnection(TcpConnectionForwarder forwarder, TcpClient client, BigInteger conId, IPAddress addressForConnect, IPAddress addressForBind,
                                    Func <SemaphoreSlim, Task> waitForSending, Func <SemaphoreSlim, Task> waitForReceiving, SemaphoreSlim releaseConnectionSemaphore)
        {
            this.forwarder                  = forwarder;
            this.client                     = client;
            this.conId                      = conId;
            this.addressForConnect          = addressForConnect;
            this.addressForBind             = addressForBind;
            this.waitForSending             = waitForSending;
            this.waitForReceiving           = waitForReceiving;
            this.localRemoteIPEndpoint      = ((IPEndPoint)client.Client.RemoteEndPoint);
            this.localLocalIPEndpoint       = ((IPEndPoint)client.Client.LocalEndPoint);
            this.releaseConnectionSemaphore = releaseConnectionSemaphore;

            // Note: Setting client.SendTimeout has no effect in our case because it only applies to synchronous Write() calls.
            // To implement a send timeout, we implement something that will close the destination socket after a specific time
            // if the write call did not finish in that time, so that the Write() or Read() method of the stream will throw an exception.
            // Currently, this is implemented by the AsyncTimeoutHelper class which uses Semaphores in a separate Task to decide if the
            // socket should be closed.
        }
Example #2
0
        private void startButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                string remoteHost = textHost.Text;
                int    remotePort = int.Parse(textPortRemote.Text, CultureInfo.InvariantCulture);
                int    localPort  = int.Parse(textPortLocal.Text, CultureInfo.InvariantCulture);

                forwarder = new TcpConnectionForwarder(
                    new Random().Next(), remoteHost, remotePort, localPort, sslHost,
                    TcpConnectionForwarderUtils.sslProtocols, serverSslCertificate,
                    TcpConnectionForwarderUtils.sslProtocols, 10000 /* TODO: let the user specify this number */);
                UpdownValueChanged(false);
                UpdownValueChanged(true);
                forwarder.ConnectionAccepted += con =>
                {
                    ConnectionData data = null; // used by the GUI thread

                    // Add events to the connection
                    con.LocalConnectionAuthenticated += (protocol,
                                                         cipherAlgorithmType, cipherAlgorithmStrength,
                                                         hashAlgorithmType, hashAlgorithmStrength,
                                                         exchangeAlgorithmType, exchangeAlgorithmStrength)
                                                        => Dispatcher.Invoke(new Action(() => con_LocalConnectionAuthenticated(data, protocol,
                                                                                                                               cipherAlgorithmType, cipherAlgorithmStrength, hashAlgorithmType, hashAlgorithmStrength, exchangeAlgorithmType, exchangeAlgorithmStrength)));
                    con.RemoteConnectionEstablished += (usedIpv6, remoteLocalEndpoint, remoteRemoteEndpoint) =>
                                                       Dispatcher.Invoke(new Action(() => con_RemoteConnectionEstablished(data, usedIpv6, remoteLocalEndpoint, remoteRemoteEndpoint)));
                    con.RemoteConnectionAuthenticated += (protocol, remoteCertificate,
                                                          cipherAlgorithmType, cipherAlgorithmStrength,
                                                          hashAlgorithmType, hashAlgorithmStrength,
                                                          exchangeAlgorithmType, exchangeAlgorithmStrength)
                                                         => Dispatcher.Invoke(new Action(() => con_RemoteConnectionAuthenticated(data, protocol, remoteCertificate, cipherAlgorithmType, cipherAlgorithmStrength,
                                                                                                                                 hashAlgorithmType, hashAlgorithmStrength, exchangeAlgorithmType, exchangeAlgorithmStrength)));
                    con.LocalConnectionClosed      += () => Dispatcher.Invoke(new Action(() => con_LocalConnectionClosed(data)));
                    con.RemoteConnectionClosed     += () => Dispatcher.Invoke(new Action(() => con_RemoteConnectionClosed(data)));
                    con.ConnectionClosedCompletely += () => Dispatcher.Invoke(new Action(() => con_ConnectionClosedCompletely(data)));
                    con.ConnectionAborted          += (fromClient, ex) => Dispatcher.Invoke(new Action(() => con_ConnectionAborted(data, fromClient, ex)));
                    con.DataReceivedLocal          += (buf, offset, count) =>
                    {
                        byte[] copy = null;
                        if (logDataContents || logDataToFile)
                        {
                            // Need to copy the byte[] array because when the following Action is processed
                            // it may already be used for other data.
                            // TODO: Don't copy it since we use Invoke() which waits until the method in the GUI thread
                            // has completed.
                            copy = new byte[count];
                            Array.Copy(buf, offset, copy, 0, count);
                        }
                        Dispatcher.Invoke(new Action(() => con_DataReceivedLocal(data, copy, 0, count)));
                    };
                    con.DataReceivedRemote += (buf, offset, count) =>
                    {
                        byte[] copy = null;
                        if (logDataContents || logDataToFile)
                        {
                            // Need to copy the byte[] array because when the following Action is processed
                            // it may already be used for other data.
                            copy = new byte[count];
                            Array.Copy(buf, offset, copy, 0, count);
                        }
                        Dispatcher.Invoke(new Action(() => con_DataReceivedRemote(data, copy, 0, count)));
                    };
                    con.DataForwardedLocal  += () => Dispatcher.Invoke(new Action(() => con_DataForwardedLocal(data)));
                    con.DataForwardedRemote += () => Dispatcher.Invoke(new Action(() => con_DataForwardedRemote(data)));

                    Dispatcher.Invoke(new Action(() =>
                    {
                        data = new ConnectionData()
                        {
                            Connection = con, LocalLocalEndpoint = con.LocalLocalIPEndpoint, LocalRemoteEndpoint = con.LocalRemoteIPEndpoint
                        };

                        forwarder_ConnectionAccepted(data);
                    }));
                };

                forwarderTask = forwarder.RunAsync();

                if (forwarderTask.IsCompleted)
                {
                    // Task has already completed - this should mean there was some exception.
                    // Wait for the task to get the exception.
                    forwarderTask.Wait();
                }
                else
                {
                    // Wrap the task to handle unhandled exceptions.
                    forwarderTask = new Func <Task>(async() => await ExceptionUtils.WrapTaskForHandlingUnhandledExceptions(async() => await forwarderTask))();
                }

                // OK
                logDataToFile                   = checkLogToFile.IsChecked.Value;
                startButton.IsEnabled           = textHost.IsEnabled = textPortLocal.IsEnabled = textPortRemote.IsEnabled = false;
                checkPauseClient.IsEnabled      = checkPauseServer.IsEnabled = true;
                formsHost1.Child.Enabled        = formsHost2.Child.Enabled = true;
                checkLimitSpeedClient.IsEnabled = checkLimitSpeedServer.IsEnabled = true;
                checkUseSsl.IsEnabled           = false;
                checkUseServerSsl.IsEnabled     = false;
                checkLogToFile.IsEnabled        = false;
            }
            catch (Exception ex)
            {
                if (ExceptionUtils.ShouldExceptionBeRethrown(ex))
                {
                    throw;
                }

                forwarder     = null;
                forwarderTask = null;
                MessageBox.Show(ex.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }