46836e | 2005-04-09 | Jonas Wallden | |
|
cc46f9 | 2008-07-18 | H. William Welliver III | | 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.
|
46836e | 2005-04-09 | Jonas Wallden | |
The specification can be found at <http://www.dns-sd.org/>.
|
cc46f9 | 2008-07-18 | H. William Welliver III | | 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).
|
46836e | 2005-04-09 | Jonas Wallden | | */
#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
#ifdef HAVE_DNS_SD_H
|
700573 | 2005-05-29 | Jonas Wallden | |
#define kDNSServiceErr_BadinterfaceIndex kDNSServiceErr_BadInterfaceIndex
|
46836e | 2005-04-09 | Jonas Wallden | | #include <dns_sd.h>
#endif
#define IS_ERR(x) ((x) != kDNSServiceErr_NoError)
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;
|
700573 | 2005-05-29 | Jonas Wallden | | case kDNSServiceErr_BadInterfaceIndex:
|
46836e | 2005-04-09 | Jonas Wallden | | reason = "Bad interface index";
break;
default:
reason = "Unknown error";
break;
}
Pike_error("DNS_SD: %s Reason: %s (%d)\n", msg, reason, err);
}
|
74dfe8 | 2012-12-30 | Jonas Walldén | | 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))
|
46836e | 2005-04-09 | Jonas Wallden | | {
}
static DNSServiceErrorType start_service(struct service *svc,
char *name,
char *service,
char *domain,
int port,
char *txt,
int txtlen)
{
DNSServiceErrorType err;
DNSServiceRef ref;
if (name && !strlen(name))
name = NULL;
if (domain && !strlen(domain))
domain = NULL;
if (txt && !txtlen)
txt = NULL;
|
cc46f9 | 2008-07-18 | H. William Welliver III | |
port = htons(port);
|
46836e | 2005-04-09 | Jonas Wallden | | 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;
|
65acbc | 2005-10-21 | H. William Welliver III | |
err = DNSServiceProcessResult(ref);
|
46836e | 2005-04-09 | Jonas Wallden | | 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)
#ifdef HAVE_HOWL_H
#include <howl.h>
#endif
#define IS_ERR(x) ((x) != SW_OKAY)
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)
{
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;
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) {
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()
{
if (sw_discovery_init(&service_session) == SW_OKAY) {
th_create_small(&service_thread, howl_thread, NULL);
}
}
static void exit_howl_module()
{
if (service_session)
sw_discovery_fina(service_session);
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,
0);
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,
BIT_STRING,
BIT_STRING,
BIT_INT,
BIT_STRING | BIT_VOID,
0);
stop_service(THIS);
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;
txt = (args == 5) ? sp[4 - args].u.string->str : NULL;
txtlen = txt ? sp[4 - args].u.string->len : 0;
err = start_service(THIS, name, service, domain, port, txt, txtlen);
if (IS_ERR(err))
raise_error("Could not register service.", err);
pop_n_elems(args);
}
|
74dfe8 | 2012-12-30 | Jonas Walldén | | static void init_service_struct(struct object *UNUSED(o))
|
46836e | 2005-04-09 | Jonas Wallden | | {
THIS->service_ref = 0;
}
|
74dfe8 | 2012-12-30 | Jonas Walldén | | static void exit_service_struct(struct object *UNUSED(o))
|
46836e | 2005-04-09 | Jonas Wallden | | {
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);
ADD_FUNCTION("create", f_create,
tFunc(tStr tStr tStr tInt tOr(tStr, tVoid), tVoid), 0);
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) */
|