/// <summary> /// Frame and Transmit the packet to the remote client /// </summary> /// /// <param name="PacketType">The packet class</param> /// <param name="PacketFlag">The packet message type flag</param> /// <param name="OptionFlag">The option flag</param> /// <param name="Payload">The packet payload flag</param> /// <param name="Blocking">Blocking or Async transmit</param> private void Transmit(DtmPacketTypes PacketType, short PacketFlag, long OptionFlag = 0, MemoryStream Payload = null, bool Blocking = false) { lock (_sendLock) { long pldLen = Payload == null ? 0 : Payload.Length; // create a new packet: packet flag, payload size, sequence, and state flag MemoryStream pktStm = new DtmPacket(PacketType, pldLen, _sndSequence, PacketFlag, OptionFlag).ToStream(); // add payload if (Payload != null) { // store total encrypted bytes sent if (_isEstablished) _bytesSent += Payload.Length; // copy to output pktStm.Seek(0, SeekOrigin.End); Payload.WriteTo(pktStm); pktStm.Seek(0, SeekOrigin.Begin); } // service requests are not buffered if (PacketType != DtmPacketTypes.Service) { // store in the packet buffer _sndBuffer.Push(_sndSequence, pktStm); } // increment send counter _sndSequence++; // transmit to remote client if (_clientSocket.IsConnected) { if (Blocking) { 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, slow down Throttle(pktStm); } else if (se.SocketErrorCode != SocketError.Success) { // possible connection dropped, alert app if (SessionError != null) { DtmErrorEventArgs args = new DtmErrorEventArgs(ce, DtmErrorSeverity.Connection); SessionError(this, args); if (args.Cancel == true) Disconnect(); } } } } else { try { pktStm.WriteTo(_clientSocket.TcpStream); } catch (Exception ex) { // internal error, alert app if (SessionError != null) { DtmErrorEventArgs args = new DtmErrorEventArgs(ex, DtmErrorSeverity.Critical); SessionError(this, args); if (args.Cancel == true) Disconnect(); } } } // notify app if (PacketSent != null) PacketSent(this, new DtmPacketEventArgs((short)_exchangeState, pldLen)); } else { // possible connection dropped, alert app if (SessionError != null) { DtmErrorEventArgs args = new DtmErrorEventArgs(new SocketException((int)SocketError.ConnectionReset), DtmErrorSeverity.Connection); SessionError(this, args); if (args.Cancel == true) Disconnect(); } } } }
private void Transmit(DtmPacketTypes 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 DtmPacket(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) { DtmErrorEventArgs args = new DtmErrorEventArgs(ce, DtmErrorSeverity.Connection); SessionError(this, args); } } } catch (Exception) { } // notify app if (PacketSent != null) PacketSent(this, new DtmPacketEventArgs((short)DtmTransferFlags.DataChunk, pldLen)); } } }
/// <summary> /// Blocking transceiver; sends a packet and waits for a response. /// <para>For use with time sensitive data, that requires fast synchronous processing. /// Sent and received packets are not queued or buffered.</para> /// </summary> /// /// <param name="DataStream">The payload data to send to the remote host</param> /// <param name="TimeOut">The number of milliseconds to wait before timing out (default is infinite)</param> /// /// <returns>The return streams decrypted payload data, or an empty stream on failure</returns> public MemoryStream SendReceive(MemoryStream DataStream, int TimeOut = Timeout.Infinite) { if (!_isEstablished) throw new CryptoProcessingException("DtmKex:SendReceive", "The VPN is not established!", new InvalidOperationException()); byte[] data = DataStream.ToArray(); // append/prepend random data = WrapMessage(data, _dtmParameters.MaxMessageAppend, _dtmParameters.MaxMessagePrePend); // encrypt the data with the clients symmetric processor byte[] enc = SymmetricTransform(_srvSymProcessor, data); // store total bytes sent _bytesSent += enc.Length; // optional delay before transmission if (_dtmParameters.MaxMessageDelayMS > 0) SendWait(_dtmParameters.MaxMessageDelayMS); // create the packet MemoryStream pktStm = new DtmPacket(DtmPacketTypes.Message, enc.Length, _sndSequence, (short)DtmMessageFlags.Transmission).ToStream(); pktStm.Seek(0, SeekOrigin.End); pktStm.Write(enc, 0, enc.Length); pktStm.Seek(0, SeekOrigin.Begin); // transmit data _clientSocket.Send(pktStm); _sndSequence++; // wait for response pktStm = BlockingReceive(); // get the header DtmPacket dtmHdr = new DtmPacket(pktStm); // payload buffer data = new byte[dtmHdr.PayloadLength]; // copy data to buffer pktStm.Write(data, 0, data.Length); // decrypt response data = SymmetricTransform(_cltSymProcessor, data); // remove padding data = UnwrapMessage(data); // increment rcv counter _rcvSequence++; // record encrypted byte count for resync _bytesReceived += dtmHdr.PayloadLength; return new MemoryStream(data); }
/// <summary> /// Creates a serialized request packet (DtmPacket) /// </summary> private MemoryStream CreateRequest(DtmPacketTypes Message, short State) { MemoryStream ret = new DtmPacket(Message, 0, 0, State).ToStream(); ret.Seek(0, SeekOrigin.Begin); return ret; }