Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

blueillusion

macrumors member
Original poster
Aug 18, 2008
56
3
I'm trying to implement automatic port forwarding using apples bonjour services.

The specific function im using is: http://developer.apple.com/library/...ple_ref/c/func/DNSServiceNATPortMappingCreate

At the moment, all Im trying to do is call the function so that I can get my external ip address.

I call the function appropriately, it returns success, but my callback is never called. Without the callback, I cant get my external ip.

The calling code is:

Code:
DNSServiceErrorType rError = DNSServiceNATPortMappingCreate(&externalIPServiceRef, 0, 0, 0, 0, 0, 0, portmap_cb, NULL);
    
    if(rError != kDNSServiceErr_NoError)
    {
        switch(rError)
        {
            case kDNSServiceErr_NATPortMappingDisabled:
                NSLog(@"Portmapping on your router is disabled");
                break;
            case kDNSServiceErr_NATPortMappingUnsupported:
                NSLog(@"Portmapping is unsupported on your router");
                break;
            case kDNSServiceErr_NoRouter:
                NSLog(@"You don't have a router");
                break;
            default:
                NSLog(@"Error Code: %d", rError);
        }
    }

Where externalIPServiceRef is just an uninitialized DNSServiceRef struct.

My callback looks like:

Code:
void DC_PortmapReply(DNSServiceRef sdRef, 
                         DNSServiceFlags flags, 
                         uint32_t interfaceIndex, 
                         DNSServiceErrorType errorCode, 
                         uint32_t externalAddress, /* four byte IPv4 address in network byte order */
                         DNSServiceProtocol protocol, 
                         uint16_t internalPort, 
                         uint16_t externalPort, /* may be different than the requested port     */
                         uint32_t ttl, /* may be different than the requested ttl      */
                         void *context)
{    
    if(errorCode != kDNSServiceErr_NoError)
    {
        NSLog(@"Error in callback");
        return;
    }
    
    NSLog(@"In Portmap Reply");
    
    switch(protocol)
    {
        case 0:
        {
            char addrStr[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, &externalAddress, addrStr, INET_ADDRSTRLEN);
            NSString *networkString = [[NSString alloc] initWithUTF8String:addrStr];
            NSNumber *hostNumber = [[NSNumber alloc] initWithUnsignedInteger:externalAddress];
            NSDictionary *d = [[NSDictionary alloc] initWithObjectsAndKeys:networkString, @"networkString", hostNumber, @"hostNumber", nil];
            [[NSNotificationCenter defaultCenter] postNotificationName:DCNetworkAddressNotification object:networkString userInfo:d];
            [networkString release];
            [hostNumber release];
            [d release];
        }
            break;
        case kDNSServiceProtocol_TCP:
            break;
    }
}

However, the callback is never called. Does anyone have any experience with using nat-pmp?
 
Code:
DNSServiceErrorType rError =
  DNSServiceNATPortMappingCreate(
    &externalIPServiceRef, 0, 0, 0, 0, 0, 0, 
    [COLOR=red]portmap_cb[/COLOR], NULL);

Code:
void [COLOR=red]DC_PortmapReply[/COLOR](DNSServiceRef sdRef, 
                         DNSServiceFlags flags, 
                         uint32_t interfaceIndex, 
                         DNSServiceErrorType errorCode, 
                         uint32_t externalAddress,
                         DNSServiceProtocol protocol, 
                         uint16_t internalPort, 
                         uint16_t externalPort,
                         uint32_t ttl,
                         void *context)

The two highlighted identifiers don't match. Shouldn't they?
 
Oops, i forgot to post another piece of code.

In one of my class initializers i do:

Code:
portmap_cb = &DC_PortmapReply;

Which portmap_cb is defined as
Code:
DNSServiceNATPortMappingReply portmap_cb

I've also skipped using the intermediate variable above, and plugged the function name directly into the call DNSServiceNATPortMappingCreate, but nothing happens either.
 
I just tried out the Portmapper sample code you provided, and it execute the callbacks as it should.

After looking carefully at the PortMapper code, It seems that you need to open a socket for a specific DNSService context.

This makes sense, as you definitely would need to get the requested results from a socket. However this wasn't documented, and I assumed that the dns_sd functions would do that for me.

However now i know!

Thanks for pointing me to that code.

(by the way, this is running on lion)
 
Thanks for pointing me to that code.

All I did was google the function you named, and added a site-specific search qualifier. So the search terms were:
DNSServiceNATPortMappingCreate site:developer.apple.com

There were only two results, and one was PortMapper.

For reference, the PortMapper class is a wrapper around the port-mapping and bonjour functions, because some of them are not documented or are poorly documented (in PortMapper's README file). So if I were doing this task, I would probably just use the PortMapper class as-is.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.