source/Sources/AirPlayReceiverServer.c
static OSStatus	_UpdateBonjourAirPlay( AirPlayReceiverServerRef inServer, CFDataRef *outTXTRecord )
{
	OSStatus			err;
	TXTRecordRef		txtRec;
	uint8_t				txtBuf[ 256 ];
	const uint8_t *		txtPtr;
	uint16_t			txtLen;
	char				cstr[ 256 ];
	const char *		ptr;
	AirPlayFeatures		features;
	int					n;
	uint32_t			u32;
	uint16_t			port;
	DNSServiceFlags		flags;
	const char *		domain;
	uint32_t			ifindex;
	
	TXTRecordCreate( &txtRec, (uint16_t) sizeof( txtBuf ), txtBuf );
	
	// Device Name
	
	*cstr = '\0';
	err = AirPlayGetDeviceName( cstr, sizeof( cstr ) );
	require_noerr( err, exit );
	
	
	// DeviceID
	
	MACAddressToCString( inServer->deviceID, cstr );
	err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_DeviceID, (uint8_t) strlen( cstr ), cstr );
	require_noerr( err, exit );
	
	// Features
	
	features = AirPlayGetFeatures( inServer );
	u32 = (uint32_t)( ( features >> 32 ) & UINT32_C( 0xFFFFFFFF ) );
	if( u32 != 0 )
	{
		n = snprintf( cstr, sizeof( cstr ), "0x%X,0x%X", (uint32_t)( features & UINT32_C( 0xFFFFFFFF ) ), u32 );
	}
	else
	{
		n = snprintf( cstr, sizeof( cstr ), "0x%X", (uint32_t)( features & UINT32_C( 0xFFFFFFFF ) ) );
	}
	err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_Features, (uint8_t) n, cstr );
	require_noerr( err, exit );
	
	// FirmwareRevision
	
	*cstr = '\0';
	AirPlayGetConfigCString( inServer, CFSTR( kAirPlayKey_FirmwareRevision ), cstr, sizeof( cstr ), NULL );
	if( *cstr == '\0' )
	{
		AirPlayReceiverServerPlatformGetCString( inServer, CFSTR( kAirPlayKey_FirmwareRevision ), NULL,
												cstr, sizeof( cstr ), NULL );
	}
	
	if( *cstr != '\0' )
	{
		err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_FirmwareVersion, (uint8_t) strlen( cstr ), cstr );
		require_noerr( err, exit );
	}
	
	// Flags
	
	u32 = AirPlayGetStatusFlags( inServer );
	if( u32 != 0 )
	{
		n = snprintf( cstr, sizeof( cstr ), "0x%x", u32 );
		err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_Flags, (uint8_t) n, cstr );
		require_noerr( err, exit );
	}
	
	// Model
	
	*cstr = '\0';
	AirPlayReceiverServerPlatformGetCString( inServer, CFSTR( kAirPlayKey_Model ), NULL, cstr, sizeof( cstr ), NULL );
	if( *cstr == '\0' )
	{
		AirPlayGetDeviceModel( inServer, cstr, sizeof( cstr ) );
	}
	if( *cstr != '\0' )
	{
		err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_Model, (uint8_t) strlen( cstr ), cstr );
		require_noerr( err, exit );
	}
	
	// Protocol version
	
	ptr = kAirPlayProtocolVersionStr;
	if( strcmp( ptr, "1.0" ) != 0 )
	{
		err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_ProtocolVersion, (uint8_t) strlen( ptr ), ptr );
		require_noerr( err, exit );
	}
	
{
	char *		cptr;
	
	// Public HomeKit pairing identity
	
	err = AirPlayCopyHomeKitPairingIdentity( &cptr, NULL );
	if( !err )	
	{
		err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_PublicHKID, (uint8_t) strlen( cptr ), cptr );
		free( cptr );
		require_noerr( err, exit );
	}
	else
	{
		aprs_ulog( kLogLevelNotice, "### Add pairing HomeKit peer identifier to advertiser info failed: %#m\n", err );
	}
}
	
	// Source Version
	
	ptr = kAirPlaySourceVersionStr;
	err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_SourceVersion, (uint8_t) strlen( ptr ), ptr );
	require_noerr( err, exit );
	
	// If we're only building the TXT record then return it and exit without registering.
	
	txtPtr = TXTRecordGetBytesPtr( &txtRec );
	txtLen = TXTRecordGetLength( &txtRec );
	if( outTXTRecord )
	{
		CFDataRef		data;
		
		data = CFDataCreate( NULL, txtPtr, txtLen );
		require_action( data, exit, err = kNoMemoryErr );
		*outTXTRecord = data;
		goto exit;
	}
	
	// Update the service.
	
	if( inServer->bonjourAirPlay )
	{
		err = DNSServiceUpdateRecord( inServer->bonjourAirPlay, NULL, 0, txtLen, txtPtr, 0 );
		if( !err ) aprs_ulog( kLogLevelNotice, "Updated Bonjour TXT for %s\n", kAirPlayBonjourServiceType );
		else
		{
			// Update record failed or isn't supported so deregister to force a re-register below.
			
			aprs_ulog( kLogLevelNotice, "Bonjour TXT update failed for %s, deregistering so we can force a re-register %s\n",
					  kAirPlayBonjourServiceType );
			DNSServiceForget( &inServer->bonjourAirPlay );
		}
	}
	if( !inServer->bonjourAirPlay )
	{
		
		ptr = NULL;
		*cstr = '\0';
		AirPlayGetDeviceName( cstr, sizeof( cstr ) );
		ptr = cstr;
		
		flags = kDNSServiceFlagsKnownUnique;
		domain = kAirPlayBonjourServiceDomain;
		
		port = (uint16_t) _GetListenPort( inServer );
		require_action( port > 0, exit, err = kInternalErr );
		
		ifindex = kDNSServiceInterfaceIndexAny;
		if( *inServer->ifname != '\0' )
		{
			ifindex = if_nametoindex( inServer->ifname );
			require_action_quiet( ifindex != 0, exit, err = kNotFoundErr );
		}
		err = DNSServiceRegister( &inServer->bonjourAirPlay, flags, ifindex, ptr, kAirPlayBonjourServiceType, domain, NULL,
								 htons( port ), txtLen, txtPtr, _BonjourRegistrationHandler, inServer );
		require_noerr_quiet( err, exit );
		
		aprs_ulog( kLogLevelNotice, "Registering Bonjour %s port %d\n", kAirPlayBonjourServiceType, port );
	}
	
exit:
	TXTRecordDeallocate( &txtRec );
	return( err );
}
//===========================================================================================================================
//	_UpdateBonjourAirPlay
//
//	Update Bonjour for the _airplay._tcp service.
//===========================================================================================================================
_UpdateBonjourAirPlay
Update Bonjour for the _airplay._tcp service.
_UpdateBonjourAirPlay Update Bonjour for the _airplay . _tcp service .
static OSStatus	_UpdateBonjourAirPlay( AirPlayReceiverServerRef inServer, CFDataRef *outTXTRecord )
{
	OSStatus			err;
	TXTRecordRef		txtRec;
	uint8_t				txtBuf[ 256 ];
	const uint8_t *		txtPtr;
	uint16_t			txtLen;
	char				cstr[ 256 ];
	const char *		ptr;
	AirPlayFeatures		features;
	int					n;
	uint32_t			u32;
	uint16_t			port;
	DNSServiceFlags		flags;
	const char *		domain;
	uint32_t			ifindex;
	TXTRecordCreate( &txtRec, (uint16_t) sizeof( txtBuf ), txtBuf );
	*cstr = '\0';
	err = AirPlayGetDeviceName( cstr, sizeof( cstr ) );
	require_noerr( err, exit );
	MACAddressToCString( inServer->deviceID, cstr );
	err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_DeviceID, (uint8_t) strlen( cstr ), cstr );
	require_noerr( err, exit );
	features = AirPlayGetFeatures( inServer );
	u32 = (uint32_t)( ( features >> 32 ) & UINT32_C( 0xFFFFFFFF ) );
	if( u32 != 0 )
	{
		n = snprintf( cstr, sizeof( cstr ), "0x%X,0x%X", (uint32_t)( features & UINT32_C( 0xFFFFFFFF ) ), u32 );
	}
	else
	{
		n = snprintf( cstr, sizeof( cstr ), "0x%X", (uint32_t)( features & UINT32_C( 0xFFFFFFFF ) ) );
	}
	err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_Features, (uint8_t) n, cstr );
	require_noerr( err, exit );
	*cstr = '\0';
	AirPlayGetConfigCString( inServer, CFSTR( kAirPlayKey_FirmwareRevision ), cstr, sizeof( cstr ), NULL );
	if( *cstr == '\0' )
	{
		AirPlayReceiverServerPlatformGetCString( inServer, CFSTR( kAirPlayKey_FirmwareRevision ), NULL,
												cstr, sizeof( cstr ), NULL );
	}
	if( *cstr != '\0' )
	{
		err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_FirmwareVersion, (uint8_t) strlen( cstr ), cstr );
		require_noerr( err, exit );
	}
	u32 = AirPlayGetStatusFlags( inServer );
	if( u32 != 0 )
	{
		n = snprintf( cstr, sizeof( cstr ), "0x%x", u32 );
		err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_Flags, (uint8_t) n, cstr );
		require_noerr( err, exit );
	}
	*cstr = '\0';
	AirPlayReceiverServerPlatformGetCString( inServer, CFSTR( kAirPlayKey_Model ), NULL, cstr, sizeof( cstr ), NULL );
	if( *cstr == '\0' )
	{
		AirPlayGetDeviceModel( inServer, cstr, sizeof( cstr ) );
	}
	if( *cstr != '\0' )
	{
		err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_Model, (uint8_t) strlen( cstr ), cstr );
		require_noerr( err, exit );
	}
	ptr = kAirPlayProtocolVersionStr;
	if( strcmp( ptr, "1.0" ) != 0 )
	{
		err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_ProtocolVersion, (uint8_t) strlen( ptr ), ptr );
		require_noerr( err, exit );
	}
{
	char *		cptr;
	err = AirPlayCopyHomeKitPairingIdentity( &cptr, NULL );
	if( !err )	
	{
		err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_PublicHKID, (uint8_t) strlen( cptr ), cptr );
		free( cptr );
		require_noerr( err, exit );
	}
	else
	{
		aprs_ulog( kLogLevelNotice, "### Add pairing HomeKit peer identifier to advertiser info failed: %#m\n", err );
	}
}
	ptr = kAirPlaySourceVersionStr;
	err = TXTRecordSetValue( &txtRec, kAirPlayTXTKey_SourceVersion, (uint8_t) strlen( ptr ), ptr );
	require_noerr( err, exit );
	txtPtr = TXTRecordGetBytesPtr( &txtRec );
	txtLen = TXTRecordGetLength( &txtRec );
	if( outTXTRecord )
	{
		CFDataRef		data;
		data = CFDataCreate( NULL, txtPtr, txtLen );
		require_action( data, exit, err = kNoMemoryErr );
		*outTXTRecord = data;
		goto exit;
	}
	if( inServer->bonjourAirPlay )
	{
		err = DNSServiceUpdateRecord( inServer->bonjourAirPlay, NULL, 0, txtLen, txtPtr, 0 );
		if( !err ) aprs_ulog( kLogLevelNotice, "Updated Bonjour TXT for %s\n", kAirPlayBonjourServiceType );
		else
		{
			aprs_ulog( kLogLevelNotice, "Bonjour TXT update failed for %s, deregistering so we can force a re-register %s\n",
					  kAirPlayBonjourServiceType );
			DNSServiceForget( &inServer->bonjourAirPlay );
		}
	}
	if( !inServer->bonjourAirPlay )
	{
		ptr = NULL;
		*cstr = '\0';
		AirPlayGetDeviceName( cstr, sizeof( cstr ) );
		ptr = cstr;
		flags = kDNSServiceFlagsKnownUnique;
		domain = kAirPlayBonjourServiceDomain;
		port = (uint16_t) _GetListenPort( inServer );
		require_action( port > 0, exit, err = kInternalErr );
		ifindex = kDNSServiceInterfaceIndexAny;
		if( *inServer->ifname != '\0' )
		{
			ifindex = if_nametoindex( inServer->ifname );
			require_action_quiet( ifindex != 0, exit, err = kNotFoundErr );
		}
		err = DNSServiceRegister( &inServer->bonjourAirPlay, flags, ifindex, ptr, kAirPlayBonjourServiceType, domain, NULL,
								 htons( port ), txtLen, txtPtr, _BonjourRegistrationHandler, inServer );
		require_noerr_quiet( err, exit );
		aprs_ulog( kLogLevelNotice, "Registering Bonjour %s port %d\n", kAirPlayBonjourServiceType, port );
	}
exit:
	TXTRecordDeallocate( &txtRec );
	return( err );
}
static OSStatus _UpdateBonjourAirPlay ( AirPlayReceiverServerRef inServer , CFDataRef * outTXTRecord ) { OSStatus err ; TXTRecordRef txtRec ; uint8_t txtBuf [ 256 ] ; const uint8_t * txtPtr ; uint16_t txtLen ; char cstr [ 256 ] ; const char * ptr ; AirPlayFeatures features ; int n ; uint32_t u32 ; uint16_t port ; DNSServiceFlags flags ; const char * domain ; uint32_t ifindex ; TXTRecordCreate ( & txtRec , ( uint16_t ) sizeof ( txtBuf ) , txtBuf ) ; * cstr = ' \0 ' ; err = AirPlayGetDeviceName ( cstr , sizeof ( cstr ) ) ; require_noerr ( err , exit ) ; MACAddressToCString ( inServer -> deviceID , cstr ) ; err = TXTRecordSetValue ( & txtRec , kAirPlayTXTKey_DeviceID , ( uint8_t ) strlen ( cstr ) , cstr ) ; require_noerr ( err , exit ) ; features = AirPlayGetFeatures ( inServer ) ; u32 = ( uint32_t ) ( ( features >> 32 ) & UINT32_C ( 0xFFFFFFFF ) ) ; if ( u32 != 0 ) { n = snprintf ( cstr , sizeof ( cstr ) , " " , ( uint32_t ) ( features & UINT32_C ( 0xFFFFFFFF ) ) , u32 ) ; } else { n = snprintf ( cstr , sizeof ( cstr ) , " " , ( uint32_t ) ( features & UINT32_C ( 0xFFFFFFFF ) ) ) ; } err = TXTRecordSetValue ( & txtRec , kAirPlayTXTKey_Features , ( uint8_t ) n , cstr ) ; require_noerr ( err , exit ) ; * cstr = ' \0 ' ; AirPlayGetConfigCString ( inServer , CFSTR ( kAirPlayKey_FirmwareRevision ) , cstr , sizeof ( cstr ) , NULL ) ; if ( * cstr == ' \0 ' ) { AirPlayReceiverServerPlatformGetCString ( inServer , CFSTR ( kAirPlayKey_FirmwareRevision ) , NULL , cstr , sizeof ( cstr ) , NULL ) ; } if ( * cstr != ' \0 ' ) { err = TXTRecordSetValue ( & txtRec , kAirPlayTXTKey_FirmwareVersion , ( uint8_t ) strlen ( cstr ) , cstr ) ; require_noerr ( err , exit ) ; } u32 = AirPlayGetStatusFlags ( inServer ) ; if ( u32 != 0 ) { n = snprintf ( cstr , sizeof ( cstr ) , " " , u32 ) ; err = TXTRecordSetValue ( & txtRec , kAirPlayTXTKey_Flags , ( uint8_t ) n , cstr ) ; require_noerr ( err , exit ) ; } * cstr = ' \0 ' ; AirPlayReceiverServerPlatformGetCString ( inServer , CFSTR ( kAirPlayKey_Model ) , NULL , cstr , sizeof ( cstr ) , NULL ) ; if ( * cstr == ' \0 ' ) { AirPlayGetDeviceModel ( inServer , cstr , sizeof ( cstr ) ) ; } if ( * cstr != ' \0 ' ) { err = TXTRecordSetValue ( & txtRec , kAirPlayTXTKey_Model , ( uint8_t ) strlen ( cstr ) , cstr ) ; require_noerr ( err , exit ) ; } ptr = kAirPlayProtocolVersionStr ; if ( strcmp ( ptr , " " ) != 0 ) { err = TXTRecordSetValue ( & txtRec , kAirPlayTXTKey_ProtocolVersion , ( uint8_t ) strlen ( ptr ) , ptr ) ; require_noerr ( err , exit ) ; } { char * cptr ; err = AirPlayCopyHomeKitPairingIdentity ( & cptr , NULL ) ; if ( ! err ) { err = TXTRecordSetValue ( & txtRec , kAirPlayTXTKey_PublicHKID , ( uint8_t ) strlen ( cptr ) , cptr ) ; free ( cptr ) ; require_noerr ( err , exit ) ; } else { aprs_ulog ( kLogLevelNotice , " \n " , err ) ; } } ptr = kAirPlaySourceVersionStr ; err = TXTRecordSetValue ( & txtRec , kAirPlayTXTKey_SourceVersion , ( uint8_t ) strlen ( ptr ) , ptr ) ; require_noerr ( err , exit ) ; txtPtr = TXTRecordGetBytesPtr ( & txtRec ) ; txtLen = TXTRecordGetLength ( & txtRec ) ; if ( outTXTRecord ) { CFDataRef data ; data = CFDataCreate ( NULL , txtPtr , txtLen ) ; require_action ( data , exit , err = kNoMemoryErr ) ; * outTXTRecord = data ; goto exit ; } if ( inServer -> bonjourAirPlay ) { err = DNSServiceUpdateRecord ( inServer -> bonjourAirPlay , NULL , 0 , txtLen , txtPtr , 0 ) ; if ( ! err ) aprs_ulog ( kLogLevelNotice , " \n " , kAirPlayBonjourServiceType ) ; else { aprs_ulog ( kLogLevelNotice , " \n " , kAirPlayBonjourServiceType ) ; DNSServiceForget ( & inServer -> bonjourAirPlay ) ; } } if ( ! inServer -> bonjourAirPlay ) { ptr = NULL ; * cstr = ' \0 ' ; AirPlayGetDeviceName ( cstr , sizeof ( cstr ) ) ; ptr = cstr ; flags = kDNSServiceFlagsKnownUnique ; domain = kAirPlayBonjourServiceDomain ; port = ( uint16_t ) _GetListenPort ( inServer ) ; require_action ( port > 0 , exit , err = kInternalErr ) ; ifindex = kDNSServiceInterfaceIndexAny ; if ( * inServer -> ifname != ' \0 ' ) { ifindex = if_nametoindex ( inServer -> ifname ) ; require_action_quiet ( ifindex != 0 , exit , err = kNotFoundErr ) ; } err = DNSServiceRegister ( & inServer -> bonjourAirPlay , flags , ifindex , ptr , kAirPlayBonjourServiceType , domain , NULL , htons ( port ) , txtLen , txtPtr , _BonjourRegistrationHandler , inServer ) ; require_noerr_quiet ( err , exit ) ; aprs_ulog ( kLogLevelNotice , " \n " , kAirPlayBonjourServiceType , port ) ; } exit : TXTRecordDeallocate ( & txtRec ) ; return ( err ) ; }
_UpdateBonjourAirPlay
Update Bonjour for the _airplay._tcp service.
_UpdateBonjourAirPlay Update Bonjour for the _airplay . _tcp service .
// Device Name // DeviceID // Features // FirmwareRevision // Flags // Model // Protocol version // Public HomeKit pairing identity // Source Version // If we're only building the TXT record then return it and exit without registering. // Update the service. // Update record failed or isn't supported so deregister to force a re-register below.