Commit 88d79439 authored by Mickaël Turnel's avatar Mickaël Turnel

Add multicast DNS registration implementation

parent 653cbf88
......@@ -37,6 +37,7 @@ set(HEADER_FILES
listener.h
listeningpoint.h
mainloop.h
mdns_register.h
message.h
object.h
parameters.h
......
......@@ -42,6 +42,7 @@
#include "belle-sip/http-message.h"
#include "belle-sip/belle-sdp.h"
#include "belle-sip/bodyhandler.h"
#include "belle-sip/mdns_register.h"
#ifdef __ANDROID__
#include "belle-sip/wakelock.h"
......
/*
belle-sip - SIP (RFC3261) library.
Copyright (C) 2010 Belledonne Communications SARL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BELLE_SIP_MDNS_REGISTER_H
#define BELLE_SIP_MDNS_REGISTER_H
typedef struct belle_sip_mdns_register belle_sip_mdns_register_t;
#define BELLE_SIP_MDNS_REGISTER(obj) BELLE_SIP_CAST(obj,belle_sip_mdns_register_t)
/**
* Callback prototype for asynchronous multicast DNS registration (advertisement).
*/
typedef void (*belle_sip_mdns_register_callback_t)(void *data, int error);
BELLE_SIP_BEGIN_DECLS
/**
* Asynchronously performs the mdns registration (advertisement).
* @param service the queried service ("sip", "stun", "turn"...).
* @param transport the queried transport ("udp", "tcp", "tls").
* @param domain the local domain name in which the service will be registered.
* @param port the port of the service.
* @param priority the priority of the service, lower value means more preferred.
* @param weight a relative weight for services within the same local domain that have the same priority, higher value means more preferred.
* @param cb a callback function that will be called to notify the results.
* @param data a user pointer passed through the callback as first argument.
* @return a #belle_sip_register_t that can be used to cancel the registration if needed. The context must have been ref'd with belle_sip_object_ref().
**/
BELLESIP_EXPORT belle_sip_mdns_register_t *belle_sip_mdns_register(const char *service, const char *transport, const char *domain, int port, int prio, int weight, belle_sip_mdns_register_callback_t cb, void *data);
/**
* Cancels the mdns registration.
* @param context the belle_sip_mdns_register_t used to register the service.
**/
BELLESIP_EXPORT void belle_sip_mdns_unregister(belle_sip_mdns_register_t *context);
BELLE_SIP_END_DECLS
#endif /* BELLE_SIP_MDNS_REGISTER_H */
\ No newline at end of file
......@@ -146,7 +146,8 @@ BELLE_SIP_DECLARE_TYPES_BEGIN(belle_sip,1)
BELLE_SIP_TYPE_ID(belle_sip_header_content_disposition_t),
BELLE_SIP_TYPE_ID(belle_sip_header_accept_t),
BELLE_SIP_TYPE_ID(belle_sip_header_reason_t),
BELLE_SIP_TYPE_ID(belle_sip_header_authentication_info_t)
BELLE_SIP_TYPE_ID(belle_sip_header_authentication_info_t),
BELLE_SIP_TYPE_ID(belle_sip_mdns_register_t)
BELLE_SIP_DECLARE_TYPES_END
......
......@@ -59,6 +59,9 @@ if(ZLIB_FOUND)
list(APPEND LIBS ${ZLIB_LIBRARIES})
endif()
if(DNSSD_FOUND)
set(MDNS_SOURCE_FILES_C
belle_sip_mdns_register.c
)
list(APPEND LIBS ${DNSSD_LIBRARIES})
endif()
if(WIN32)
......@@ -154,6 +157,7 @@ set(BELLE_SIP_SOURCE_FILES_C
${SDP_GENERATED_SOURCE_FILES_C}
${SIP_MESSAGE_GENERATED_SOURCE_FILES_C}
${TUNNEL_SOURCE_FILES_C}
${MDNS_SOURCE_FILES_C}
)
add_definitions(
......
......@@ -149,9 +149,6 @@ BELLE_SIP_DECLARE_VPTR(belle_sip_datagram_listening_point_t);
BELLE_SIP_DECLARE_VPTR(belle_sip_provider_t);
BELLE_SIP_DECLARE_VPTR(belle_sip_main_loop_t);
BELLE_SIP_DECLARE_VPTR(belle_sip_source_t);
#ifdef HAVE_MDNS
BELLE_SIP_DECLARE_VPTR(belle_sip_mdns_resolve_source_t);
#endif
BELLE_SIP_DECLARE_VPTR(belle_sip_dialog_t);
BELLE_SIP_DECLARE_VPTR(belle_sip_header_address_t);
BELLE_SIP_DECLARE_VPTR(belle_sip_header_contact_t);
......@@ -231,6 +228,10 @@ BELLE_SIP_DECLARE_VPTR(belle_sip_header_content_disposition_t);
BELLE_SIP_DECLARE_VPTR(belle_sip_header_accept_t);
BELLE_SIP_DECLARE_VPTR(belle_sip_header_reason_t);
BELLE_SIP_DECLARE_VPTR(belle_sip_header_authentication_info_t);
#ifdef HAVE_MDNS
BELLE_SIP_DECLARE_VPTR(belle_sip_mdns_resolve_source_t);
BELLE_SIP_DECLARE_VPTR(belle_sip_mdns_register_t);
#endif
BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_resolver_context_t,belle_sip_source_t)
......
/*
belle-sip - SIP (RFC3261) library.
Copyright (C) 2010 Belledonne Communications SARL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "belle_sip_internal.h"
#include <bctoolbox/defs.h>
#include <dns_sd.h>
#ifndef _WIN32
#include <unistd.h>
#include <poll.h>
typedef struct pollfd belle_sip_pollfd_t;
static int belle_sip_poll(belle_sip_pollfd_t *pfd, int count, int duration) {
int err = poll(pfd, count, duration);
if (err == -1 && errno != EINTR)
belle_sip_error("poll() error: %s",strerror(errno));
return err;
}
#else
#include <winsock2.h>
typedef WSAPOLLFD belle_sip_pollfd_t;
static int belle_sip_poll(belle_sip_pollfd_t *pfd, int count, int duration) {
int err = WSAPoll(pfd, count, duration);
if (err == SOCKET_ERROR)
belle_sip_error("WSAPoll() error: %d", WSAGetLastError());
return err;
}
#endif
struct belle_sip_mdns_register {
belle_sip_object_t base;
DNSServiceRef service_ref;
belle_sip_mdns_register_callback_t cb;
void *data;
bctbx_thread_t thread;
volatile bool_t running;
};
belle_sip_mdns_register_t *belle_sip_mdns_register_create(belle_sip_mdns_register_callback_t cb, void *data) {
belle_sip_mdns_register_t *obj = belle_sip_object_new(belle_sip_mdns_register_t);
obj->cb = cb;
obj->data = data;
obj->running = FALSE;
return obj;
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_mdns_register_t);
BELLE_SIP_INSTANCIATE_VPTR(belle_sip_mdns_register_t, belle_sip_object_t, NULL, NULL, NULL, FALSE);
static char * srv_prefix_from_service_and_transport(const char *service, const char *transport) {
if (service == NULL) service = "sip";
if (strcasecmp(transport, "udp") == 0) {
return belle_sip_strdup_printf("_%s._udp.", service);
} else if (strcasecmp(transport, "tcp") == 0) {
return belle_sip_strdup_printf("_%s._tcp.", service);
} else if (strcasecmp(transport, "tls") == 0) {
return belle_sip_strdup_printf("_%ss._tcp.", service);
}
return belle_sip_strdup_printf("_%s._udp.", service);
}
static void belle_sip_mdns_register_reply(DNSServiceRef service_ref
, DNSServiceFlags flags
, DNSServiceErrorType error_code
, const char *name
, const char *type
, const char *domain
, void *data) {
belle_sip_mdns_register_t *reg = (belle_sip_mdns_register_t *)data;
int error = 0;
if (error_code != kDNSServiceErr_NoError) {
belle_sip_error("%s error while registering %s [%s%s]: code %d", __FUNCTION__, name, type, domain, error_code);
error = -1;
}
if (reg->cb) reg->cb(reg->data, error);
}
void *mdns_register_poll(void *data) {
belle_sip_mdns_register_t *reg = (belle_sip_mdns_register_t *)data;
belle_sip_pollfd_t pollfd = {0};
pollfd.fd = DNSServiceRefSockFD(reg->service_ref);
pollfd.events = POLLIN;
reg->running = TRUE;
while(reg->running) {
int err = belle_sip_poll(&pollfd, 1, 1000);
if (err > 0) {
DNSServiceProcessResult(reg->service_ref);
}
}
return NULL;
}
belle_sip_mdns_register_t *belle_sip_mdns_register(const char *service, const char *transport, const char *domain, int port, int prio, int weight, belle_sip_mdns_register_callback_t cb, void *data) {
belle_sip_mdns_register_t *reg = belle_sip_mdns_register_create(cb, data);
DNSServiceErrorType error;
TXTRecordRef txt_ref;
char number[10];
char *prefix;
int n;
TXTRecordCreate(&txt_ref, 0, NULL);
n = snprintf(number, sizeof(number), "%d", prio);
TXTRecordSetValue(&txt_ref, "prio\0", n, number);
n = snprintf(number, sizeof(number), "%d", weight);
TXTRecordSetValue(&txt_ref, "weight\0", n, number);
prefix = srv_prefix_from_service_and_transport(service, transport);
error = DNSServiceRegister(&reg->service_ref
, 0
, 0
, NULL
, prefix
, domain
, NULL
, port
, TXTRecordGetLength(&txt_ref)
, TXTRecordGetBytesPtr(&txt_ref)
, belle_sip_mdns_register_reply
, reg);
belle_sip_free(prefix);
TXTRecordDeallocate(&txt_ref);
if (error != kDNSServiceErr_NoError) {
belle_sip_error("%s Register error [%s%s]: code %d", __FUNCTION__, prefix, domain, error);
belle_sip_object_unref(reg);
return NULL;
} else {
int errnum = bctbx_thread_create(&reg->thread, NULL, mdns_register_poll, reg);
if (errnum != 0) {
belle_sip_error("%s Error creating register thread: code %d", __FUNCTION__, errnum);
belle_sip_object_unref(reg);
return NULL;
}
}
return reg;
}
void belle_sip_mdns_unregister(belle_sip_mdns_register_t *reg) {
if (!reg) return;
if (reg->running) {
reg->running = FALSE;
bctbx_thread_join(reg->thread, NULL);
}
DNSServiceRefDeallocate(reg->service_ref);
belle_sip_object_unref(reg);
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment