I ended up having to implement this earlier today; here’s the code I came up with. “_inputStream” is an NSInputStream opened on a TCP socket. Disclaimer: I haven’t tested it much yet, and not at all with IPv6 addresses.
- (NSString*) remoteHost {
// First recover the socket handle from the stream:
NSData* handleData = CFBridgingRelease(CFReadStreamCopyProperty(
(__bridge CFReadStreamRef)_inputStream,
kCFStreamPropertySocketNativeHandle));
if (!handleData || handleData.length != sizeof(CFSocketNativeHandle))
return nil;
CFSocketNativeHandle socketHandle = *(const CFSocketNativeHandle*)handleData.bytes;
// Get the remote/peer address in binary form:
struct sockaddr_in addr;
unsigned addrLen = sizeof(addr);
if (getpeername(socketHandle, (struct sockaddr*)&addr,&addrLen) < 0)
return nil;
// Format it in readable (e.g. dotted-quad) form, with the port number:
char nameBuf[INET6_ADDRSTRLEN];
if (inet_ntop(addr.sin_family, &addr.sin_addr, nameBuf, (socklen_t)sizeof(nameBuf)) == NULL)
return nil;
return [NSString stringWithFormat: @"%s:%hu", nameBuf, ntohs(addr.sin_port)];
}