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 send
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).
Thank you rintaro for directing me to right direction.
Stream setup stayed the same as in my question. I tested different setups and did not find difference between socket handle detection examples described in my question.
Code that activates keepalive with iPod device and iOS 7.1
case NSStreamEventOpenCompleted:
@try {
if (theStream == outputStream)
{
NSData *data = (NSData *)[theStream propertyForKey:(__bridge NSString *)kCFStreamPropertySocketNativeHandle];
if(data)
{
CFSocketNativeHandle socket_handle = *(CFSocketNativeHandle *)[data bytes];
//NSLog(@"SOCK HANDLE: %x", socket_handle);
//SO_KEEPALIVE option to activate
int option = 1;
//TCP_NODELAY option to activate
int option2 = 1;
//Idle time used when SO_KEEPALIVE is enabled. Sets how long connection must be idle before keepalive is sent
int keepaliveIdle = 10;
//Interval between keepalives when there is no reply. Not same as idle time
int keepaliveIntvl = 2;
//Number of keepalives before close (including first keepalive packet)
int keepaliveCount = 4;
//Time after which tcp packet retransmissions will be stopped and the connection will be dropped.Stream is closed
int retransmissionTimeout = 5;
if (setsockopt(socket_handle, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof (int)) == -1)
{
NSLog(@"setsockopt SO_KEEPALIVE failed: %s", strerror(errno));
}else
{
NSLog(@"setsockopt SO_KEEPALIVE ok");
}
if (setsockopt(socket_handle, IPPROTO_TCP, TCP_KEEPCNT, &keepaliveCount, sizeof(int)) == -1)
{
NSLog(@"setsockopt TCP_KEEPCNT failed: %s", strerror(errno));
}else
{
NSLog(@"setsockopt TCP_KEEPCNT ok");
}
if (setsockopt(socket_handle, IPPROTO_TCP, TCP_KEEPALIVE, &keepaliveIdle, sizeof(int)) == -1)
{
NSLog(@"setsockopt TCP_KEEPALIVE failed: %s", strerror(errno));
}else
{
NSLog(@"setsockopt TCP_KEEPALIVE ok");
}
if (setsockopt(socket_handle, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveIntvl, sizeof(int)) == -1)
{
NSLog(@"setsockopt TCP_KEEPINTVL failed: %s", strerror(errno));
}else
{
NSLog(@"setsockopt TCP_KEEPINTVL ok");
}
if (setsockopt(socket_handle, IPPROTO_TCP, TCP_RXT_CONNDROPTIME, &retransmissionTimeout, sizeof(int)) == -1)
{
NSLog(@"setsockopt TCP_RXT_CONNDROPTIME failed: %s", strerror(errno));
}else
{
NSLog(@"setsockopt TCP_RXT_CONNDROPTIME ok");
}
if (setsockopt(socket_handle, IPPROTO_TCP, TCP_NODELAY, &option2, sizeof(int)) == -1)
{
NSLog(@"setsockopt TCP_NODELAY failed: %s", strerror(errno));
}else
{
NSLog(@"setsockopt TCP_NODELAY ok");
}
}
}
When TCP connection is idle, app starts to send keepalive after 10 second intervals. When there is no answer, app starts to send keepalive packets with 2 second interval and closes stream when there is 4 keepalive packets without reply. This means that when WiFi module is turned off after successful keepalive exchange it takes maximum 18 seconds on idle to close stream when connection is lost.
Another parameter is retransmission timeout value. Default seems to be around 6 seconds. This timer starts when there is first packet retransmission. App tries to retransmit packet but if packet retransmission fails during 5 seconds stream is closed.
NB! Different results in device and simulator.
iPod settings activation log
Simulator settings activation log
This means that it is not possible to activate and trace with iOS simulator. I did not find why error message "Protocol not available" is displayed in simulator.