/// <summary> /// add data from owner to buffer, and the sequence information to data sequence. /// </summary> /// <param name="owner"> /// an object that specifies the owner of data or event.<para/> /// if data, the length must not be null/byte[0].<para/> /// if event, it's a TransportEvent object and data must be byte[0]. /// </param> /// <param name="data"> /// a bytes array that contains the data.<para/> /// if event, it can be null. /// </param> /// <param name="buffer"> /// a BytesBuffer object that stores the data. /// </param> /// <exception cref="ObjectDisposedException"> /// thrown when this object is disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// thrown when data is null. /// </exception> public void Add(object owner, byte[] data, BytesBuffer buffer) { if (disposed) { throw new ObjectDisposedException("DataSequence"); } if (data == null) { throw new ArgumentNullException("data"); } lock (this.objectLock) { // must add data to buffer, then add the sequence item to triggle received event. if (data.Length > 0) { buffer.Add(data); this.dataLength += data.Length; this.sequence.Add(new SequenceItem(owner, data.Length)); } else { this.sequence.Add(new SequenceItem(owner, 0)); } // if the owner in the search history, remove it to make it can be searched by user again. if (this.visitedOwners.Contains(owner)) { this.visitedOwners.Remove(owner); } this.receivedEvent.Set(); } }
/// <summary> /// expect packet from transport. /// </summary> /// <param name="buffer"> /// a BytesBuffer object that contains the received data from endpoint. /// </param> /// <param name="decoder"> /// a DecodePacketCallback delegate that is used to decode packet from buffer. /// </param> /// <param name="endpoint"> /// an object that specifies the endpoint for decoder.<para/> /// remember: this endpoint must be the endpoint that is returned to the user, /// that is the endpoint return by Connect(). /// </param> /// <param name="timeout"> /// a TimeSpan object that indicates the timeout to expect event. /// </param> /// <param name="packetCache"> /// a list that contains the stackpackets. /// </param> /// <returns> /// a StackPacket object that specifies the received packet. /// </returns> public static StackPacket Visit( BytesBuffer buffer, DecodePacketCallback decoder, object endpoint, TimeSpan timeout, SyncFilterQueue <StackPacket> packetCache) { // get the packet in packet list. if (packetCache.Count > 0) { return(Utility.GetOne <StackPacket>(packetCache, null)); } // the consumed length of decoder. int consumedLength = 0; // decode packet, return null or at least one packet. StackPacket[] packets = ExpectMultiPacketsVisitor.Visit( buffer, decoder, endpoint, timeout, out consumedLength); // packet is null, buffer is closed, no packet will come. if (packets == null) { return(null); } // if packet arrived, add to packet list, and return the first. foreach (StackPacket packet in packets) { packetCache.Enqueue(packet); } return(Utility.GetOne <StackPacket>(packetCache, null)); }
/// <summary> /// Release resources. /// </summary> /// <param name = "disposing"> /// If disposing equals true, managed and unmanaged resources are disposed. if false, Only unmanaged resources /// can be disposed. /// </param> protected virtual void Dispose(bool disposing) { if (!this.disposed) { // If disposing equals true, dispose all managed and unmanaged resources. if (disposing) { // Free managed resources & other reference types: if (this.thread != null) { this.thread.Dispose(); this.thread = null; } if (this.transport != null) { // the netbios transport may throw exception, donot arise exception. Utility.SafelyDisconnectNetbiosConnection(this.transport, this.remoteEndPoint); this.transport = null; } if (this.buffer != null) { this.buffer.Dispose(); this.buffer = null; } } // Call the appropriate methods to clean up unmanaged resources. // If disposing is false, only the following code is executed: this.disposed = true; } }
/// <summary> /// connect to remote endpoint.<para/> /// the underlayer transport must be NetbiosTransport, UdpClient or NetbiosClient. /// </summary> /// <returns> /// the remote endpoint of the connection. /// </returns> /// <exception cref="InvalidOperationException"> /// thrown when netbios client is connected to server. /// </exception> /// <exception cref="InvalidOperationException"> /// thrown when the received thread does not cleanup. /// </exception> /// <exception cref="ObjectDisposedException"> /// thrown when this object is disposed. /// </exception> public object Connect() { if (disposed) { throw new ObjectDisposedException("NetbiosClientTransport"); } if (this.transport != null) { throw new InvalidOperationException("netbios client is connected to server."); } if (this.thread != null) { throw new InvalidOperationException("the received thread does not cleanup."); } this.buffer = new BytesBuffer(); this.eventQueue.Clear(); this.packetCache.Clear(); this.transport = new NetbiosTransport( this.netbiosConfig.LocalNetbiosName, this.netbiosConfig.AdapterIndex, (ushort)this.netbiosConfig.BufferSize, (byte)this.netbiosConfig.MaxSessions, (byte)this.netbiosConfig.MaxNames); this.remoteEndPoint = this.transport.Connect(this.netbiosConfig.RemoteNetbiosName); this.localEndPoint = this.transport.NcbNum; this.thread = new ThreadManager(NetbiosClientReceiveLoop, UnblockReceiveThread); this.thread.Start(); return(this.remoteEndPoint); }
/// <summary> /// connect to remote endpoint.<para/> /// the underlayer transport must be TcpClient, UdpClient or NetbiosClient. /// </summary> /// <returns> /// the remote endpoint of the connection. /// </returns> /// <exception cref="InvalidOperationException"> /// thrown when tcp client is connected to server. /// </exception> /// <exception cref="InvalidOperationException"> /// thrown when the received thread does not cleanup. /// </exception> /// <exception cref="ObjectDisposedException"> /// thrown when this object is disposed. /// </exception> public object Connect() { if (disposed) { throw new ObjectDisposedException("StreamTransport"); } if (this.thread != null) { throw new InvalidOperationException("stream client is connected."); } this.buffer = new BytesBuffer(); this.eventQueue.Clear(); this.packetCache.Clear(); this.localEndPoint = StreamTransport.StreamIdentity; this.stream = this.streamConfig.Stream; this.thread = new ThreadManager(StreamReceiveLoop); this.thread.Start(); return(this.localEndPoint); }
public QuicServerConnection( QuicConnection clientConnection, QuicServerTransport quicServerTransport, IPEndPoint lspHookedLocalEP, bool isLspHooked) { if (clientConnection == null) { throw new ArgumentNullException(nameof(clientConnection)); } if (quicServerTransport == null) { throw new ArgumentNullException(nameof(quicServerTransport)); } if (!clientConnection.Connected) { throw new ArgumentException($"Client has already disconnected"); } this.server = quicServerTransport; this.connection = clientConnection; this.stream = clientConnection.OpenBidirectionalStream(); this.thread = new ThreadManager(QuicServerConnectionReceiveLoop, Unblock); this.buffer = new BytesBuffer(); this.localEndPoint = clientConnection.LocalEndPoint as IPEndPoint; this.remoteEndPoint = clientConnection.RemoteEndPoint as IPEndPoint; }
/// <summary> /// to receive bytes from connection. /// </summary> /// <param name="buffer"> /// a BytesBuffer object that contains the received data from endpoint. /// </param> /// <param name="timeout"> /// a TimeSpan object that specifies the timeout for this operation. /// </param> /// <param name="maxCount"> /// an int value that specifies the maximum count of expect bytes. /// </param> /// <returns> /// a bytes array that contains the received bytes. /// </returns> /// <exception cref="InvalidOperationException"> /// thrown when the connection is closed, there is no data anymore. /// </exception> public static byte[] Visit(BytesBuffer buffer, TimeSpan timeout, int maxCount) { bool bufferClosed; // get specified length data in buffer, at-least one byte. byte[] data = buffer.Read(timeout, maxCount, 0, out bufferClosed); if (data.Length == 0) { throw new InvalidOperationException("the connection is closed, there is no data anymore."); } buffer.Remove(data.Length); return data; }
/// <summary> /// to receive bytes from connection. /// </summary> /// <param name="buffer"> /// a BytesBuffer object that contains the received data from endpoint. /// </param> /// <param name="timeout"> /// a TimeSpan object that specifies the timeout for this operation. /// </param> /// <param name="maxCount"> /// an int value that specifies the maximum count of expect bytes. /// </param> /// <returns> /// a bytes array that contains the received bytes. /// </returns> /// <exception cref="InvalidOperationException"> /// thrown when the connection is closed, there is no data anymore. /// </exception> public static byte[] Visit(BytesBuffer buffer, TimeSpan timeout, int maxCount) { bool bufferClosed; // get specified length data in buffer, at-least one byte. byte[] data = buffer.Read(timeout, maxCount, 0, out bufferClosed); if (data.Length == 0) { throw new InvalidOperationException("the connection is closed, there is no data anymore."); } buffer.Remove(data.Length); return(data); }
/// <summary> /// expect packet from transport. /// </summary> /// <param name="buffer"> /// a BytesBuffer object that contains the received data from endpoint. /// </param> /// <param name="decoder"> /// a DecodePacketCallback delegate that is used to decode packet from buffer. /// </param> /// <param name="endpoint"> /// an object that specifies the endpoint for decoder.<para/> /// remember: this endpoint is the identity endpoint of tcp/netbios connection, /// that is the remote endpoint of connection. /// </param> /// <param name="timeout"> /// a TimeSpan object that indicates the timeout to expect event. /// </param> /// <param name="consumedLength"> /// return an int value that specifies the consumed length. /// </param> /// <returns> /// a StackPacket object that specifies the received packet. /// </returns> public static StackPacket[] Visit( BytesBuffer buffer, DecodePacketCallback decoder, object endpoint, TimeSpan timeout, out int consumedLength) { bool bufferClosed; // get all data in buffer, at-least one byte. byte[] data = buffer.Read(timeout, BytesBuffer.MaxCount, 0, out bufferClosed); // the end time for operation. DateTime endTime = DateTime.Now + timeout; while (true) { // decode packets using data in buffer. int expectedLength = 0; // decode data. if (data.Length > 0) { StackPacket[] packets = decoder(endpoint, data, out consumedLength, out expectedLength); buffer.Remove(consumedLength); // if packet arrived, add to packet list, and return the first. if (packets != null && packets.Length > 0) { return(packets); } } // if buffer is closed, no data will come, return null. if (bufferClosed) { consumedLength = 0; return(null); } // wait for the next data coming. data = buffer.Read(endTime - DateTime.Now, BytesBuffer.MaxCount, data.Length, out bufferClosed); } }
/// <summary> /// Release resources. /// </summary> /// <param name = "disposing"> /// If disposing equals true, Managed and unmanaged resources are disposed. if false, Only unmanaged resources /// can be disposed. /// </param> protected virtual void Dispose(bool disposing) { if (!this.disposed) { // If disposing equals true, dispose all managed and unmanaged resources. if (disposing) { // Free managed resources & other reference types: if (this.thread != null) { this.thread.Dispose(); this.thread = null; } if (this.stream != null) { this.stream.Dispose(); this.stream = null; } if (this.eventQueue != null) { // the SyncFilterQueue may throw exception, donot arise exception. this.eventQueue.Dispose(); this.eventQueue = null; } if (this.packetCache != null) { this.packetCache.Dispose(); this.packetCache = null; } if (this.buffer != null) { this.buffer.Dispose(); this.buffer = null; } } // Call the appropriate methods to clean up unmanaged resources. // If disposing is false, only the following code is executed: this.disposed = true; } }
/// <summary> /// consturctor. /// </summary> /// <param name="transportConfig"> /// a TransportConfig object that contains the config. /// </param> /// <param name="decodePacketCallback"> /// a DecodePacketCallback delegate that is used to decode the packet from bytes. /// </param> /// <exception cref="ArgumentException"> /// thrown when transportConfig is not StreamConfig /// </exception> /// <exception cref="ArgumentNullException"> /// thrown when transportConfig is null. /// </exception> /// <exception cref="ArgumentNullException"> /// thrown when decodePacketCallback is null. /// </exception> public StreamTransport(TransportConfig transportConfig, DecodePacketCallback decodePacketCallback) { if (transportConfig == null) { throw new ArgumentNullException("transportConfig"); } if (decodePacketCallback == null) { throw new ArgumentNullException("decodePacketCallback"); } this.UpdateConfig(transportConfig); this.buffer = new BytesBuffer(); this.eventQueue = new SyncFilterQueue <TransportEvent>(); this.packetCache = new SyncFilterQueue <StackPacket>(); this.decoder = decodePacketCallback; }
/// <summary> /// constructor /// </summary> /// <param name="localEndPoint"> /// an int value that specifies the session id of connection. /// </param> /// <param name="remoteEndPoint"> /// an int value that specifies the session id of connection. /// </param> /// <param name="server"> /// NetbiosServerTransport object that specifies the netbios server transport. /// </param> /// <param name="transport"> /// a NetbiosTransport object that specifies the owner of client. /// </param> /// <exception cref="ArgumentNullException"> /// thrown when the server is null! /// </exception> /// <exception cref="ArgumentNullException"> /// thrown when the transport is null! /// </exception> public NetbiosServerConnection( int localEndPoint, int remoteEndPoint, NetbiosServerTransport server, NetbiosTransport transport) { if (server == null) { throw new ArgumentNullException("server"); } if (transport == null) { throw new ArgumentNullException("transport"); } this.localEndPoint = localEndPoint; this.remoteEndPoint = remoteEndPoint; this.server = server; this.transport = transport; this.thread = new ThreadManager(NetbiosServerConnectionReceiveLoop, Unblock); this.buffer = new BytesBuffer(); }
/// <summary> /// constructor /// </summary> /// <param name="tcpClient"> /// a TcpClient object that specifies the tcp client. /// </param> /// <param name="tcpServerTransport"> /// a TcpServerTransport that represents the owner of listener. /// </param> /// <param name="lspHookedLocalEP"> /// an IPEndPoint object that specifies the local endpoint.<para/> /// if LSP hooked, return the required local endpoint.<para/> /// otherwise, return the actual listened local endpoint. /// </param> /// <param name="isLspHooked"> /// a bool value that indicates whether lsp hooked the transport. /// </param> /// <exception cref="ArgumentNullException"> /// thrown when the tcpClient is null! /// </exception> /// <exception cref="ArgumentNullException"> /// thrown when the tcpServerTransport is null! /// </exception> public TcpServerConnection( TcpClient tcpClient, TcpServerTransport tcpServerTransport, IPEndPoint lspHookedLocalEP, bool isLspHooked) { if (tcpClient == null) { throw new ArgumentNullException("tcpClient"); } if (tcpServerTransport == null) { throw new ArgumentNullException("tcpServerTransport"); } this.isAForwarderChannel = false; this.lspHooked = isLspHooked; this.stream = tcpClient.GetStream(); this.server = tcpServerTransport; this.thread = new ThreadManager(TcpServerConnectionReceiveLoop, Unblock); this.buffer = new BytesBuffer(); if (isLspHooked) { IPEndPoint destinationEndpoint; this.localEndPoint = lspHookedLocalEP; this.remoteEndPoint = LspConsole.Instance.RetrieveRemoteEndPoint(tcpClient.Client, out destinationEndpoint); //if equals, it means this is a forwarder channel. if (remoteEndPoint.Equals(destinationEndpoint)) { isAForwarderChannel = true; } } else { this.localEndPoint = tcpClient.Client.LocalEndPoint as IPEndPoint; this.remoteEndPoint = tcpClient.Client.RemoteEndPoint as IPEndPoint; } }
/// <summary> /// Release resources. /// </summary> /// <param name = "disposing"> /// If disposing equals true, managed and unmanaged resources are disposed. if false, Only unmanaged resources /// can be disposed. /// </param> protected virtual void Dispose(bool disposing) { if (!this.disposed) { // If disposing equals true, dispose all managed and unmanaged resources. if (disposing) { // Free managed resources & other reference types: if (this.thread != null) { this.thread.Dispose(); this.thread = null; } if (this.stream != null) { this.stream.Close(); this.stream = null; } if (this.buffer != null) { this.buffer.Dispose(); this.buffer = null; } if (associatedForwarderChannel != null) { this.associatedForwarderChannel.Dispose(); } } // Call the appropriate methods to clean up unmanaged resources. // If disposing is false, only the following code is executed: this.disposed = true; } }
/// <summary> /// expect packet from transport. /// </summary> /// <param name="buffer"> /// a BytesBuffer object that contains the received data from endpoint. /// </param> /// <param name="decoder"> /// a DecodePacketCallback delegate that is used to decode packet from buffer. /// </param> /// <param name="endpoint"> /// an object that specifies the endpoint for decoder.<para/> /// remember: this endpoint must be the endpoint that is returned to the user, /// that is the endpoint return by Connect(). /// </param> /// <param name="timeout"> /// a TimeSpan object that indicates the timeout to expect event. /// </param> /// <param name="packetCache"> /// a list that contains the stackpackets. /// </param> /// <returns> /// a StackPacket object that specifies the received packet. /// </returns> public static StackPacket Visit( BytesBuffer buffer, DecodePacketCallback decoder, object endpoint, TimeSpan timeout, SyncFilterQueue<StackPacket> packetCache) { // get the packet in packet list. if (packetCache.Count > 0) { return Utility.GetOne<StackPacket>(packetCache, null); } // the consumed length of decoder. int consumedLength = 0; // decode packet, return null or at least one packet. StackPacket[] packets = ExpectMultiPacketsVisitor.Visit( buffer, decoder, endpoint, timeout, out consumedLength); // packet is null, buffer is closed, no packet will come. if (packets == null) { return null; } // if packet arrived, add to packet list, and return the first. foreach (StackPacket packet in packets) { packetCache.Enqueue(packet); } return Utility.GetOne<StackPacket>(packetCache, null); }
/// <summary> /// connect to remote endpoint.<para/> /// the underlayer transport must be TcpClient, UdpClient or NetbiosClient. /// </summary> /// <returns> /// the remote endpoint of the connection. /// </returns> /// <exception cref="InvalidOperationException"> /// thrown when tcp client is connected to server. /// </exception> /// <exception cref="InvalidOperationException"> /// thrown when the received thread does not cleanup. /// </exception> /// <exception cref="InvalidOperationException"> /// thrown when the remote ip address is null. /// </exception> /// <exception cref="ObjectDisposedException"> /// thrown when this object is disposed. /// </exception> public object Connect() { if (disposed) { throw new ObjectDisposedException("TcpClientTransport"); } if (this.stream != null) { throw new InvalidOperationException("tcp client is connected to server."); } if (this.thread != null) { throw new InvalidOperationException("the received thread does not cleanup."); } if (this.socketConfig.RemoteIpAddress == null) { throw new InvalidOperationException("the remote ip address is null."); } this.buffer = new BytesBuffer(); this.eventQueue.Clear(); this.packetCache.Clear(); TcpClient tcpClient; if (this.socketConfig.LocalIpAddress != null) { tcpClient = new TcpClient(new IPEndPoint(this.socketConfig.LocalIpAddress, 0)); } else { tcpClient = new TcpClient(this.socketConfig.RemoteIpAddress.AddressFamily); } // The Timeout be set to TimeSpan.Zero if it is not initialized. if (this.socketConfig.Timeout != TimeSpan.Zero) { IAsyncResult result = tcpClient.BeginConnect(this.socketConfig.RemoteIpAddress, this.socketConfig.RemoteIpPort, new AsyncCallback(TcpConnectCallback), tcpClient); result.AsyncWaitHandle.WaitOne(this.socketConfig.Timeout, true); if (!tcpClient.Connected) { throw new TimeoutException(string.Format(CultureInfo.InvariantCulture, "Failed to connect server {0}:{1} within {2} milliseconds.", this.socketConfig.RemoteIpAddress,this.socketConfig.RemoteIpPort, this.socketConfig.Timeout.TotalMilliseconds)); } } else { tcpClient.Connect(new IPEndPoint(this.socketConfig.RemoteIpAddress, this.socketConfig.RemoteIpPort)); } this.localEndPoint = tcpClient.Client.LocalEndPoint; this.remoteEndPoint = tcpClient.Client.RemoteEndPoint; this.stream = tcpClient.GetStream(); if (this.sslProvider != null) { SslStream sslStream = new SslStream(this.stream); if (this.sslProvider.Certificate == null) { sslStream.AuthenticateAsClient(this.sslProvider.TargetHost); } else { sslStream.AuthenticateAsClient(this.sslProvider.TargetHost, new X509CertificateCollection(new X509Certificate[] { this.sslProvider.Certificate }), this.sslProvider.EnabledSslProtocols, false); } this.stream = sslStream; } this.thread = new ThreadManager(TcpClientReceiveLoop, UnblockReceiveThread); this.thread.Start(); return this.localEndPoint; }
/// <summary> /// connect to remote endpoint.<para/> /// the underlayer transport must be TcpClient, UdpClient or NetbiosClient. /// </summary> /// <returns> /// the remote endpoint of the connection. /// </returns> /// <exception cref="InvalidOperationException"> /// thrown when tcp client is connected to server. /// </exception> /// <exception cref="InvalidOperationException"> /// thrown when the received thread does not cleanup. /// </exception> /// <exception cref="ObjectDisposedException"> /// thrown when this object is disposed. /// </exception> public object Connect() { if (disposed) { throw new ObjectDisposedException("StreamTransport"); } if (this.thread != null) { throw new InvalidOperationException("stream client is connected."); } this.buffer = new BytesBuffer(); this.eventQueue.Clear(); this.packetCache.Clear(); this.localEndPoint = StreamTransport.StreamIdentity; this.stream = this.streamConfig.Stream; this.thread = new ThreadManager(StreamReceiveLoop); this.thread.Start(); return this.localEndPoint; }
/// <summary> /// constructor /// </summary> /// <param name="transportConfig"> /// a TransportConfig object that contains the config. /// </param> /// <param name="decodePacketCallback"> /// a DecodePacketCallback delegate that is used to decode the packet from bytes. /// </param> /// <exception cref="ArgumentException"> /// thrown when transportConfig is not NetbiosTransportConfig /// </exception> /// <exception cref="ArgumentNullException"> /// thrown when transportConfig is null. /// </exception> /// <exception cref="ArgumentNullException"> /// thrown when decodePacketCallback is null. /// </exception> public NetbiosClientTransport(TransportConfig transportConfig, DecodePacketCallback decodePacketCallback) { if (transportConfig == null) { throw new ArgumentNullException("transportConfig"); } if (decodePacketCallback == null) { throw new ArgumentNullException("decodePacketCallback"); } this.UpdateConfig(transportConfig); this.buffer = new BytesBuffer(); this.eventQueue = new SyncFilterQueue<TransportEvent>(); this.packetCache = new SyncFilterQueue<StackPacket>(); this.decoder = decodePacketCallback; }
/// <summary> /// connect to remote endpoint.<para/> /// the underlayer transport must be NetbiosTransport, UdpClient or NetbiosClient. /// </summary> /// <returns> /// the remote endpoint of the connection. /// </returns> /// <exception cref="InvalidOperationException"> /// thrown when netbios client is connected to server. /// </exception> /// <exception cref="InvalidOperationException"> /// thrown when the received thread does not cleanup. /// </exception> /// <exception cref="ObjectDisposedException"> /// thrown when this object is disposed. /// </exception> public object Connect() { if (disposed) { throw new ObjectDisposedException("NetbiosClientTransport"); } if (this.transport != null) { throw new InvalidOperationException("netbios client is connected to server."); } if (this.thread != null) { throw new InvalidOperationException("the received thread does not cleanup."); } this.buffer = new BytesBuffer(); this.eventQueue.Clear(); this.packetCache.Clear(); this.transport = new NetbiosTransport( this.netbiosConfig.LocalNetbiosName, this.netbiosConfig.AdapterIndex, (ushort)this.netbiosConfig.BufferSize, (byte)this.netbiosConfig.MaxSessions, (byte)this.netbiosConfig.MaxNames); this.remoteEndPoint = this.transport.Connect(this.netbiosConfig.RemoteNetbiosName); this.localEndPoint = this.transport.NcbNum; this.thread = new ThreadManager(NetbiosClientReceiveLoop, UnblockReceiveThread); this.thread.Start(); return this.remoteEndPoint; }
/// <summary> /// connect to remote endpoint.<para/> /// the underlayer transport must be TcpClient, UdpClient or NetbiosClient. /// </summary> /// <returns> /// the remote endpoint of the connection. /// </returns> /// <exception cref="InvalidOperationException"> /// thrown when tcp client is connected to server. /// </exception> /// <exception cref="InvalidOperationException"> /// thrown when the received thread does not cleanup. /// </exception> /// <exception cref="InvalidOperationException"> /// thrown when the remote ip address is null. /// </exception> /// <exception cref="ObjectDisposedException"> /// thrown when this object is disposed. /// </exception> public object Connect() { if (disposed) { throw new ObjectDisposedException("TcpClientTransport"); } if (this.stream != null) { throw new InvalidOperationException("tcp client is connected to server."); } if (this.thread != null) { throw new InvalidOperationException("the received thread does not cleanup."); } if (this.socketConfig.RemoteIpAddress == null) { throw new InvalidOperationException("the remote ip address is null."); } this.buffer = new BytesBuffer(); this.eventQueue.Clear(); this.packetCache.Clear(); TcpClient tcpClient; if (this.socketConfig.LocalIpAddress != null) { tcpClient = new TcpClient(new IPEndPoint(this.socketConfig.LocalIpAddress, 0)); } else { tcpClient = new TcpClient(this.socketConfig.RemoteIpAddress.AddressFamily); } // The Timeout be set to TimeSpan.Zero if it is not initialized. if (this.socketConfig.Timeout != TimeSpan.Zero) { IAsyncResult result = tcpClient.BeginConnect(this.socketConfig.RemoteIpAddress, this.socketConfig.RemoteIpPort, new AsyncCallback(TcpConnectCallback), tcpClient); result.AsyncWaitHandle.WaitOne(this.socketConfig.Timeout, true); if (!tcpClient.Connected) { throw new TimeoutException(string.Format(CultureInfo.InvariantCulture, "Failed to connect server {0}:{1} within {2} milliseconds.", this.socketConfig.RemoteIpAddress, this.socketConfig.RemoteIpPort, this.socketConfig.Timeout.TotalMilliseconds)); } } else { tcpClient.Connect(new IPEndPoint(this.socketConfig.RemoteIpAddress, this.socketConfig.RemoteIpPort)); } this.localEndPoint = tcpClient.Client.LocalEndPoint; this.remoteEndPoint = tcpClient.Client.RemoteEndPoint; this.stream = tcpClient.GetStream(); if (this.sslProvider != null) { SslStream sslStream = new SslStream(this.stream); if (this.sslProvider.Certificate == null) { sslStream.AuthenticateAsClient(this.sslProvider.TargetHost); } else { sslStream.AuthenticateAsClient(this.sslProvider.TargetHost, new X509CertificateCollection(new X509Certificate[] { this.sslProvider.Certificate }), this.sslProvider.EnabledSslProtocols, false); } this.stream = sslStream; } this.thread = new ThreadManager(TcpClientReceiveLoop, UnblockReceiveThread); this.thread.Start(); return(this.localEndPoint); }
/// <summary> /// expect packet from transport. /// </summary> /// <param name="buffer"> /// a BytesBuffer object that contains the received data from endpoint. /// </param> /// <param name="decoder"> /// a DecodePacketCallback delegate that is used to decode packet from buffer. /// </param> /// <param name="endpoint"> /// an object that specifies the endpoint for decoder.<para/> /// remember: this endpoint is the identity endpoint of tcp/netbios connection, /// that is the remote endpoint of connection. /// </param> /// <param name="timeout"> /// a TimeSpan object that indicates the timeout to expect event. /// </param> /// <param name="consumedLength"> /// return an int value that specifies the consumed length. /// </param> /// <returns> /// a StackPacket object that specifies the received packet. /// </returns> public static StackPacket[] Visit( BytesBuffer buffer, DecodePacketCallback decoder, object endpoint, TimeSpan timeout, out int consumedLength) { bool bufferClosed; // get all data in buffer, at-least one byte. byte[] data = buffer.Read(timeout, BytesBuffer.MaxCount, 0, out bufferClosed); // the end time for operation. DateTime endTime = DateTime.Now + timeout; while (true) { // decode packets using data in buffer. int expectedLength = 0; // decode data. if (data.Length > 0) { StackPacket[] packets = decoder(endpoint, data, out consumedLength, out expectedLength); buffer.Remove(consumedLength); // if packet arrived, add to packet list, and return the first. if (packets != null && packets.Length > 0) { return packets; } } // if buffer is closed, no data will come, return null. if (bufferClosed) { consumedLength = 0; return null; } // wait for the next data coming. data = buffer.Read(endTime - DateTime.Now, BytesBuffer.MaxCount, data.Length, out bufferClosed); } }
/// <summary> /// Release resources. /// </summary> /// <param name = "disposing"> /// If disposing equals true, Managed and unmanaged resources are disposed. if false, Only unmanaged resources /// can be disposed. /// </param> protected virtual void Dispose(bool disposing) { if (!this.disposed) { // If disposing equals true, dispose all managed and unmanaged resources. if (disposing) { // Free managed resources & other reference types: if (this.thread != null) { this.thread.Dispose(); this.thread = null; } if (this.transport != null) { // the netbios transport may throw exception, donot arise exception. Utility.SafelyDisconnectNetbiosConnection(this.transport, this.remoteEndPoint); this.transport.Dispose(); this.transport = null; } if (this.eventQueue != null) { // the SyncFilterQueue may throw exception, donot arise exception. this.eventQueue.Dispose(); this.eventQueue = null; } if (this.packetCache != null) { this.packetCache.Dispose(); this.packetCache = null; } if (this.buffer != null) { this.buffer.Dispose(); this.buffer = null; } } // Call the appropriate methods to clean up unmanaged resources. // If disposing is false, only the following code is executed: this.disposed = true; } }