/// <summary> /// Creates a serialized request packet (DtmPacket) /// </summary> private MemoryStream CreateRequest(DtmPacketFlags Message, short State) { MemoryStream ret = new DtmPacketStruct(Message, 0, 0, State).ToStream(); ret.Seek(0, SeekOrigin.Begin); return(ret); }
private void Resend(DtmPacketStruct PacketHeader) { if (_sndBuffer.Exists(PacketHeader.Sequence)) { MemoryStream pktStm = _sndBuffer.Peek(PacketHeader.Sequence); if (pktStm != null) { if (pktStm.Length > 0) { pktStm.WriteTo(_clientSocket.TcpStream); } } } }
private void Transmit(DtmPacketFlags PacketType, short PacketFlag, long OptionFlag = 0, MemoryStream Payload = null) { lock (_sndLock) { long pldLen = Payload == null ? 0 : Payload.Length; // create a new packet: packet flag, payload size, sequence, and state flag MemoryStream pktStm = new DtmPacketStruct(PacketType, pldLen, _sndSequence, PacketFlag, OptionFlag).ToStream(); // add payload if (Payload != null) { // copy to output pktStm.Seek(0, SeekOrigin.End); Payload.WriteTo(pktStm); pktStm.Seek(0, SeekOrigin.Begin); } // store in the file packet buffer _sndBuffer.Push(_sndSequence, pktStm); // increment file send counter _sndSequence++; // transmit to remote client if (_clientSocket.IsConnected) { try { _clientSocket.SendAsync(pktStm); } catch (CryptoSocketException ce) { SocketException se = ce.InnerException as SocketException; if (se.SocketErrorCode == SocketError.WouldBlock || se.SocketErrorCode == SocketError.IOPending || se.SocketErrorCode == SocketError.NoBufferSpaceAvailable) { // buffer is full, throttle down Throttle(pktStm); } else { // possible connection dropped, alert app if (SessionError != null) { DtmErrorArgs args = new DtmErrorArgs(ce, DtmErrorSeverityFlags.Connection); SessionError(this, args); } } } catch (Exception ex) { // possible connection dropped, alert app if (SessionError != null) { DtmErrorArgs args = new DtmErrorArgs(ex, DtmErrorSeverityFlags.Connection); SessionError(this, args); } } // notify app if (PacketSent != null) { PacketSent(this, new DtmPacketArgs((short)DtmTransferFlags.DataChunk, pldLen)); } } } }
private void ProcessAndPush(PacketBuffer Buffer, MemoryStream PacketStream) { int hdrLen = DtmPacketStruct.GetHeaderSize(); int pktLen = 0; // get the header DtmPacketStruct pktHdr = new DtmPacketStruct(PacketStream); PacketStream.Seek(0, SeekOrigin.Begin); // track high sequence number if (pktHdr.Sequence > _seqCounter) { _seqCounter = pktHdr.Sequence; } // out of sync, possible packet loss if (_seqCounter - _rcvSequence > _bufferCount / 4) { // request a retransmission Transmit(DtmPacketFlags.Service, (short)DtmServiceFlags.Resend, _rcvSequence + 1); } // packet aligned if (pktHdr.PayloadLength + hdrLen == PacketStream.Length) { // resend was already processed if (pktHdr.Sequence < _rcvSequence) { return; } // push onto buffer Buffer.Push(pktHdr.Sequence, PacketStream); } // more than one packet else if (pktHdr.PayloadLength + hdrLen < PacketStream.Length) { byte[] buffer; long pos = 0; do { // get packet position and size pos = PacketStream.Position; if (PacketStream.Length - pos < DtmPacketStruct.GetHeaderSize()) { // next packet corrupted, request a retransmission and exit Transmit(DtmPacketFlags.Service, (short)DtmServiceFlags.Resend, Buffer.GetHighKey() + 1); return; } pktHdr = new DtmPacketStruct(PacketStream); pktLen = (int)(hdrLen + pktHdr.PayloadLength); if (pktLen > MAXRCVBUFFER || pktLen < 0 || PacketStream.Length - pos < pktLen) { // packet corrupted, request a retransmission and exit Transmit(DtmPacketFlags.Service, (short)DtmServiceFlags.Resend, Buffer.GetHighKey() + 1); return; } else { // create the buffer buffer = new byte[pktLen]; PacketStream.Seek(pos, SeekOrigin.Begin); PacketStream.Read(buffer, 0, (int)pktLen); // push onto buffer Buffer.Push(pktHdr.Sequence, new MemoryStream(buffer)); } } while (PacketStream.Position < PacketStream.Length); } // malformed packet, send retransmit request else if (pktHdr.PayloadLength > MAXRCVBUFFER || pktHdr.PayloadLength < 0 || pktHdr.PayloadLength + hdrLen > PacketStream.Length) { // packet corrupted, request a retransmission of last in queue + 1 Transmit(DtmPacketFlags.Service, (short)DtmServiceFlags.Resend, Buffer.GetHighKey() + 1); } }
private void Process(MemoryStream PacketStream) { // increment rcv sequence _rcvSequence++; // get the header DtmPacketStruct pktHdr = new DtmPacketStruct(PacketStream); PacketStream.Seek(0, SeekOrigin.Begin); switch (pktHdr.PacketType) { // file transfer case DtmPacketFlags.Transfer: { switch ((DtmTransferFlags)pktHdr.PacketFlag) { case DtmTransferFlags.DataChunk: { try { lock (_rcvLock) { // received file data Receive(PacketStream); } } catch (Exception) { // packet corrupted, request a retransmission and exit Transmit(DtmPacketFlags.Service, (short)DtmServiceFlags.Resend, pktHdr.Sequence); return; } // echo the packet to remove it from remote buffer Transmit(DtmPacketFlags.Service, (short)DtmServiceFlags.Echo, pktHdr.Sequence); break; } } break; } // service messages case DtmPacketFlags.Service: { switch ((DtmServiceFlags)pktHdr.PacketFlag) { case DtmServiceFlags.Resend: { // resend the packet Resend(pktHdr); break; } case DtmServiceFlags.Echo: { // remove from local buffer if (_sndBuffer.Exists(pktHdr.OptionFlag)) { _sndBuffer.Destroy(pktHdr.OptionFlag); } break; } } break; } default: { throw new CryptoKeyExchangeException("DtmFileTransfer:Process", "The packet type is unknown!", new InvalidDataException()); } } // notify parent if (PacketReceived != null) { PacketReceived(this, new DtmPacketArgs(pktHdr.PacketFlag, pktHdr.PayloadLength)); } }
public void SendFile() { int bytesRead = 0; long len = new FileInfo(_filePath).Length; DtmFileInfoSruct flHdr = new DtmFileInfoSruct(_filePath, len, 0); int ckSize = _clientSocket.SendBufferSize - (flHdr.GetHeaderSize() + DtmPacketStruct.GetHeaderSize()); byte[] inputBuffer = new byte[ckSize]; try { using (FileStream inStream = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { // loop through file while ((bytesRead = inStream.Read(inputBuffer, 0, ckSize)) > 0) { // wrap in a file info; option flag is used for payload length flHdr.OptionsFlag = bytesRead; byte[] hdrArr = flHdr.ToBytes(); // add data if (bytesRead == ckSize) { hdrArr = ArrayUtils.Concat(hdrArr, inputBuffer); } else { hdrArr = ArrayUtils.Concat(hdrArr, ArrayUtils.GetRange(inputBuffer, 0, bytesRead)); } // encrypt the header and data byte[] enc = SymmetricTransform(_fileSymProcessor, hdrArr); // send to the remote host Transmit(DtmPacketFlags.Transfer, (short)DtmTransferFlags.DataChunk, _fileId, new MemoryStream(enc)); // increment counter _bytesSent += bytesRead; // progress if (ProgressPercent != null) { double progress = 100.0 * (double)_bytesSent / inStream.Length; ProgressPercent(this, new System.ComponentModel.ProgressChangedEventArgs((int)progress, (object)inStream.Length)); } } } // notify app if (FileTransferred != null) { FileTransferred(this, new DtmPacketArgs((short)DtmTransferFlags.Sent, _fileId)); } } catch (Exception ex) { throw new CryptoFileTransferException("DtmFileTransfer:SendFile", "The file transfer did not complete!", ex); } finally { // flush SendFlush(); } }
private void Receive(Stream PacketStream) { // get the packet header DtmPacketStruct prcPacket = new DtmPacketStruct(PacketStream); // read the packet byte[] enc = new byte[prcPacket.PayloadLength]; // get the encrypted data PacketStream.Read(enc, 0, enc.Length); // decrypt it using file crypto processor byte[] dec = SymmetricTransform(_fileSymProcessor, enc); // get file info header DtmFileInfoSruct pktFi = new DtmFileInfoSruct(dec); // store file name and size string fileName = pktFi.FileName; long fileSize = pktFi.FileSize; long streamLen = 0; try { using (FileStream outStream = new FileStream(_tempPath, FileMode.Append, FileAccess.Write, FileShare.Read)) { // calculate offsets int hdrSize = pktFi.GetHeaderSize(); int len = dec.Length - hdrSize; // write to file outStream.Write(ArrayUtils.GetRange(dec, hdrSize, len), 0, len); // store length streamLen = outStream.Length; // progress if (ProgressPercent != null) { double progress = 100.0 * (double)pktFi.OptionsFlag / fileSize; ProgressPercent(this, new System.ComponentModel.ProgressChangedEventArgs((int)progress, (object)fileSize)); } } // transfer completed if (streamLen == fileSize) { // reset attributes File.SetAttributes(_tempPath, File.GetAttributes(_tempPath) & ~FileAttributes.Hidden); // rename the file File.Move(_tempPath, VTDev.Libraries.CEXEngine.Tools.FileTools.GetUniqueName(_filePath)); // notify app if (FileTransferred != null) { FileTransferred(this, new DtmPacketArgs((short)DtmTransferFlags.Received, prcPacket.OptionFlag)); } // flush and close ReceiveClose(); } } catch (Exception ex) { throw new CryptoFileTransferException("DtmFileTransfer:Receive", "The file transfer did not complete!", ex); } }