DNSServiceDiscovery.c [plain text]
#include "DNSServiceDiscovery.h"
#include "DNSServiceDiscoveryDefines.h"
#include <stdlib.h>
#include <stdio.h>
#include <servers/bootstrap.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <pthread.h>
#include <netinet/in.h>
extern struct rpc_subsystem internal_DNSServiceDiscoveryReply_subsystem;
extern boolean_t DNSServiceDiscoveryReply_server(
mach_msg_header_t *InHeadP,
mach_msg_header_t *OutHeadP);
extern
kern_return_t DNSServiceBrowserCreate_rpc
(
mach_port_t server,
mach_port_t client,
DNSCString regtype,
DNSCString domain
);
extern
kern_return_t DNSServiceDomainEnumerationCreate_rpc
(
mach_port_t server,
mach_port_t client,
int registrationDomains
);
extern
kern_return_t DNSServiceRegistrationCreate_rpc
(
mach_port_t server,
mach_port_t client,
DNSCString name,
DNSCString regtype,
DNSCString domain,
int port,
DNSCString txtRecord
);
extern
kern_return_t DNSServiceResolverResolve_rpc
(
mach_port_t server,
mach_port_t client,
DNSCString name,
DNSCString regtype,
DNSCString domain
);
extern
kern_return_t DNSServiceRegistrationAddRecord_rpc
(
mach_port_t server,
mach_port_t client,
int type,
record_data_t data,
mach_msg_type_number_t record_dataCnt,
uint32_t ttl,
natural_t *reference
);
extern
int DNSServiceRegistrationUpdateRecord_rpc
(
mach_port_t server,
mach_port_t client,
natural_t reference,
record_data_t data,
mach_msg_type_number_t record_dataCnt,
uint32_t ttl
);
extern
kern_return_t DNSServiceRegistrationRemoveRecord_rpc
(
mach_port_t server,
mach_port_t client,
natural_t reference
);
struct a_requests {
struct a_requests *next;
mach_port_t client_port;
union {
DNSServiceBrowserReply browserCallback;
DNSServiceDomainEnumerationReply enumCallback;
DNSServiceRegistrationReply regCallback;
DNSServiceResolverReply resolveCallback;
} callout;
void *context;
};
static struct a_requests *a_requests = NULL;
static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER;
typedef struct _dns_service_discovery_t {
mach_port_t port;
} dns_service_discovery_t;
mach_port_t DNSServiceDiscoveryLookupServer(void)
{
static mach_port_t sndPort = MACH_PORT_NULL;
kern_return_t result;
if (sndPort != MACH_PORT_NULL) {
return sndPort;
}
result = bootstrap_look_up(bootstrap_port, DNS_SERVICE_DISCOVERY_SERVER, &sndPort);
if (result != KERN_SUCCESS) {
printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__, __FILE__, __LINE__, (int) result);
sndPort = MACH_PORT_NULL;
}
return sndPort;
}
void _increaseQueueLengthOnPort(mach_port_t port)
{
mach_port_limits_t qlimits;
kern_return_t result;
qlimits.mpl_qlimit = 16;
result = mach_port_set_attributes(mach_task_self(), port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&qlimits, MACH_PORT_LIMITS_INFO_COUNT);
if (result != KERN_SUCCESS) {
printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__, __FILE__, __LINE__, (int) result, mach_error_string(result));
}
}
dns_service_discovery_ref DNSServiceBrowserCreate (const char *regtype, const char *domain, DNSServiceBrowserReply callBack,void *context)
{
mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
mach_port_t clientPort;
kern_return_t result;
dns_service_discovery_ref return_t;
struct a_requests *request;
if (!serverPort) {
return NULL;
}
result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
if (result != KERN_SUCCESS) {
printf("Mach port receive creation failed, %s\n", mach_error_string(result));
return NULL;
}
result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
if (result != KERN_SUCCESS) {
printf("Mach port send creation failed, %s\n", mach_error_string(result));
mach_port_destroy(mach_task_self(), clientPort);
return NULL;
}
_increaseQueueLengthOnPort(clientPort);
return_t = malloc(sizeof(dns_service_discovery_t));
return_t->port = clientPort;
request = malloc(sizeof(struct a_requests));
request->client_port = clientPort;
request->context = context;
request->callout.browserCallback = callBack;
result = DNSServiceBrowserCreate_rpc(serverPort, clientPort, (char *)regtype, (char *)domain);
if (result != KERN_SUCCESS) {
printf("There was an error creating a browser, %s\n", mach_error_string(result));
free(request);
return NULL;
}
pthread_mutex_lock(&a_requests_lock);
request->next = a_requests;
a_requests = request;
pthread_mutex_unlock(&a_requests_lock);
return return_t;
}
dns_service_discovery_ref DNSServiceDomainEnumerationCreate (int registrationDomains, DNSServiceDomainEnumerationReply callBack, void *context)
{
mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
mach_port_t clientPort;
kern_return_t result;
dns_service_discovery_ref return_t;
struct a_requests *request;
if (!serverPort) {
return NULL;
}
result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
if (result != KERN_SUCCESS) {
printf("Mach port receive creation failed, %s\n", mach_error_string(result));
return NULL;
}
result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
if (result != KERN_SUCCESS) {
printf("Mach port send creation failed, %s\n", mach_error_string(result));
mach_port_destroy(mach_task_self(), clientPort);
return NULL;
}
_increaseQueueLengthOnPort(clientPort);
return_t = malloc(sizeof(dns_service_discovery_t));
return_t->port = clientPort;
request = malloc(sizeof(struct a_requests));
request->client_port = clientPort;
request->context = context;
request->callout.enumCallback = callBack;
result = DNSServiceDomainEnumerationCreate_rpc(serverPort, clientPort, registrationDomains);
if (result != KERN_SUCCESS) {
printf("There was an error creating an enumerator, %s\n", mach_error_string(result));
free(request);
return NULL;
}
pthread_mutex_lock(&a_requests_lock);
request->next = a_requests;
a_requests = request;
pthread_mutex_unlock(&a_requests_lock);
return return_t;
}
dns_service_discovery_ref DNSServiceRegistrationCreate
(const char *name, const char *regtype, const char *domain, uint16_t port, const char *txtRecord, DNSServiceRegistrationReply callBack, void *context)
{
mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
mach_port_t clientPort;
kern_return_t result;
dns_service_discovery_ref return_t;
struct a_requests *request;
if (!serverPort) {
return NULL;
}
if (!txtRecord) {
txtRecord = "";
}
result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
if (result != KERN_SUCCESS) {
printf("Mach port receive creation failed, %s\n", mach_error_string(result));
return NULL;
}
result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
if (result != KERN_SUCCESS) {
printf("Mach port send creation failed, %s\n", mach_error_string(result));
mach_port_destroy(mach_task_self(), clientPort);
return NULL;
}
_increaseQueueLengthOnPort(clientPort);
return_t = malloc(sizeof(dns_service_discovery_t));
return_t->port = clientPort;
request = malloc(sizeof(struct a_requests));
request->client_port = clientPort;
request->context = context;
request->callout.regCallback = callBack;
result = DNSServiceRegistrationCreate_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain, port, (char *)txtRecord);
if (result != KERN_SUCCESS) {
printf("There was an error creating a resolve, %s\n", mach_error_string(result));
free(request);
return NULL;
}
pthread_mutex_lock(&a_requests_lock);
request->next = a_requests;
a_requests = request;
pthread_mutex_unlock(&a_requests_lock);
return return_t;
}
dns_service_discovery_ref DNSServiceResolverResolve(const char *name, const char *regtype, const char *domain, DNSServiceResolverReply callBack, void *context)
{
mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
mach_port_t clientPort;
kern_return_t result;
dns_service_discovery_ref return_t;
struct a_requests *request;
if (!serverPort) {
return NULL;
}
result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
if (result != KERN_SUCCESS) {
printf("Mach port receive creation failed, %s\n", mach_error_string(result));
return NULL;
}
result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
if (result != KERN_SUCCESS) {
printf("Mach port send creation failed, %s\n", mach_error_string(result));
mach_port_destroy(mach_task_self(), clientPort);
return NULL;
}
_increaseQueueLengthOnPort(clientPort);
return_t = malloc(sizeof(dns_service_discovery_t));
return_t->port = clientPort;
request = malloc(sizeof(struct a_requests));
request->client_port = clientPort;
request->context = context;
request->callout.resolveCallback = callBack;
DNSServiceResolverResolve_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain);
pthread_mutex_lock(&a_requests_lock);
request->next = a_requests;
a_requests = request;
pthread_mutex_unlock(&a_requests_lock);
return return_t;
}
DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl)
{
mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
mach_port_t clientPort;
natural_t reference = 0;
kern_return_t result = KERN_SUCCESS;
if (!serverPort) {
return kDNSServiceDiscoveryUnknownErr;
}
clientPort = DNSServiceDiscoveryMachPort(ref);
if (!clientPort) {
return kDNSServiceDiscoveryUnknownErr;
}
result = DNSServiceRegistrationAddRecord_rpc(serverPort, clientPort, rrtype, (record_data_t)rdata, rdlen, ttl, &reference);
if (result != KERN_SUCCESS) {
printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
}
return reference;
}
DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl)
{
mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
mach_port_t clientPort;
kern_return_t result = KERN_SUCCESS;
if (!serverPort) {
return kDNSServiceDiscoveryUnknownErr;
}
clientPort = DNSServiceDiscoveryMachPort(ref);
if (!clientPort) {
return kDNSServiceDiscoveryUnknownErr;
}
result = DNSServiceRegistrationUpdateRecord_rpc(serverPort, clientPort, (natural_t)reference, (record_data_t)rdata, rdlen, ttl);
if (result != KERN_SUCCESS) {
printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
return result;
}
return kDNSServiceDiscoveryNoError;
}
DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference)
{
mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
mach_port_t clientPort;
kern_return_t result = KERN_SUCCESS;
if (!serverPort) {
return kDNSServiceDiscoveryUnknownErr;
}
clientPort = DNSServiceDiscoveryMachPort(ref);
if (!clientPort) {
return kDNSServiceDiscoveryUnknownErr;
}
result = DNSServiceRegistrationRemoveRecord_rpc(serverPort, clientPort, (natural_t)reference);
if (result != KERN_SUCCESS) {
printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
return result;
}
return kDNSServiceDiscoveryNoError;
}
void DNSServiceDiscovery_handleReply(void *replyMsg)
{
unsigned long result = 0xFFFFFFFF;
mach_msg_header_t * msgSendBufPtr;
mach_msg_header_t * receivedMessage;
unsigned msgSendBufLength;
msgSendBufLength = internal_DNSServiceDiscoveryReply_subsystem.maxsize;
msgSendBufPtr = (mach_msg_header_t *) malloc(msgSendBufLength);
receivedMessage = ( mach_msg_header_t * ) replyMsg;
result = DNSServiceDiscoveryReply_server ( receivedMessage, msgSendBufPtr );
( void ) mach_msg_send ( msgSendBufPtr );
free(msgSendBufPtr);
}
mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery)
{
return dnsServiceDiscovery->port;
}
void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery)
{
struct a_requests *request0, *request;
mach_port_t reply = dnsServiceDiscovery->port;
if (dnsServiceDiscovery->port) {
pthread_mutex_lock(&a_requests_lock);
request0 = NULL;
request = a_requests;
while (request) {
if (request->client_port == reply) {
if (request0) {
request0->next = request->next;
} else {
a_requests = request->next;
}
break;
} else {
request0 = request;
request = request->next;
}
}
pthread_mutex_unlock(&a_requests_lock);
free(request);
mach_port_destroy(mach_task_self(), dnsServiceDiscovery->port);
free(dnsServiceDiscovery);
}
return;
}
kern_return_t internal_DNSServiceDomainEnumerationReply_rpc
(
mach_port_t reply,
int resultType,
DNSCString replyDomain,
DNSServiceDiscoveryReplyFlags flags
)
{
struct a_requests *request;
void *requestContext = NULL;
DNSServiceDomainEnumerationReply callback = NULL;
pthread_mutex_lock(&a_requests_lock);
request = a_requests;
while (request) {
if (request->client_port == reply) {
break;
}
request = request->next;
}
if (request != NULL) {
callback = (*request->callout.enumCallback);
requestContext = request->context;
}
pthread_mutex_unlock(&a_requests_lock);
if (request != NULL) {
(callback)(resultType, replyDomain, flags, requestContext);
}
return KERN_SUCCESS;
}
kern_return_t internal_DNSServiceBrowserReply_rpc
(
mach_port_t reply,
int resultType,
DNSCString replyName,
DNSCString replyType,
DNSCString replyDomain,
DNSServiceDiscoveryReplyFlags flags
)
{
struct a_requests *request;
void *requestContext = NULL;
DNSServiceBrowserReply callback = NULL;
pthread_mutex_lock(&a_requests_lock);
request = a_requests;
while (request) {
if (request->client_port == reply) {
break;
}
request = request->next;
}
if (request != NULL) {
callback = (*request->callout.browserCallback);
requestContext = request->context;
}
pthread_mutex_unlock(&a_requests_lock);
if (request != NULL) {
(callback)(resultType, replyName, replyType, replyDomain, flags, requestContext);
}
return KERN_SUCCESS;
}
kern_return_t internal_DNSServiceRegistrationReply_rpc
(
mach_port_t reply,
int resultType
)
{
struct a_requests *request;
void *requestContext = NULL;
DNSServiceRegistrationReply callback = NULL;
pthread_mutex_lock(&a_requests_lock);
request = a_requests;
while (request) {
if (request->client_port == reply) {
break;
}
request = request->next;
}
if (request != NULL) {
callback = (*request->callout.regCallback);
requestContext = request->context;
}
pthread_mutex_unlock(&a_requests_lock);
if (request != NULL) {
(callback)(resultType, requestContext);
}
return KERN_SUCCESS;
}
kern_return_t internal_DNSServiceResolverReply_rpc
(
mach_port_t reply,
sockaddr_t interface,
sockaddr_t address,
DNSCString txtRecord,
DNSServiceDiscoveryReplyFlags flags
)
{
struct sockaddr *interface_storage = NULL;
struct sockaddr *address_storage = NULL;
struct a_requests *request;
void *requestContext = NULL;
DNSServiceResolverReply callback = NULL;
if (interface) {
int len = ((struct sockaddr *)interface)->sa_len;
interface_storage = (struct sockaddr *)malloc(len);
bcopy(interface, interface_storage,len);
}
if (address) {
int len = ((struct sockaddr *)address)->sa_len;
address_storage = (struct sockaddr *)malloc(len);
bcopy(address, address_storage, len);
}
pthread_mutex_lock(&a_requests_lock);
request = a_requests;
while (request) {
if (request->client_port == reply) {
break;
}
request = request->next;
}
if (request != NULL) {
callback = (*request->callout.resolveCallback);
requestContext = request->context;
}
pthread_mutex_unlock(&a_requests_lock);
if (request != NULL) {
(callback)(interface_storage, address_storage, txtRecord, flags, requestContext);
}
if (interface) {
free(interface_storage);
}
if (address) {
free(address_storage);
}
return KERN_SUCCESS;
}