2

I'm using Apple's TCPServer class to open a socket on listen from incoming connection. Here is the callback that get called when someone connect on the listening socket:

static void TCPServerAcceptCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
TCPServer *server = (TCPServer *)info;
if (kCFSocketAcceptCallBack == type) { 
    // for an AcceptCallBack, the data parameter is a pointer to a CFSocketNativeHandle
    CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data;
    uint8_t name[SOCK_MAXADDRLEN];
    socklen_t namelen = sizeof(name);
    NSData *peer = nil;
    if (0 == getpeername(nativeSocketHandle, (struct sockaddr *)name, &namelen)) {
        peer = [NSData dataWithBytes:name length:namelen];
    }

    CFReadStreamRef readStream = NULL;
    CFWriteStreamRef writeStream = NULL;
    CFStreamCreatePairWithSocket(kCFAllocatorDefault, nativeSocketHandle, &readStream, &writeStream);
    if (readStream && writeStream) {
        CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
        CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
        [server handleNewConnectionFromAddress:peer inputStream:(NSInputStream *)readStream outputStream:(NSOutputStream *)writeStream];
    } else {
        // on any failure, need to destroy the CFSocketNativeHandle 
        // since we are not going to use it any more
        close(nativeSocketHandle);
    }
    if (readStream) CFRelease(readStream);
    if (writeStream) CFRelease(writeStream);
}
}

Is there any way to get the hostname of the device which is connecting ? Regards, Kosa

[EDIT] I tried something like this to extract the ip:

struct sockaddr_in *s = (struct sockaddr_in*)name;
char *ipstr = malloc(INET_ADDRSTRLEN);         
ipstr = inet_ntoa(s->sin_addr);

NSLog(@"ip = %s", ipstr);

But it gives me 0.0.0.0.

[EDIT] Still working on it and still no success. According to apple's doc the address parameter is:

A CFData object holding the contents of a struct sockaddr appropriate for the protocol family of s (struct sockaddr_in or struct sockaddr_in6, for example), identifying the remote address to which s is connected. This value is NULL except for kCFSocketAcceptCallBack and kCFSocketDataCallBack callbacks.

However I can't extract any other IP than 132.20.0.1 (which is obviously not the IP I'm expecting) I'm really confused and it would be great if someone could help me with that !

rmonjo
  • 2,675
  • 5
  • 30
  • 37
  • Where is `TCPServer` defined? – trojanfoe Jul 02 '12 at 14:00
  • TCPServer is the class holding this static method. It can be found in the "witap" sample project in the iOS dev center. – rmonjo Jul 02 '12 at 14:16
  • And where is this callback used? I can only see the use of `TCPServerDelegate`. – trojanfoe Jul 02 '12 at 14:19
  • the: "[server handleNewConnectionFromAddress:peer inputStream:(NSInputStream *)readStream outputStream:(NSOutputStream *)writeStream];" calls a delegate method. Do you know if there is anyway to get the hostname of the incoming connection from here ? The rest of the code doesn't contain any useful stuff to get it. – rmonjo Jul 02 '12 at 14:24

1 Answers1

2

After trying to follow your way to get the address I came up with a slight variant of your code that is working for me. This code is working if you are dealing with IPv6 addresses but it is easy to change to work with IPv4. I will have to change the code to work with both anyway.

- (void)getPublicClientAddress {
    // Get public IP from stream

    // Get hands on appropriate data structures via the socket number
    CFSocketNativeHandle nativeSocketHandle = _socketnumber;
    uint8_t name[SOCK_MAXADDRLEN];
    socklen_t namelen = sizeof(name);
    NSData *peer = nil;
    if (0 == getpeername(nativeSocketHandle, (struct sockaddr *)name, &namelen)) {
        peer = [NSData dataWithBytes:name length:namelen];
    }

    // TODO distiguish between ipv4 and ipv6
    struct sockaddr_in6 *s = (struct sockaddr_in6*)name;

    // convert ip to string
    char *ipstr = malloc(INET6_ADDRSTRLEN);
    struct in6_addr *ipv6addr = &s->sin6_addr;  // used pointer here, but that really should make no difference
    inet_ntop(AF_INET6, ipv6addr, ipstr, sizeof(ipstr)); // used a different function here

    // convert port to int
    int portnumber = s->sin6_port;

    // Save in properties
    _publicIP   = [NSString stringWithFormat:@"%s", ipstr];
    _publicPort = [NSString stringWithFormat:@"%d", portnumber];
}

So this code is working for me and I hope that it might help someone who stumbles upon this post while searching for an answer.

Jashugan
  • 323
  • 1
  • 4
  • 17