2 * $Id: IrcConnection.cs 211 2007-02-01 22:08:32Z meebey $
3 * $URL: svn://svn.qnetp.net/smartirc/SmartIrc4net/tags/0.4.0/src/IrcConnection/IrcConnection.cs $
6 * $Date: 2007-02-01 23:08:32 +0100 (Thu, 01 Feb 2007) $
8 * SmartIrc4net - the IRC library for .NET/C# <http://smartirc4net.sf.net>
10 * Copyright (c) 2003-2005 Mirco Bauer <meebey@meebey.net> <http://www.meebey.net>
12 * Full LGPL License: <http://www.gnu.org/licenses/lgpl.txt>
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 using System
.Collections
;
33 using System
.Threading
;
34 using System
.Reflection
;
35 using System
.Net
.Sockets
;
37 namespace Meebey
.SmartIrc4net
42 /// <threadsafety static="true" instance="true" />
43 public class IrcConnection
45 private string _VersionNumber
;
46 private string _VersionString
;
47 private string[] _AddressList
= {"localhost"}
;
48 private int _CurrentAddress
;
49 private int _Port
= 6667;
50 private StreamReader _Reader
;
51 private StreamWriter _Writer
;
52 private ReadThread _ReadThread
;
53 private WriteThread _WriteThread
;
54 private IdleWorkerThread _IdleWorkerThread
;
55 private IrcTcpClient _TcpClient
;
56 private Hashtable _SendBuffer
= Hashtable
.Synchronized(new Hashtable());
57 private int _SendDelay
= 200;
58 private bool _IsRegistered
;
59 private bool _IsConnected
;
60 private bool _IsConnectionError
;
61 private int _ConnectTries
;
62 private bool _AutoRetry
;
63 private int _AutoRetryDelay
= 30;
64 private bool _AutoReconnect
;
65 private Encoding _Encoding
= Encoding
.Default
;
66 private int _SocketReceiveTimeout
= 600;
67 private int _SocketSendTimeout
= 600;
68 private int _IdleWorkerInterval
= 60;
69 private int _PingInterval
= 60;
70 private int _PingTimeout
= 300;
71 private DateTime _LastPingSent
;
72 private DateTime _LastPongReceived
;
73 private TimeSpan _Lag
;
75 /// <event cref="OnReadLine">
76 /// Raised when a \r\n terminated line is read from the socket
78 public event ReadLineEventHandler OnReadLine
;
79 /// <event cref="OnWriteLine">
80 /// Raised when a \r\n terminated line is written to the socket
82 public event WriteLineEventHandler OnWriteLine
;
83 /// <event cref="OnConnect">
84 /// Raised before the connect attempt
86 public event EventHandler OnConnecting
;
87 /// <event cref="OnConnect">
88 /// Raised on successful connect
90 public event EventHandler OnConnected
;
91 /// <event cref="OnConnect">
92 /// Raised before the connection is closed
94 public event EventHandler OnDisconnecting
;
95 /// <event cref="OnConnect">
96 /// Raised when the connection is closed
98 public event EventHandler OnDisconnected
;
99 /// <event cref="OnConnectionError">
100 /// Raised when the connection got into an error state
102 public event EventHandler OnConnectionError
;
103 /// <event cref="AutoConnectErrorEventHandler">
104 /// Raised when the connection got into an error state during auto connect loop
106 public event AutoConnectErrorEventHandler OnAutoConnectError
;
109 /// When a connection error is detected this property will return true
111 protected bool IsConnectionError
{
114 return _IsConnectionError
;
119 _IsConnectionError
= value;
125 /// Gets the current address of the connection
127 public string Address
{
129 return _AddressList
[_CurrentAddress
];
134 /// Gets the address list of the connection
136 public string[] AddressList
{
143 /// Gets the used port of the connection
152 /// By default nothing is done when the library looses the connection
157 /// true, if the library should reconnect on lost connections
158 /// false, if the library should not take care of it
160 public bool AutoReconnect
{
162 return _AutoReconnect
;
167 Logger
.Connection
.Info("AutoReconnect enabled");
169 Logger
.Connection
.Info("AutoReconnect disabled");
172 _AutoReconnect
= value;
177 /// If the library should retry to connect when the connection fails.
181 /// true, if the library should retry to connect
182 /// false, if the library should not retry
184 public bool AutoRetry
{
191 Logger
.Connection
.Info("AutoRetry enabled");
193 Logger
.Connection
.Info("AutoRetry disabled");
201 /// Delay between retry attempts in Connect() in seconds.
204 public int AutoRetryDelay
{
206 return _AutoRetryDelay
;
209 _AutoRetryDelay
= value;
214 /// To prevent flooding the IRC server, it's required to delay each
215 /// message, given in milliseconds.
218 public int SendDelay
{
228 /// On successful registration on the IRC network, this is set to true.
230 public bool IsRegistered
{
232 return _IsRegistered
;
237 /// On successful connect to the IRC server, this is set to true.
239 public bool IsConnected
{
246 /// Gets the SmartIrc4net version number
248 public string VersionNumber
{
250 return _VersionNumber
;
255 /// Gets the full SmartIrc4net version string
257 public string VersionString
{
259 return _VersionString
;
264 /// Encoding which is used for reading and writing to the socket
265 /// Default: encoding of the system
267 public Encoding Encoding
{
277 /// Timeout in seconds for receiving data from the socket
280 public int SocketReceiveTimeout
{
282 return _SocketReceiveTimeout
;
285 _SocketReceiveTimeout
= value;
290 /// Timeout in seconds for sending data to the socket
293 public int SocketSendTimeout
{
295 return _SocketSendTimeout
;
298 _SocketSendTimeout
= value;
303 /// Interval in seconds to run the idle worker
306 public int IdleWorkerInterval
{
308 return _IdleWorkerInterval
;
311 _IdleWorkerInterval
= value;
316 /// Interval in seconds to send a PING
319 public int PingInterval
{
321 return _PingInterval
;
324 _PingInterval
= value;
329 /// Timeout in seconds for server response to a PING
332 public int PingTimeout
{
337 _PingTimeout
= value;
342 /// Latency between client and the server
344 public TimeSpan Lag
{
351 /// Initializes the message queues, read and write thread
353 public IrcConnection()
357 Logger
.Main
.Debug("IrcConnection created");
359 _SendBuffer
[Priority
.High
] = Queue
.Synchronized(new Queue());
360 _SendBuffer
[Priority
.AboveMedium
] = Queue
.Synchronized(new Queue());
361 _SendBuffer
[Priority
.Medium
] = Queue
.Synchronized(new Queue());
362 _SendBuffer
[Priority
.BelowMedium
] = Queue
.Synchronized(new Queue());
363 _SendBuffer
[Priority
.Low
] = Queue
.Synchronized(new Queue());
365 // setup own callbacks
366 OnReadLine
+= new ReadLineEventHandler(_SimpleParser
);
367 OnConnectionError
+= new EventHandler(_OnConnectionError
);
369 _ReadThread
= new ReadThread(this);
370 _WriteThread
= new WriteThread(this);
371 _IdleWorkerThread
= new IdleWorkerThread(this);
373 Assembly assm
= Assembly
.GetAssembly(this.GetType());
374 AssemblyName assm_name
= assm
.GetName(false);
376 AssemblyProductAttribute pr
= (AssemblyProductAttribute
)assm
.GetCustomAttributes(typeof(AssemblyProductAttribute
), false)[0];
378 _VersionNumber
= assm_name
.Version
.ToString();
379 _VersionString
= pr
.Product
+" "+_VersionNumber
;
385 Logger
.Main
.Debug("IrcConnection destroyed");
389 /// <overloads>this method has 2 overloads</overloads>
391 /// Connects to the specified server and port, when the connection fails
392 /// the next server in the list will be used.
394 /// <param name="addresslist">List of servers to connect to</param>
395 /// <param name="port">Portnumber to connect to</param>
396 /// <exception cref="CouldNotConnectException">The connection failed</exception>
397 /// <exception cref="AlreadyConnectedException">If there is already an active connection</exception>
398 public void Connect(string[] addresslist
, int port
)
401 throw new AlreadyConnectedException("Already connected to: "+Address
+":"+Port
);
405 Logger
.Connection
.Info("connecting...");
408 _AddressList
= (string[])addresslist
.Clone();
411 if (OnConnecting
!= null) {
412 OnConnecting(this, EventArgs
.Empty
);
415 System
.Net
.IPAddress ip
= System
.Net
.Dns
.Resolve(Address
).AddressList
[0];
416 _TcpClient
= new IrcTcpClient();
417 _TcpClient
.NoDelay
= true;
418 _TcpClient
.Socket
.SetSocketOption(SocketOptionLevel
.Socket
, SocketOptionName
.KeepAlive
, 1);
419 // set timeout, after this the connection will be aborted
420 _TcpClient
.ReceiveTimeout
= _SocketReceiveTimeout
*1000;
421 _TcpClient
.SendTimeout
= _SocketSendTimeout
*1000;
422 _TcpClient
.Connect(ip
, port
);
424 _Reader
= new StreamReader(_TcpClient
.GetStream(), _Encoding
);
425 _Writer
= new StreamWriter(_TcpClient
.GetStream(), _Encoding
);
427 if (_Encoding
.GetPreamble().Length
> 0) {
428 // HACK: we have an encoding that has some kind of preamble
429 // like UTF-8 has a BOM, this will confuse the IRCd!
430 // Thus we send a \r\n so the IRCd can safely ignore that
435 // Connection was succeful, reseting the connect counter
438 // updating the connection error state, so connecting is possible again
439 IsConnectionError
= false;
442 // lets power up our threads
444 _WriteThread
.Start();
445 _IdleWorkerThread
.Start();
448 Logger
.Connection
.Info("connected");
450 if (OnConnected
!= null) {
451 OnConnected(this, EventArgs
.Empty
);
453 } catch (Exception e
) {
454 if (_Reader
!= null) {
457 } catch (ObjectDisposedException
) {
460 if (_Writer
!= null) {
463 } catch (ObjectDisposedException
) {
466 if (_TcpClient
!= null) {
469 _IsConnected
= false;
470 IsConnectionError
= true;
473 Logger
.Connection
.Info("connection failed: "+e
.Message
);
476 _ConnectTries
<= 3) {
477 if (OnAutoConnectError
!= null) {
478 OnAutoConnectError(this, new AutoConnectErrorEventArgs(Address
, Port
, e
));
481 Logger
.Connection
.Debug("delaying new connect attempt for "+_AutoRetryDelay
+" sec");
483 Thread
.Sleep(_AutoRetryDelay
* 1000);
485 Connect(_AddressList
, _Port
);
487 throw new CouldNotConnectException("Could not connect to: "+Address
+":"+Port
+" "+e
.Message
, e
);
493 /// Connects to the specified server and port.
495 /// <param name="address">Server address to connect to</param>
496 /// <param name="port">Port number to connect to</param>
497 public void Connect(string address
, int port
)
499 Connect(new string[] {address}
, port
);
503 /// Reconnects to the server
505 /// <exception cref="NotConnectedException">
506 /// If there was no active connection
508 /// <exception cref="CouldNotConnectException">
509 /// The connection failed
511 /// <exception cref="AlreadyConnectedException">
512 /// If there is already an active connection
514 public void Reconnect()
517 Logger
.Connection
.Info("reconnecting...");
520 Connect(_AddressList
, _Port
);
524 /// Disconnects from the server
526 /// <exception cref="NotConnectedException">
527 /// If there was no active connection
529 public void Disconnect()
532 throw new NotConnectedException("The connection could not be disconnected because there is no active connection");
536 Logger
.Connection
.Info("disconnecting...");
538 if (OnDisconnecting
!= null) {
539 OnDisconnecting(this, EventArgs
.Empty
);
545 _IsConnected
= false;
546 _IsRegistered
= false;
548 if (OnDisconnected
!= null) {
549 OnDisconnected(this, EventArgs
.Empty
);
553 Logger
.Connection
.Info("disconnected");
560 /// <param name="blocking"></param>
561 public void Listen(bool blocking
)
564 while (IsConnected
) {
568 while (ReadLine(false).Length
> 0) {
569 // loop as long as we receive messages
585 /// <param name="blocking"></param>
586 public void ListenOnce(bool blocking
)
594 public void ListenOnce()
602 /// <param name="blocking"></param>
603 /// <returns></returns>
604 public string ReadLine(bool blocking
)
608 // block till the queue has data, but bail out on connection error
609 while (IsConnected
&&
610 !IsConnectionError
&&
611 _ReadThread
.Queue
.Count
== 0) {
617 _ReadThread
.Queue
.Count
> 0) {
618 data
= (string)(_ReadThread
.Queue
.Dequeue());
621 if (data
!= null && data
.Length
> 0) {
623 Logger
.Queue
.Debug("read: \""+data
+"\"");
625 if (OnReadLine
!= null) {
626 OnReadLine(this, new ReadLineEventArgs(data
));
630 if (IsConnectionError
&&
631 OnConnectionError
!= null) {
632 OnConnectionError(this, EventArgs
.Empty
);
641 /// <param name="data"></param>
642 /// <param name="priority"></param>
643 public void WriteLine(string data
, Priority priority
)
645 if (priority
== Priority
.Critical
) {
647 throw new NotConnectedException();
652 ((Queue
)_SendBuffer
[priority
]).Enqueue(data
);
659 /// <param name="data"></param>
660 public void WriteLine(string data
)
662 WriteLine(data
, Priority
.Medium
);
665 private bool _WriteLine(string data
)
669 _Writer
.Write(data
+"\r\n");
671 } catch (IOException
) {
673 Logger
.Socket
.Warn("sending data failed, connection lost");
675 IsConnectionError
= true;
677 } catch (ObjectDisposedException
) {
679 Logger
.Socket
.Warn("sending data failed (stream error), connection lost");
681 IsConnectionError
= true;
686 Logger
.Socket
.Debug("sent: \""+data
+"\"");
688 if (OnWriteLine
!= null) {
689 OnWriteLine(this, new WriteLineEventArgs(data
));
697 private void _NextAddress()
700 if (_CurrentAddress
>= _AddressList
.Length
) {
704 Logger
.Connection
.Info("set server to: "+Address
);
708 private void _SimpleParser(object sender
, ReadLineEventArgs args
)
710 string rawline
= args
.Line
;
711 string[] rawlineex
= rawline
.Split(new char[] {' '}
);
712 string messagecode
= "";
714 if (rawline
[0] == ':') {
715 messagecode
= rawlineex
[1];
717 ReplyCode replycode
= ReplyCode
.Null
;
719 replycode
= (ReplyCode
)int.Parse(messagecode
);
720 } catch (FormatException
) {
723 if (replycode
!= ReplyCode
.Null
) {
725 case ReplyCode
.Welcome
:
726 _IsRegistered
= true;
728 Logger
.Connection
.Info("logged in");
733 switch (rawlineex
[1]) {
735 DateTime now
= DateTime
.Now
;
736 _LastPongReceived
= now
;
737 _Lag
= now
- _LastPingSent
;
740 Logger
.Connection
.Debug("PONG received, took: "+_Lag
.TotalMilliseconds
+" ms");
746 messagecode
= rawlineex
[0];
747 switch (messagecode
) {
749 IsConnectionError
= true;
755 private void _OnConnectionError(object sender
, EventArgs e
)
759 // lets try to recover the connection
762 // make sure we clean up
765 } catch (ConnectionException
) {
772 private class ReadThread
774 private IrcConnection _Connection
;
775 private Thread _Thread
;
776 private Queue _Queue
= Queue
.Synchronized(new Queue());
787 /// <param name="connection"></param>
788 public ReadThread(IrcConnection connection
)
790 _Connection
= connection
;
798 _Thread
= new Thread(new ThreadStart(_Worker
));
799 _Thread
.Name
= "ReadThread ("+_Connection
.Address
+":"+_Connection
.Port
+")";
800 _Thread
.IsBackground
= true;
811 _Connection
._Reader
.Close();
812 } catch (ObjectDisposedException
) {
816 private void _Worker()
819 Logger
.Socket
.Debug("ReadThread started");
824 while (_Connection
.IsConnected
&&
825 ((data
= _Connection
._Reader
.ReadLine()) != null)) {
826 _Queue
.Enqueue(data
);
828 Logger
.Socket
.Debug("received: \""+data
+"\"");
831 } catch (IOException e
) {
833 Logger
.Socket
.Warn("IOException: "+e
.Message
);
837 Logger
.Socket
.Warn("connection lost");
839 _Connection
.IsConnectionError
= true;
841 } catch (ThreadAbortException
) {
844 Logger
.Socket
.Debug("ReadThread aborted");
853 private class WriteThread
855 private IrcConnection _Connection
;
856 private Thread _Thread
;
857 private int _HighCount
;
858 private int _AboveMediumCount
;
859 private int _MediumCount
;
860 private int _BelowMediumCount
;
861 private int _LowCount
;
862 private int _AboveMediumSentCount
;
863 private int _MediumSentCount
;
864 private int _BelowMediumSentCount
;
865 private int _AboveMediumThresholdCount
= 4;
866 private int _MediumThresholdCount
= 2;
867 private int _BelowMediumThresholdCount
= 1;
868 private int _BurstCount
;
873 /// <param name="connection"></param>
874 public WriteThread(IrcConnection connection
)
876 _Connection
= connection
;
884 _Thread
= new Thread(new ThreadStart(_Worker
));
885 _Thread
.Name
= "WriteThread ("+_Connection
.Address
+":"+_Connection
.Port
+")";
886 _Thread
.IsBackground
= true;
897 _Connection
._Writer
.Close();
898 } catch (ObjectDisposedException
) {
902 private void _Worker()
905 Logger
.Socket
.Debug("WriteThread started");
909 while (_Connection
.IsConnected
) {
911 Thread
.Sleep(_Connection
._SendDelay
);
913 } catch (IOException e
) {
915 Logger
.Socket
.Warn("IOException: "+e
.Message
);
919 Logger
.Socket
.Warn("connection lost");
921 _Connection
.IsConnectionError
= true;
923 } catch (ThreadAbortException
) {
926 Logger
.Socket
.Debug("WriteThread aborted");
931 #region WARNING: complex scheduler, don't even think about changing it!
932 // WARNING: complex scheduler, don't even think about changing it!
933 private void _CheckBuffer()
935 // only send data if we are succefully registered on the IRC network
936 if (!_Connection
._IsRegistered
) {
940 _HighCount
= ((Queue
)_Connection
._SendBuffer
[Priority
.High
]).Count
;
941 _AboveMediumCount
= ((Queue
)_Connection
._SendBuffer
[Priority
.AboveMedium
]).Count
;
942 _MediumCount
= ((Queue
)_Connection
._SendBuffer
[Priority
.Medium
]).Count
;
943 _BelowMediumCount
= ((Queue
)_Connection
._SendBuffer
[Priority
.BelowMedium
]).Count
;
944 _LowCount
= ((Queue
)_Connection
._SendBuffer
[Priority
.Low
]).Count
;
946 if (_CheckHighBuffer() &&
947 _CheckAboveMediumBuffer() &&
948 _CheckMediumBuffer() &&
949 _CheckBelowMediumBuffer() &&
951 // everything is sent, resetting all counters
952 _AboveMediumSentCount
= 0;
953 _MediumSentCount
= 0;
954 _BelowMediumSentCount
= 0;
958 if (_BurstCount
< 3) {
964 private bool _CheckHighBuffer()
966 if (_HighCount
> 0) {
967 string data
= (string)((Queue
)_Connection
._SendBuffer
[Priority
.High
]).Dequeue();
968 if (_Connection
._WriteLine(data
) == false) {
970 Logger
.Queue
.Warn("Sending data was not sucessful, data is requeued!");
972 ((Queue
)_Connection
._SendBuffer
[Priority
.High
]).Enqueue(data
);
975 if (_HighCount
> 1) {
976 // there is more data to send
984 private bool _CheckAboveMediumBuffer()
986 if ((_AboveMediumCount
> 0) &&
987 (_AboveMediumSentCount
< _AboveMediumThresholdCount
)) {
988 string data
= (string)((Queue
)_Connection
._SendBuffer
[Priority
.AboveMedium
]).Dequeue();
989 if (_Connection
._WriteLine(data
) == false) {
991 Logger
.Queue
.Warn("Sending data was not sucessful, data is requeued!");
993 ((Queue
)_Connection
._SendBuffer
[Priority
.AboveMedium
]).Enqueue(data
);
995 _AboveMediumSentCount
++;
997 if (_AboveMediumSentCount
< _AboveMediumThresholdCount
) {
1005 private bool _CheckMediumBuffer()
1007 if ((_MediumCount
> 0) &&
1008 (_MediumSentCount
< _MediumThresholdCount
)) {
1009 string data
= (string)((Queue
)_Connection
._SendBuffer
[Priority
.Medium
]).Dequeue();
1010 if (_Connection
._WriteLine(data
) == false) {
1012 Logger
.Queue
.Warn("Sending data was not sucessful, data is requeued!");
1014 ((Queue
)_Connection
._SendBuffer
[Priority
.Medium
]).Enqueue(data
);
1018 if (_MediumSentCount
< _MediumThresholdCount
) {
1026 private bool _CheckBelowMediumBuffer()
1028 if ((_BelowMediumCount
> 0) &&
1029 (_BelowMediumSentCount
< _BelowMediumThresholdCount
)) {
1030 string data
= (string)((Queue
)_Connection
._SendBuffer
[Priority
.BelowMedium
]).Dequeue();
1031 if (_Connection
._WriteLine(data
) == false) {
1033 Logger
.Queue
.Warn("Sending data was not sucessful, data is requeued!");
1035 ((Queue
)_Connection
._SendBuffer
[Priority
.BelowMedium
]).Enqueue(data
);
1037 _BelowMediumSentCount
++;
1039 if (_BelowMediumSentCount
< _BelowMediumThresholdCount
) {
1047 private bool _CheckLowBuffer()
1049 if (_LowCount
> 0) {
1050 if ((_HighCount
> 0) ||
1051 (_AboveMediumCount
> 0) ||
1052 (_MediumCount
> 0) ||
1053 (_BelowMediumCount
> 0)) {
1057 string data
= (string)((Queue
)_Connection
._SendBuffer
[Priority
.Low
]).Dequeue();
1058 if (_Connection
._WriteLine(data
) == false) {
1060 Logger
.Queue
.Warn("Sending data was not sucessful, data is requeued!");
1062 ((Queue
)_Connection
._SendBuffer
[Priority
.Low
]).Enqueue(data
);
1065 if (_LowCount
> 1) {
1072 // END OF WARNING, below this you can read/change again ;)
1079 private class IdleWorkerThread
1081 private IrcConnection _Connection
;
1082 private Thread _Thread
;
1087 /// <param name="connection"></param>
1088 public IdleWorkerThread(IrcConnection connection
)
1090 _Connection
= connection
;
1098 DateTime now
= DateTime
.Now
;
1099 _Connection
._LastPingSent
= now
;
1100 _Connection
._LastPongReceived
= now
;
1102 _Thread
= new Thread(new ThreadStart(_Worker
));
1103 _Thread
.Name
= "IdleWorkerThread ("+_Connection
.Address
+":"+_Connection
.Port
+")";
1104 _Thread
.IsBackground
= true;
1116 private void _Worker()
1119 Logger
.Socket
.Debug("IdleWorkerThread started");
1122 while (_Connection
.IsConnected
) {
1123 if (_Connection
.IsRegistered
) {
1124 DateTime now
= DateTime
.Now
;
1125 int last_ping_sent
= (int)(now
- _Connection
._LastPingSent
).TotalSeconds
;
1126 int last_pong_rcvd
= (int)(now
- _Connection
._LastPongReceived
).TotalSeconds
;
1127 // determins if the resoponse time is ok
1128 if (last_ping_sent
< _Connection
._PingTimeout
) {
1129 // determines if it need to send another ping yet
1130 if (last_pong_rcvd
> _Connection
._PingInterval
) {
1131 _Connection
.WriteLine(Rfc2812
.Ping(_Connection
.Address
), Priority
.Critical
);
1132 _Connection
._LastPingSent
= now
;
1133 _Connection
._LastPongReceived
= now
;
1134 } // else connection is fine, just continue
1137 Logger
.Socket
.Warn("ping timeout, connection lost");
1139 _Connection
.IsConnectionError
= true;
1143 Thread
.Sleep(_Connection
._IdleWorkerInterval
);
1145 } catch (ThreadAbortException
) {
1146 Thread
.ResetAbort();
1148 Logger
.Socket
.Debug("IdleWorkerThread aborted");