Is it possible to activate TCP keepalive on Apple iOS devices

ios, iphone, sockets, tcp

Solution

see: http://en.wikipedia.org/wiki/Keepalive#TCP_keepalive

Usually, keepalive time (`net.inet.tcp.keepidle`) is 7200sec by default. I don't know that is true in iOS or not, but "no less than 2 hours" is clearly required by RFC 1122.

This interval MUST be configurable and MUST default to no less than two hours.

So, how could you configure it in your application? try:

#import <sys/types.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <netinet/tcp.h>

int on = 1;
int delay = 120;
setsockopt(socket_handle, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
setsockopt(socket_handle, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay));

see `man tcp`.

I confirmed this works on iOS Simulator (iPhone 5s / iOS 8.0).

Problem

Apple device === Router === WiFi module Apple device(iPhone) is connecting to WiFi module port 2000 with TCP connection. I want to activate TCP keepalive packet sending on Apple device to find out when TCP connection to WiFi module is lost (module is switched off). My stream setup ``` CFReadStreamRef readStream; CFWriteStreamRef writeStream; CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)CFBridgingRetain(moduleIPaddress), port2000, &readStream, &writeStream); outputStream = (NSOutputStream *)CFBridgingRelease(writeStream); inputStream = (NSInputStream *)CFBridgingRelease(readStream); [outputStream setDelegate:(id)self]; [inputStream setDelegate:(id)self]; [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [outputStream open]; [inputStream open]; ``` I tried to activate keepalive according to David H post Keeping socket connection alive in iOS ``` - (void) stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent { switch (streamEvent) { case NSStreamEventOpenCompleted: if (theStream == outputStream) { /* CFDataRef data = (CFDataRef)CFWriteStreamCopyProperty((__bridge CFWriteStreamRef)theStream, kCFStreamPropertySocketNativeHandle); if(data) { CFSocketNativeHandle socket_handle = *(CFSocketNativeHandle *)CFDataGetBytePtr(data); CFRelease(data); NSLog(@"SOCK HANDLE: %x", socket_handle); //Enabling keep alive int opt = 1; if( setsockopt( socket_handle, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof( opt ) ) < 0 ) { NSLog(@"Yikes 2: failed to set keepalive! ERRNO: %s", strerror(errno)); } } */ NSData *data = (NSData *)[theStream propertyForKey:(__bridge NSString *)kCFStreamPropertySocketNativeHandle]; if(data) { CFSocketNativeHandle socket_handle = *(CFSocketNativeHandle *)[data bytes]; NSLog(@"SOCK HANDLE: %x", socket_handle); //Enabling keep alive int opt = 1; if( setsockopt( socket_handle, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof( opt ) ) < 0 ) { NSLog(@"Yikes 2: failed to set keepalive! ERRNO: %s", strerror(errno)); } } } ``` Both options print out SOCK HANDLE: 9 , no error messages. When WiFi module is switched off connection still stays open for 30 minutes or more when I do not send data to outputstream. If I send data to outputstream I get NSStreamEventErrorOccurred - Error Domain=NSPOSIXErrorDomain Code=60 "The operation couldn’t be completed. Operation timed out" after around 60 seconds. I tried this with Apple device. When I tried with iOS Simulator I did not see keepalive packets with Wireshark. NSStream tcp keepalive in iOS also describes keepalive setup. Martin R example code activates keepalive for inputstream that seems wrong. Is it possible to activate TCP keepalive on Apple iOS devices like iPhone (should be according to David H)? If it is possible how it should be done (what is missing from my code)?

Original source

Related problems