diff --git a/src/IRCConnection.h b/src/IRCConnection.h index 0ee023d..7c72deb 100644 --- a/src/IRCConnection.h +++ b/src/IRCConnection.h @@ -82,6 +82,9 @@ OFMutableDictionary *_channels; id _delegate; of_string_encoding_t _fallbackEncoding; + of_time_interval_t _pingInterval, _pingTimeout; + OFString *_pingData; + OFTimer *_pingTimer; } @property (assign) Class socketClass; @@ -91,6 +94,7 @@ @property (assign) id delegate; @property (readonly, retain) OFTCPSocket *socket; @property of_string_encoding_t fallbackEncoding; +@property of_time_interval_t pingInterval, pingTimeout; + (instancetype)connection; - (void)sendLine: (OFString*)line; diff --git a/src/IRCConnection.m b/src/IRCConnection.m index 9b52980..25817fa 100644 --- a/src/IRCConnection.m +++ b/src/IRCConnection.m @@ -43,6 +43,7 @@ @synthesize nickname = _nickname, username = _username, realname = _realname; @synthesize delegate = _delegate, socket = _socket; @synthesize fallbackEncoding = _fallbackEncoding; +@synthesize pingInterval = _pingInterval, pingTimeout = _pingTimeout; + (instancetype)connection { @@ -58,6 +59,8 @@ _channels = [[OFMutableDictionary alloc] init]; _port = 6667; _fallbackEncoding = OF_STRING_ENCODING_ISO_8859_1; + _pingInterval = 120; + _pingTimeout = 30; } @catch (id e) { [self release]; @throw e; @@ -74,6 +77,8 @@ [_username release]; [_realname release]; [_channels release]; + [_pingData release]; + [_pingTimer release]; [super dealloc]; } @@ -249,6 +254,19 @@ return; } + /* PONG */ + if ([components count] == 4 && + [[components objectAtIndex: 1] isEqual: @"PONG"] && + [[components objectAtIndex: 3] isEqual: _pingData]) { + [_pingTimer invalidate]; + + [_pingData release]; + [_pingTimer release]; + + _pingData = nil; + _pingTimer = nil; + } + action = [[components objectAtIndex: 1] uppercaseString]; /* Connected */ @@ -257,6 +275,11 @@ @selector(connectionWasEstablished:)]) [_delegate connectionWasEstablished: self]; + [OFTimer scheduledTimerWithTimeInterval: _pingInterval + target: self + selector: @selector(IRC_sendPing) + repeats: true]; + return; } @@ -527,6 +550,31 @@ } } +- (void)IRC_sendPing +{ + [_pingData release]; + [_pingTimer release]; + + _pingData = [[OFString alloc] initWithFormat: @":%d", rand()]; + [_socket writeFormat: @"PING %@\r\n", _pingData]; + + _pingTimer = [[OFTimer + scheduledTimerWithTimeInterval: _pingTimeout + target: self + selector: @selector(IRC_pingTimeout) + repeats: false] retain]; +} + +- (void)IRC_pingTimeout +{ + if ([_delegate respondsToSelector: @selector(connectionWasClosed:)]) + [_delegate connectionWasClosed: self]; + + [_socket cancelAsyncRequests]; + [_socket release]; + _socket = nil; +} + - (void)processLine: (OFString*)line { void *pool = objc_autoreleasePoolPush(); @@ -570,11 +618,14 @@ return false; } - if ([_delegate respondsToSelector: @selector(connectionWasClosed:)]) { + if ([_delegate respondsToSelector: @selector(connectionWasClosed:)]) [_delegate connectionWasClosed: self]; - [_socket release]; - _socket = nil; - } + + [_pingTimer invalidate]; + + [_socket cancelAsyncRequests]; + [_socket release]; + _socket = nil; return false; } diff --git a/tests/tests.m b/tests/tests.m index eed7c20..51a2ee4 100644 --- a/tests/tests.m +++ b/tests/tests.m @@ -138,4 +138,11 @@ OF_APPLICATION_DELEGATE(TestApp) of_log(@"Users in %@: %@", channel, [connection usersInChannel: channel]); } + +- (void)connectionWasClosed: (IRCConnection*)connection +{ + of_log(@"Disconnected!"); + + [OFApplication terminate]; +} @end