pike.git
/
src
/
modules
/
_Protocols_DNS_SD
/
sd.c
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/src/modules/_Protocols_DNS_SD/sd.c:1:
-
/*
-
|| This file is part of Pike. For copyright information see COPYRIGHT.
-
|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
-
|| for more information.
-
*/
+
-
-
/* Glue for DNS Service Discovery, which is built on top of e.g. Multicast
-
DNS (ZeroConf/Rendezvous/Bonjour). Using this API a Pike program can
-
register a service (e.g. a web server) and have other applications on
-
the local network detect it without additional configuration.
-
-
The specification can be found at <http://www.dns-sd.org/>.
-
-
The implementation requires either the dns_ds.h (found in Mac OS X
-
and SunOS 5.11+) or howl.h (part of libhowl on Linux).
-
*/
-
-
-
#include "global.h"
-
#include "config.h"
-
#include "pike_macros.h"
-
#include "stralloc.h"
-
#include "pike_error.h"
-
#include "object.h"
-
#include "constants.h"
-
#include "interpret.h"
-
#include "svalue.h"
-
#include "mapping.h"
-
#include "builtin_functions.h"
-
#include "module_support.h"
-
#include "threads.h"
-
-
#include <signal.h>
-
-
-
#ifdef THIS
-
#undef THIS
-
#endif
-
#define THIS ((struct service *)(Pike_fp->current_storage))
-
#define sp Pike_sp
-
-
-
#if defined(HAVE_DNS_SD) || defined(HAVE_HOWL)
-
-
-
-
-
-
#ifdef HAVE_DNS_SD
-
-
/* Mac OS X interface is defined in <dns_sd.h> */
-
#ifdef HAVE_DNS_SD_H
-
-
/* Workaround for typo in 10.3 header (which 10.4 doesn't preserve) */
-
#define kDNSServiceErr_BadinterfaceIndex kDNSServiceErr_BadInterfaceIndex
-
-
#include <dns_sd.h>
-
#endif
-
-
#define IS_ERR(x) ((x) != kDNSServiceErr_NoError)
-
-
/* Instance variables for each service registration */
-
struct service {
-
DNSServiceRef service_ref;
-
};
-
-
-
static void raise_error(char *msg, DNSServiceErrorType err)
-
{
-
char *reason;
-
-
if (err == kDNSServiceErr_NoError)
-
return;
-
-
switch (err) {
-
case kDNSServiceErr_NoSuchName:
-
reason = "No such name";
-
break;
-
case kDNSServiceErr_NoMemory:
-
reason = "No memory";
-
break;
-
case kDNSServiceErr_BadParam:
-
reason = "Bad parameter";
-
break;
-
case kDNSServiceErr_BadReference:
-
reason = "Bad reference";
-
break;
-
case kDNSServiceErr_BadState:
-
reason = "Bad state";
-
break;
-
case kDNSServiceErr_BadFlags:
-
reason = "Bad flags";
-
break;
-
case kDNSServiceErr_Unsupported:
-
reason = "Unsupported";
-
break;
-
case kDNSServiceErr_AlreadyRegistered:
-
reason = "Already registered";
-
break;
-
case kDNSServiceErr_NameConflict:
-
reason = "Name conflict";
-
break;
-
case kDNSServiceErr_Invalid:
-
reason = "Invalid";
-
break;
-
case kDNSServiceErr_Incompatible:
-
reason = "Incompatible";
-
break;
-
case kDNSServiceErr_BadInterfaceIndex:
-
reason = "Bad interface index";
-
break;
-
default:
-
reason = "Unknown error";
-
break;
-
}
-
Pike_error("DNS_SD: %s Reason: %s (%d)\n", msg, reason, err);
-
}
-
-
-
static void start_service_callback(DNSServiceRef UNUSED(ref),
-
DNSServiceFlags UNUSED(flags),
-
DNSServiceErrorType UNUSED(error),
-
const char *UNUSED(name),
-
const char *UNUSED(regtype),
-
const char *UNUSED(domain),
-
void *UNUSED(context))
-
{
-
}
-
-
-
static DNSServiceErrorType start_service(struct service *svc,
-
char *name,
-
char *service,
-
char *domain,
-
int port,
-
char *txt,
-
int txtlen)
-
{
-
DNSServiceErrorType err;
-
DNSServiceRef ref;
-
-
/* Empty strings should be passed as NULL in order to get default values */
-
if (name && !strlen(name))
-
name = NULL;
-
if (domain && !strlen(domain))
-
domain = NULL;
-
if (txt && !txtlen)
-
txt = NULL;
-
-
// port must be provided in network byte-order.
-
port = htons(port);
-
-
svc->service_ref = NULL;
-
err = DNSServiceRegister(&ref, 0, 0, name, service, domain, NULL, port,
-
txtlen, txt, start_service_callback, NULL);
-
if (err == kDNSServiceErr_NoError)
-
svc->service_ref = ref;
-
-
err = DNSServiceProcessResult(ref);
-
return err;
-
}
-
-
-
static void stop_service(struct service *svc)
-
{
-
if (svc->service_ref) {
-
DNSServiceRefDeallocate(svc->service_ref);
-
svc->service_ref = NULL;
-
}
-
}
-
-
-
static DNSServiceErrorType update_txt_record(struct service *svc,
-
char *txt, int txtlen)
-
{
-
if (svc->service_ref) {
-
int ttl = 0;
-
return DNSServiceUpdateRecord(svc->service_ref, NULL, 0,
-
txtlen, txt, ttl);
-
}
-
return kDNSServiceErr_Invalid;
-
}
-
-
#endif /* HAVE_DNS_SD */
-
-
-
-
-
#if defined(HAVE_HOWL) && !defined(HAVE_DNS_SD)
-
-
/* Load <howl.h> to indirectly get <discovery/discovery.h> */
-
#ifdef HAVE_HOWL_H
-
#include <howl.h>
-
#endif
-
-
#define IS_ERR(x) ((x) != SW_OKAY)
-
-
/* Global session shared for all objects */
-
static sw_discovery service_session = NULL;
-
static THREAD_T service_thread;
-
-
struct service {
-
sw_discovery_oid service_ref;
-
};
-
-
-
static void raise_error(char *msg, sw_result err)
-
{
-
char *reason;
-
-
if (err == SW_OKAY)
-
return;
-
-
switch (err) {
-
case SW_DISCOVERY_E_NO_MEM:
-
reason = "No memory";
-
break;
-
case SW_DISCOVERY_E_BAD_PARAM:
-
reason = "Bad parameter";
-
break;
-
case SW_DISCOVERY_E_UNKNOWN:
-
default:
-
reason = "Unknown error";
-
break;
-
}
-
Pike_error("DNS_SD: %s Reason: %s (%d)\n", msg, reason, err);
-
}
-
-
-
-
static sw_result start_reply_fn(sw_discovery discovery,
-
sw_discovery_publish_status status,
-
sw_discovery_oid oid,
-
sw_opaque extra)
-
{
-
// Do nothing
-
return SW_OKAY;
-
}
-
-
-
static sw_result start_service(struct service *svc,
-
char *name,
-
char *service,
-
char *domain,
-
int port,
-
char *txt,
-
int txtlen)
-
{
-
sw_result err = SW_DISCOVERY_E_UNKNOWN;
-
-
/* Empty strings should be passed as NULL in order to get default values */
-
if (domain && !strlen(domain))
-
domain = NULL;
-
if (txt && !txtlen)
-
txt = NULL;
-
-
err = sw_discovery_publish(service_session,
-
0, name, service, domain, NULL, port,
-
txt, txtlen, start_reply_fn, NULL,
-
&svc->service_ref);
-
return err;
-
}
-
-
-
static void stop_service(struct service *svc)
-
{
-
if (svc->service_ref) {
-
/* Abort registration */
-
sw_discovery_cancel(service_session, svc->service_ref);
-
}
-
}
-
-
-
static sw_result update_txt_record(struct service *svc, char *txt, int txtlen)
-
{
-
if (svc->service_ref) {
-
return sw_discovery_publish_update(service_session,
-
svc->service_ref,
-
txt, txtlen);
-
}
-
return SW_DISCOVERY_E_UNKNOWN;
-
}
-
-
-
static void * howl_thread(void *arg)
-
{
-
sw_discovery_run(service_session);
-
return NULL;
-
}
-
-
-
static void init_howl_module(void)
-
{
-
if (sw_discovery_init(&service_session) == SW_OKAY) {
-
th_create_small(&service_thread, howl_thread, NULL);
-
}
-
}
-
-
-
static void exit_howl_module(void)
-
{
-
/* Close active session */
-
if (service_session)
-
sw_discovery_fina(service_session);
-
-
/* Kill Howl thread if running */
-
if (service_thread)
-
th_kill(service_thread, SIGCHLD);
-
}
-
-
-
#endif /* defined(HAVE_HOWL) && !defined(HAVE_DNS_SD) */
-
-
-
-
-
static void f_update_txt(INT32 args)
-
{
-
check_all_args("Service->update_txt", args,
-
BIT_STRING, /* txt */
-
0);
-
-
/* Can only be called if we have valid service */
-
if (THIS->service_ref) {
-
char *txt = sp[0 - args].u.string->str;
-
int txtlen = sp[0 - args].u.string->len;
-
-
int err = update_txt_record(THIS, txt, txtlen);
-
if (IS_ERR(err))
-
raise_error("Could not update TXT record.", err);
-
}
-
pop_n_elems(args);
-
}
-
-
-
static void f_create(INT32 args)
-
{
-
char *name, *service, *domain, *txt;
-
int port, txtlen, err;
-
-
check_all_args("Service->create", args,
-
BIT_STRING, /* name */
-
BIT_STRING, /* service */
-
BIT_STRING, /* domain */
-
BIT_INT, /* port */
-
BIT_STRING | BIT_VOID, /* txt */
-
0);
-
-
/* Stop existing service if one is running */
-
stop_service(THIS);
-
-
/* Get string arguments which should already be UTF-8 and clipped to
-
appropriate lengths. */
-
name = sp[0 - args].u.string->str;
-
service = sp[1 - args].u.string->str;
-
domain = sp[2 - args].u.string->str;
-
port = sp[3 - args].u.integer;
-
-
/* Optional TXT record may theoretically contain NUL chars so we can't
-
trust strlen. */
-
txt = (args == 5) ? sp[4 - args].u.string->str : NULL;
-
txtlen = txt ? sp[4 - args].u.string->len : 0;
-
-
/* Register new service */
-
err = start_service(THIS, name, service, domain, port, txt, txtlen);
-
if (IS_ERR(err))
-
raise_error("Could not register service.", err);
-
}
-
-
-
static void init_service_struct(struct object *UNUSED(o))
-
{
-
THIS->service_ref = 0;
-
}
-
-
-
static void exit_service_struct(struct object *UNUSED(o))
-
{
-
/* Stop an existing service */
-
stop_service(THIS);
-
}
-
-
-
PIKE_MODULE_INIT
-
{
-
start_new_program();
-
-
ADD_STORAGE(struct service);
-
-
set_init_callback(init_service_struct);
-
set_exit_callback(exit_service_struct);
-
-
/* function(string, string, string, int, string|void:void) */
-
ADD_FUNCTION("create", f_create,
-
tFunc(tStr tStr tStr tInt tOr(tStr, tVoid), tVoid), 0);
-
-
/* function(string:void) */
-
ADD_FUNCTION("update_txt", f_update_txt, tFunc(tStr, tVoid), 0);
-
-
end_class("Service", 0);
-
-
#ifdef HAVE_HOWL
-
init_howl_module();
-
#endif
-
}
-
-
-
PIKE_MODULE_EXIT
-
{
-
#ifdef HAVE_HOWL
-
exit_howl_module();
-
#endif
-
}
-
-
-
#else /* defined(HAVE_DNS_SD) || defined(HAVE_HOWL) */
-
-
PIKE_MODULE_INIT {}
-
PIKE_MODULE_EXIT {}
-
-
#endif /* defined(HAVE_DNS_SD) || defined(HAVE_HOWL) */
+
Newline at end of file removed.