The Problem Obvious answer was that when connecting, you are supposed to fill out the sockaddr structure yourself. There is apparently no API for this, and my attempts to find one above just sent me down a rabbit hole that returned a const sockaddr structure without a port field. This is not the only variant of the sockaddr structure, however. There are also sockaddr_in and sockaddr_in6 which are both more suitable for this use. I was able to make my own struct, copy in the bits the OS provided then set the port and move on. I'm sure it is entirely understood by the experts in the art just how crufty this is by current API standards so I won't bedevil the point but at least in my newbie perspective this and the ridiculous endianness patch for the port was on the level of "Don't drink the water" and "Don't feed the grizzly bears" -- the sort of cultural information that your language professor reveals with evident glee because it justifies perpetual employment in any economy, that would otherwise be a unwelcome trap for the strangers in a strange land, to the level of "Why would I even want to visit?" had they known. I'm not sure this has a place in well designed API, but it is culture at this point, I am sure, and obviously not under Apple's control.
In any event, this seems to work for me, should any other woe begotten travelers find themselves detoured on this path.
// My DNSServiceGetAddrInfoReply
void ServiceList::Node::AddressInfoCallback( DNSServiceRef __nonnull _sdRef,
DNSServiceFlags _flags,
uint32_t _interfaceIndex,
DNSServiceErrorType _errorCode,
const char * __nullable _hostname,
const struct sockaddr * __nullable _address,
uint32_t UNUSED _ttl, void * __nonnull context)
{
AddrInfo * info = (AddrInfo*) context;
if( kDNSServiceErr_NoError != _errorCode || NULL == _hostname || NULL == _address)
{
LOG_ERROR("Failed to get address info on \"%s\"\n", (const char*) info->hostTarget);
delete info;
return;
}
// set the port
union {
sockaddr_in in;
sockaddr_in6 in6;
} addrs; memset( &addrs, 0, sizeof(addrs));
socklen_t addrsSize = 0;
switch( _address->sa_len)
{
case sizeof( sockaddr_in):
addrsSize = sizeof(addrs.in);
memcpy( &addrs.in, _address, addrsSize);
addrs.in.sin_port = htons(info->port); // big endian. Because, obviously...
break;
case sizeof( sockaddr_in6):
addrsSize = sizeof(addrs.in6);
memcpy( &addrs.in6, _address, addrsSize);
addrs.in6.sin6_port = htons(info->port);
break;
default:
LOG_ERROR("Unhandled sockaddr variant");
return;
}
int err = connect(info->socket, (sockaddr*) &addrs, addrsSize);
....