I'm having a problem with EPIPE in my iOS app, and it's not being caught in the @try/@catch/@finally block. How can I catch this signal (SIGPIPE, likely)...
I've built a "web proxy" into my app that will handle certain kinds of URLs - in this error case, it seems that the remote end (also in my app, but hiding in the iOS libraries) closes its end of the socket. I don't get a notification (should I? Is there something I should register for with the NSFileHandle that might help here?).
I've based this proxy on HTTPServer that Matt Gallagher put together (available here), and the problem is in a subclass of the HTTPRequestHandler
class he put together. Here's the code (this code is the equivalent of the startResponse
method in the base class):
-(void)proxyTS:(SSProxyTSResource *)proxyTS didReceiveResource:(NSData *)resource
{
NSLog(@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
CFHTTPMessageRef response =
CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1);
CFHTTPMessageSetHeaderFieldValue(response,
(CFStringRef)@"Content-Type",
(__bridge CFStringRef)s_MIMEtype);
CFHTTPMessageSetHeaderFieldValue(response,
(CFStringRef)@"Connection",
(CFStringRef)@"close");
CFHTTPMessageSetBody(response,
(__bridge CFDataRef)resource);
CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response);
@try
{
NSLog(@" -> writing %u bytes to filehandle...",[((__bridge NSData *)headerData) length]);
[self.fileHandle writeData:(__bridge NSData *)headerData];
}
@catch (NSException *exception)
{
// Ignore the exception, it normally just means the client
// closed the connection from the other end.
}
@finally
{
NSLog(@" *ding*");
CFRelease(headerData);
CFRelease(response);
[self.server closeHandler:self];
}
}
And here's what shows up in the console log when it crashes:
Jan 15 14:55:10 AWT-NoTouch-iPhone-1 Streamer[1788] <Warning>: [SSProxyTSResponseHandler proxyTS:didReceiveResource:]
Jan 15 14:55:10 iPhone-1 Streamer[1788] <Warning>: -> writing 261760 bytes to filehandle...
Jan 15 14:55:11 iPhone-1 com.apple.launchd[1] (UIKitApplication:com.XXX.Streamer[0xf58][1788]) <Warning>: (UIKitApplication:com.XXX.Streamer[0xf58]) Exited abnormally: Broken pipe: 13
It seems that because the other end closed the pipe the write()
fails, so if someone can point me at how I can either discover that it's already closed and not try to write data to it OR whatever will make it not crash my program that would be very helpful.
signal(SIGPIPE,SIG_IGN)
) inapplication:didFinishLaunchingWithOptions:
and restoring it inapplicationWillTerminate:
. A more detailed version is below in my answer to my own question... – Alkali