Пример #1
0
        /// <summary>
        /// Used to initialize the file transfer sequence.
        /// <para>Sends a file request with the file id, name, and size.</para>
        /// </summary>
        /// 
        /// <param name="FilePath">The full path to the file to send</param>
        public void SendFile(string FilePath)
        {
            // store file length
            long len = new FileInfo(FilePath).Length;
            // increment file id
            _fileCounter++;
            // get an open port
            int port = _clientSocket.NextOpenPort();
            // create the file info header
            byte[] btInfo = new DtmFileInfo(Path.GetFileName(FilePath), len, port).ToBytes();

            // create a new symmetric key
            KeyParams fileKey = GenerateSymmetricKey(_srvIdentity.Session);
            MemoryStream keyStrm = (MemoryStream)KeyParams.Serialize(fileKey);
            // add the key
            btInfo = ArrayUtils.Concat(btInfo, keyStrm.ToArray());

            // wrap the request
            btInfo = WrapMessage(btInfo, _dtmParameters.MaxMessageAppend, _dtmParameters.MaxMessagePrePend);
            // encrypt with master
            btInfo = SymmetricTransform(_srvSymProcessor, btInfo);

            // initialize the files unique crypto processor
            ICipherMode fileSymProcessor = SymmetricInit(_srvIdentity.Session, fileKey);
            // tune for parallel processing
            int blockSize = ((int)MessageBufferSize - DtmPacket.GetHeaderSize()) - ((int)MessageBufferSize - DtmPacket.GetHeaderSize()) % ((CTR)fileSymProcessor).ParallelMinimumSize;
            ((CTR)fileSymProcessor).ParallelBlockSize = blockSize;

            // build the file transfer instance
            DtmFileTransfer fileTransfer = new DtmFileTransfer(fileSymProcessor, _fileCounter, 1024, (int)FileBufferSize);
            fileTransfer.FileTransferred += new DtmFileTransfer.FileTransferredDelegate(OnFileSent);
            fileTransfer.ProgressPercent += new DtmFileTransfer.ProgressDelegate(OnFileSentProgress);
            // add to dictionary
            _transQueue.TryAdd(_fileCounter, fileTransfer);

            // send header to the remote host in a file request
            Transmit(DtmPacketTypes.Transfer, (short)DtmTransferFlags.Request, _fileCounter, new MemoryStream(btInfo));

            // initiate with non-blocking listen
            fileTransfer.StartSend(_clientSocket.LocalAddress, port, FilePath);

            if (fileTransfer.IsConnected)
            {
                try
                {
                    // start on a new thread
                    Task socketTask = Task.Factory.StartNew(() =>
                    {
                        fileTransfer.SendFile();
                    });
                    socketTask.Wait(10);
                }
                catch (AggregateException ae)
                {
                    if (SessionError != null)
                        SessionError(this, new DtmErrorEventArgs(ae.GetBaseException(), DtmErrorSeverity.Warning));
                }
            }
            else
            {
                // remove from pending and dispose
                CloseTransfer(_fileCounter);

                // alert app
                DtmErrorEventArgs args = new DtmErrorEventArgs(new SocketException((int)SocketError.ConnectionAborted), DtmErrorSeverity.Connection);
                if (SessionError != null)
                    SessionError(this, args);

                if (args.Cancel == true)
                    Disconnect();
            }
        }
Пример #2
0
        /// <summary>
        /// Used Post-Exchange to setup a file transfer from the remote host
        /// </summary>
        /// 
        /// <param name="PacketStream">The stream containing the file transfer request</param>
        private void ReceiveFile(Stream PacketStream)
        {
            // asynchronous transfer by sending a file key and info, and running the entire transfer on another socket..
            if (!_isEstablished)
                throw new CryptoProcessingException("DtmKex:ReceiveFile", "The VPN has not been established!", new InvalidOperationException());
            if (FileRequest == null)
                throw new CryptoProcessingException("DtmKex:ReceiveFile", "The FileRequest and FileReceived must be connected to perform a file transfer, read the documentation!", new InvalidOperationException());
            if (FileReceived == null)
                throw new CryptoProcessingException("DtmKex:ReceiveFile", "The FileRequest and FileReceived must be connected to perform a file transfer, read the documentation!", new InvalidOperationException());

            // get the header
            DtmPacket pktHdr = new DtmPacket(PacketStream);
            // read the packet
            byte[] enc = new byte[pktHdr.PayloadLength];
            // get the encrypted data
            PacketStream.Read(enc, 0, enc.Length);
            // decrypt it using client crypto processor
            byte[] dec = SymmetricTransform(_cltSymProcessor, enc);
            // remove padding
            dec = UnwrapMessage(dec);
            MemoryStream pktStm = new MemoryStream(dec);

            // get file info header
            DtmFileInfo pktFi = new DtmFileInfo(pktStm);
            // get the key
            KeyParams fileKey = KeyParams.DeSerialize(pktStm);

            // forward request to app
            DtmFileRequestEventArgs args = new DtmFileRequestEventArgs(pktFi.FileName);
            FileRequest(this, args);

            // accept file or refuse and exit; app must send back a valid path or cancel; if cancel, send a refuse notice which will signal the end of the transfer, otherwise store file path and port
            if (args.Cancel || string.IsNullOrEmpty(args.FilePath) || args.FilePath.Equals(pktFi.FileName) || !Directory.Exists(Path.GetDirectoryName(args.FilePath)))
            {
                // send refuse and exit
                Transmit(DtmPacketTypes.Transfer, (short)DtmTransferFlags.Refused, pktHdr.OptionFlag);
            }
            else
            {
                // create the files crypto processor
                ICipherMode fileSymProcessor = SymmetricInit(_cltIdentity.Session, fileKey);
                // enable parallel decryption
                int blockSize = ((int)MessageBufferSize - DtmPacket.GetHeaderSize()) - ((int)MessageBufferSize - DtmPacket.GetHeaderSize()) % ((CTR)fileSymProcessor).ParallelMinimumSize;
                ((CTR)fileSymProcessor).ParallelBlockSize = blockSize;

                // init the file transfer host
                DtmFileTransfer fileTransfer = new DtmFileTransfer(fileSymProcessor, pktHdr.OptionFlag, 1024, (int)FileBufferSize);
                fileTransfer.FileTransferred += new DtmFileTransfer.FileTransferredDelegate(OnFileReceived);
                fileTransfer.ProgressPercent += new DtmFileTransfer.ProgressDelegate(OnFileReceivedProgress);
                // add to dictionary
                _transQueue.TryAdd(pktHdr.OptionFlag, fileTransfer);

                try
                {
                    // start the transfer on a new thread
                    Task socketTask = Task.Factory.StartNew(() =>
                    {
                        fileTransfer.StartReceive(_clientSocket.RemoteAddress, (int)pktFi.OptionsFlag, args.FilePath);
                    });
                    socketTask.Wait(10);
                }
                catch (AggregateException ae)
                {
                    if (SessionError != null)
                        SessionError(this, new DtmErrorEventArgs(ae.GetBaseException(), DtmErrorSeverity.Warning));
                }
            }
        }