missing
stamp-h1
.*.swp
+.*.swo
test-driver
+*.exe
+.dirstamp
AC_CONFIG_SRCDIR([src/server.c])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
-AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax])
+AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax subdir-objects])
AC_SUBST(PACKAGE_URL, [http://github.com/everbase/catta/])
AC_MSG_ERROR([C99 support is required])
fi
+# Windows stuff
+AC_CHECK_DECL(_WIN32)
+AM_CONDITIONAL([WINDOWS], [ test "x$ac_cv_have_decl__WIN32" = "xyes" ])
+if test "x$ac_cv_have_decl__WIN32" = "xyes" ; then
+ CPPFLAGS="$CPPFLAGS -I`pwd`/src/compat/windows/include"
+fi
+AC_CHECK_MEMBER([struct in_pktinfo.ipi_spec_dst],
+ AC_DEFINE([HAVE_IPI_SPEC_DST], [], [struct in_pktinfo has ipi_spec_dst member]),
+ [],
+ [[#include <netinet/in.h>]])
+
# -fstack-protector
AC_ARG_ENABLE([stack-protector],
[AS_HELP_STRING([--disable-stack-protector],
if test x"$enable_ssp" = x"yes"; then
# Do this the long way so we don't call GCC_STACK_PROTECT_LIB twice
GCC_STACK_PROTECT_CC
-
- AC_LANG_PUSH([C++])
- GCC_STACK_PROTECT_CXX
- AC_LANG_POP([C++])
- # XXX: Update the enable_ssp value now for output later?
fi
# libtool stuff
-AC_PROG_LIBTOOL
+LT_INIT([win32-dll])
ACX_PTHREAD(,AC_MSG_ERROR([Missing POSIX Threads support]))
# If using GCC specify some additional parameters
if test "x$GCC" = "xyes" ; then
- DESIRED_FLAGS="-Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -fdiagnostics-show-option -Wno-cast-qual -fno-strict-aliasing"
+ DESIRED_FLAGS="-Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wshadow -Wendif-labels -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -fdiagnostics-show-option -Wno-cast-qual -fno-strict-aliasing"
+
+ # when compiling for MingW, -Wmissing-noreturn is triggered a bunch of
+ # times from autogenerated libtool wrappers, so leave it out on Windows.
+ if test "x$ac_cv_have_decl__WIN32" != "xyes" ; then
+ DESIRED_FLAGS="$DESIRED_FLAGS -Wmissing-noreturn"
+ fi
for flag in $DESIRED_FLAGS ; do
AC_MSG_CHECKING([whether $CC accepts $flag])
# Checks for library functions.
AC_FUNC_SELECT_ARGTYPES
-AC_CHECK_FUNCS([gethostname select socket uname strcasecmp gettimeofday strncasecmp strlcpy])
+AC_CHECK_FUNCS([gethostname select socket uname strcasecmp gettimeofday strncasecmp strlcpy fcntl])
AC_FUNC_CHOWN
AC_FUNC_STAT
echo "
---{ $PACKAGE_NAME $VERSION }---
- prefix: ${prefix}
- sysconfdir: ${sysconfdir}
- localstatedir: ${localstatedir}
- C Compiler: ${CC}
- CFLAGS: ${CFLAGS}
- Enable stack-smashing protection: ${enable_ssp}
-"
-
-echo "\
+ prefix: ${prefix}
+ sysconfdir: ${sysconfdir}
+ localstatedir: ${localstatedir}
+ C Compiler: ${CC}
+ CFLAGS: ${CFLAGS}
+ Enable stack-smashing protection: ${enable_ssp}
Building tests: ${ENABLE_TESTS}
"
static void resolve_callback(
CattaSServiceResolver *r,
- CATTA_GCC_UNUSED CattaIfIndex interface,
+ CATTA_GCC_UNUSED CattaIfIndex iface,
CATTA_GCC_UNUSED CattaProtocol protocol,
CattaResolverEvent event,
const char *name,
static void browse_callback(
CattaSServiceBrowser *b,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
const char *name,
the callback function is called the server will free
the resolver for us. */
- if (!(catta_s_service_resolver_new(s, interface, protocol, name, type, domain, CATTA_PROTO_UNSPEC, 0, resolve_callback, s)))
+ if (!(catta_s_service_resolver_new(s, iface, protocol, name, type, domain, CATTA_PROTO_UNSPEC, 0, resolve_callback, s)))
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, catta_strerror(catta_server_errno(s)));
break;
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
#include <assert.h>
#include <catta/core.h>
}
}
+static void signal_exit(int signum) {
+ int errnosave = errno;
+ catta_simple_poll_quit(simple_poll);
+ errno = errnosave;
+
+ (void)signum; // ignore
+}
+
int main(CATTA_GCC_UNUSED int argc, CATTA_GCC_UNUSED char*argv[]) {
CattaServerConfig config;
CattaServer *server = NULL;
goto fail;
}
+ /* exit cleanly on signals */
+ signal(SIGINT, signal_exit);
+ signal(SIGTERM, signal_exit);
+
/* Run the main loop */
catta_simple_poll_loop(simple_poll);
#define CATTA_ADDRESS_STR_MAX 40 /* IPv6 Max = 4*8 + 7 + 1 for NUL */
/** Return TRUE if the specified interface index is valid */
-#define CATTA_IF_VALID(ifindex) (((ifindex) >= 0) || ((ifindex) == CATTA_IF_UNSPEC))
+#define CATTA_IF_VALID(iface) (((iface) >= 0) || ((iface) == CATTA_IF_UNSPEC))
/** Return TRUE if the specified protocol is valid */
#define CATTA_PROTO_VALID(protocol) (((protocol) == CATTA_PROTO_INET) || ((protocol) == CATTA_PROTO_INET6) || ((protocol) == CATTA_PROTO_UNSPEC))
*_head = _item; \
} while (0)
+/** Append an item to the list */
+#define CATTA_LLIST_APPEND(t,name,head,item) do { \
+ t **_cur = &(head), *_prev, *_item = (item); \
+ assert(_item); \
+ while ((_prev = *_cur)) \
+ _cur = &_prev->name##_next; \
+ _item->name##_prev = _prev; \
+ _item->name##_next = NULL; \
+ *_cur = _item; \
+ } while (0)
+
/** Remove an item from the list */
#define CATTA_LLIST_REMOVE(t,name,head,item) do { \
t **_head = &(head), *_item = (item); \
/** Callback prototype for CattaSRecordBrowser events */
typedef void (*CattaSRecordBrowserCallback)(
CattaSRecordBrowser *b, /**< The CattaSRecordBrowser object that is emitting this callback */
- CattaIfIndex interface, /**< Logical OS network interface number the record was found on */
+ CattaIfIndex iface, /**< Logical OS network interface number the record was found on */
CattaProtocol protocol, /**< Protocol number the record was found. */
CattaBrowserEvent event, /**< Browsing event, either CATTA_BROWSER_NEW or CATTA_BROWSER_REMOVE */
CattaRecord *record, /**< The record that was found */
/** Create a new browsing object for arbitrary RRs */
CattaSRecordBrowser *catta_s_record_browser_new(
CattaServer *server, /**< The server object to which attach this query */
- CattaIfIndex interface, /**< Logical OS interface number where to look for the records, or CATTA_IF_UNSPEC to look on interfaces */
+ CattaIfIndex iface, /**< Logical OS interface number where to look for the records, or CATTA_IF_UNSPEC to look on interfaces */
CattaProtocol protocol, /**< Protocol number to use when looking for the record, or CATTA_PROTO_UNSPEC to look on all protocols */
CattaKey *key, /**< The search key */
CattaLookupFlags flags, /**< Lookup flags. Must have set either CATTA_LOOKUP_FORCE_WIDE_AREA or CATTA_LOOKUP_FORCE_MULTICAST, since domain based detection is not available here. */
/** Callback prototype for CattaSHostNameResolver events */
typedef void (*CattaSHostNameResolverCallback)(
CattaSHostNameResolver *r,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaResolverEvent event, /**< Resolving event */
const char *host_name, /**< Host name which should be resolved. May differ in case from the query */
/** Create an CattaSHostNameResolver object for resolving a host name to an adddress. See CattaSRecordBrowser for more info on the paramters. */
CattaSHostNameResolver *catta_s_host_name_resolver_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *host_name, /**< The host name to look for */
CattaProtocol aprotocol, /**< The address family of the desired address or CATTA_PROTO_UNSPEC if doesn't matter. */
/** Callback prototype for CattaSAddressResolver events */
typedef void (*CattaSAddressResolverCallback)(
CattaSAddressResolver *r,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaResolverEvent event,
const CattaAddress *a,
/** Create an CattaSAddressResolver object. See CattaSRecordBrowser for more info on the paramters. */
CattaSAddressResolver *catta_s_address_resolver_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const CattaAddress *address,
CattaLookupFlags flags, /**< Lookup flags. */
/** Callback prototype for CattaSDomainBrowser events */
typedef void (*CattaSDomainBrowserCallback)(
CattaSDomainBrowser *b,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
const char *domain,
/** Create a new CattaSDomainBrowser object */
CattaSDomainBrowser *catta_s_domain_browser_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *domain,
CattaDomainBrowserType type,
/** Callback prototype for CattaSServiceTypeBrowser events */
typedef void (*CattaSServiceTypeBrowserCallback)(
CattaSServiceTypeBrowser *b,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
const char *type,
/** Create a new CattaSServiceTypeBrowser object. */
CattaSServiceTypeBrowser *catta_s_service_type_browser_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *domain,
CattaLookupFlags flags, /**< Lookup flags. */
/** Callback prototype for CattaSServiceBrowser events */
typedef void (*CattaSServiceBrowserCallback)(
CattaSServiceBrowser *b,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
const char *name /**< Service name, e.g. "Lennart's Files" */,
/** Create a new CattaSServiceBrowser object. */
CattaSServiceBrowser *catta_s_service_browser_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *service_type /** DNS-SD service type, e.g. "_http._tcp" */,
const char *domain,
/** Callback prototype for CattaSServiceResolver events */
typedef void (*CattaSServiceResolverCallback)(
CattaSServiceResolver *r,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaResolverEvent event, /**< Is CATTA_RESOLVER_FOUND when the service was resolved successfully, and everytime it changes. Is CATTA_RESOLVER_TIMOUT when the service failed to resolve or disappeared. */
const char *name, /**< Service name */
/** Create a new CattaSServiceResolver object. The specified callback function will be called with the resolved service data. */
CattaSServiceResolver *catta_s_service_resolver_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *name,
const char *type,
int catta_server_add(
CattaServer *s, /**< The server object to add this record to */
CattaSEntryGroup *g, /**< An entry group object if this new record shall be attached to one, or NULL. If you plan to remove the record sometime later you a required to pass an entry group object here. */
- CattaIfIndex interface, /**< A numeric index of a network interface to attach this record to, or CATTA_IF_UNSPEC to attach this record to all interfaces */
+ CattaIfIndex iface, /**< A numeric index of a network interface to attach this record to, or CATTA_IF_UNSPEC to attach this record to all interfaces */
CattaProtocol protocol, /**< A protocol family to attach this record to. One of the CATTA_PROTO_xxx constants. Use CATTA_PROTO_UNSPEC to make this record available on all protocols (wich means on both IPv4 and IPv6). */
CattaPublishFlags flags, /**< Special flags for this record */
CattaRecord *r /**< The record to add. This function increases the reference counter of this object. */);
int catta_server_add_address(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
int catta_server_add_service(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name, /**< Service name, e.g. "Lennart's Files" */
int catta_server_add_service_strlst(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
int catta_server_add_service_subtype(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name, /**< Specify the name of main service you already added here */
int catta_server_update_service_txt_strlst(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
int catta_server_update_service_txt(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
...) CATTA_GCC_SENTINEL;
/** Check if there is a service locally defined and return the entry group it is attached to. Returns NULL if the service isn't local*/
-int catta_server_get_group_of_service(CattaServer *s, CattaIfIndex interface, CattaProtocol protocol, const char *name, const char *type, const char *domain, CattaSEntryGroup** ret_group);
+int catta_server_get_group_of_service(CattaServer *s, CattaIfIndex iface, CattaProtocol protocol, const char *name, const char *type, const char *domain, CattaSEntryGroup** ret_group);
CATTA_C_DECL_END
#
# -Wl,-z,defs forces link-time symbol resolution, so that the
# linking checks with -shared actually have any value
+ # The Mingw32 equivalent to -z defs seems to be --error-unresolved-symbols.
#
# FIXME: -fPIC is required for -shared on many architectures,
# so we specify it here, but the right way would probably be to
# properly detect whether it is actually required.
- CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS"
+ zdefs="-z,defs"
+ case "${host_os}" in
+ *mingw32*) zdefs="--unresolved-symbols=report-all,--error-unresolved-symbols"
+ esac
+ CFLAGS="-shared -fPIC -Wl,$zdefs $CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CC="$PTHREAD_CC"
libcatta_la_SOURCES += \
iface-pfroute.c iface-pfroute.h
else
+if WINDOWS
+libcatta_la_SOURCES += \
+ iface-windows.c iface-windows.h
+else
libcatta_la_SOURCES += \
iface-none.c
endif
endif
+endif
libcatta_la_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS)
-libcatta_la_LIBADD = $(AM_LDADD) $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) $(INTLLIBS)
-libcatta_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBCATTA_VERSION_INFO)
+libcatta_la_LIBADD = $(AM_LDADD) $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+libcatta_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBCATTA_VERSION_INFO)
+
+if WINDOWS
+libcatta_la_SOURCES += \
+ compat/windows/wincompat.c \
+ compat/windows/wincompat.h
+libcatta_la_LIBADD += -lws2_32 -liphlpapi
+libcatta_la_LDFLAGS += -no-undefined
+endif
+
assert(length);
assert(a);
- if (!(inet_ntop(catta_proto_to_af(a->proto), a->data.data, s, length)))
+ if (!(inet_ntop(catta_proto_to_af(a->proto), (void *)a->data.data, s, length)))
return NULL;
return s;
if (a->time_event)
catta_time_event_free(a->time_event);
- CATTA_LLIST_REMOVE(CattaAnnouncer, by_interface, a->interface->announcers, a);
+ CATTA_LLIST_REMOVE(CattaAnnouncer, by_interface, a->iface->announcers, a);
CATTA_LLIST_REMOVE(CattaAnnouncer, by_entry, a->entry->announcers, a);
catta_free(a);
} else {
struct timeval tv;
- catta_interface_post_probe(a->interface, a->entry->record, 0);
+ catta_interface_post_probe(a->iface, a->entry->record, 0);
catta_elapse_time(&tv, CATTA_PROBE_INTERVAL_MSEC, 0);
set_timeout(a, &tv);
if (a->entry->flags & CATTA_PUBLISH_UNIQUE)
/* Send the whole rrset at once */
- catta_server_prepare_matching_responses(a->server, a->interface, a->entry->record->key, 0);
+ catta_server_prepare_matching_responses(a->server, a->iface, a->entry->record->key, 0);
else
- catta_server_prepare_response(a->server, a->interface, a->entry, 0, 0);
+ catta_server_prepare_response(a->server, a->iface, a->entry, 0, 0);
- catta_server_generate_response(a->server, a->interface, NULL, NULL, 0, 0, 0);
+ catta_server_generate_response(a->server, a->iface, NULL, NULL, 0, 0, 0);
if (++a->n_iteration >= 4) {
/* Announcing done */
assert(i);
for (a = e->announcers; a; a = a->by_entry_next)
- if (a->interface == i)
+ if (a->iface == i)
return a;
return NULL;
assert(e);
assert(!e->dead);
- if (!catta_interface_match(i, e->interface, e->protocol) || !i->announcing || !catta_entry_is_commited(e))
+ if (!catta_interface_match(i, e->iface, e->protocol) || !i->announcing || !catta_entry_is_commited(e))
return;
/* We don't want duplicate announcers */
}
a->server = s;
- a->interface = i;
+ a->iface = i;
a->entry = e;
a->time_event = NULL;
assert(e);
assert(!e->dead);
- catta_interface_monitor_walk(s->monitor, e->interface, e->protocol, announce_walk_callback, e);
+ catta_interface_monitor_walk(s->monitor, e->iface, e->protocol, announce_walk_callback, e);
}
void catta_announce_group(CattaServer *s, CattaSEntryGroup *g) {
assert(e);
assert(!e->dead);
- if (!catta_interface_match(i, e->interface, e->protocol))
+ if (!catta_interface_match(i, e->iface, e->protocol))
return;
if (e->flags & CATTA_PUBLISH_NO_ANNOUNCE)
assert(e);
assert(!e->dead);
- catta_interface_monitor_walk(s->monitor, e->interface, e->protocol, reannounce_walk_callback, e);
+ catta_interface_monitor_walk(s->monitor, e->iface, e->protocol, reannounce_walk_callback, e);
}
void catta_goodbye_interface(CattaServer *s, CattaInterface *i, int send_goodbye, int remove) {
struct CattaAnnouncer {
CattaServer *server;
- CattaInterface *interface;
+ CattaInterface *iface;
CattaEntry *entry;
CattaTimeEvent *time_event;
struct CattaDNSServerInfo {
CattaSDNSServerBrowser *browser;
- CattaIfIndex interface;
+ CattaIfIndex iface;
CattaProtocol protocol;
CattaRecord *srv_record;
CattaSHostNameResolver *host_name_resolver;
CATTA_LLIST_HEAD(CattaDNSServerInfo, info);
};
-static CattaDNSServerInfo* get_server_info(CattaSDNSServerBrowser *b, CattaIfIndex interface, CattaProtocol protocol, CattaRecord *r) {
+static CattaDNSServerInfo* get_server_info(CattaSDNSServerBrowser *b, CattaIfIndex iface, CattaProtocol protocol, CattaRecord *r) {
CattaDNSServerInfo *i;
assert(b);
assert(r);
for (i = b->info; i; i = i->info_next)
- if (i->interface == interface &&
+ if (i->iface == iface &&
i->protocol == protocol &&
catta_record_equal_no_ttl(r, i->srv_record))
return i;
static void host_name_resolver_callback(
CattaSHostNameResolver *r,
- CATTA_GCC_UNUSED CattaIfIndex interface,
+ CATTA_GCC_UNUSED CattaIfIndex iface,
CATTA_GCC_UNUSED CattaProtocol protocol,
CattaResolverEvent event,
const char *host_name,
i->browser->callback(
i->browser,
- i->interface,
+ i->iface,
i->protocol,
CATTA_BROWSER_NEW,
i->srv_record->data.srv.name,
static void record_browser_callback(
CattaSRecordBrowser*rr,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
CattaRecord *record,
assert(record);
assert(record->key->type == CATTA_DNS_TYPE_SRV);
- if (get_server_info(b, interface, protocol, record))
+ if (get_server_info(b, iface, protocol, record))
return;
if (b->n_info >= 10)
return; /* OOM */
i->browser = b;
- i->interface = interface;
+ i->iface = iface;
i->protocol = protocol;
i->srv_record = catta_record_ref(record);
i->host_name_resolver = catta_s_host_name_resolver_new(
b->server,
- interface, protocol,
+ iface, protocol,
record->data.srv.name,
b->aprotocol,
b->user_flags,
assert(record);
assert(record->key->type == CATTA_DNS_TYPE_SRV);
- if (!(i = get_server_info(b, interface, protocol, record)))
+ if (!(i = get_server_info(b, iface, protocol, record)))
return;
if (!i->host_name_resolver)
b->callback(
b,
- interface,
+ iface,
protocol,
event,
i->srv_record->data.srv.name,
b->callback(
b,
- interface,
+ iface,
protocol,
event,
NULL,
CattaSDNSServerBrowser *catta_s_dns_server_browser_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *domain,
CattaDNSServerType type,
assert(server);
assert(callback);
- CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_PROTO_VALID(aprotocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, !domain || catta_is_valid_domain_name(domain), CATTA_ERR_INVALID_DOMAIN_NAME);
goto fail;
}
- if (!(b->record_browser = catta_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, b)))
+ if (!(b->record_browser = catta_s_record_browser_new(server, iface, protocol, k, flags, record_browser_callback, b)))
goto fail;
catta_key_unref(k);
static void record_browser_callback(
CattaSRecordBrowser*rr,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
CattaRecord *record,
}
- b->callback(b, interface, protocol, event, n, flags, b->userdata);
+ b->callback(b, iface, protocol, event, n, flags, b->userdata);
}
static void defer_callback(CattaTimeEvent *e, void *userdata) {
CattaSDomainBrowser *catta_s_domain_browser_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *domain,
CattaDomainBrowserType type,
assert(server);
assert(callback);
- CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, type < CATTA_DOMAIN_BROWSER_MAX, CATTA_ERR_INVALID_FLAGS);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, !domain || catta_is_valid_domain_name(domain), CATTA_ERR_INVALID_DOMAIN_NAME);
goto fail;
}
- if (!(b->record_browser = catta_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, b)))
+ if (!(b->record_browser = catta_s_record_browser_new(server, iface, protocol, k, flags, record_browser_callback, b)))
goto fail;
catta_key_unref(k);
static void record_browser_callback(
CattaSRecordBrowser*rr,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
CattaRecord *record,
return;
}
- b->callback(b, interface, protocol, event, type, domain, flags, b->userdata);
+ b->callback(b, iface, protocol, event, type, domain, flags, b->userdata);
} else
- b->callback(b, interface, protocol, event, NULL, b->domain_name, flags, b->userdata);
+ b->callback(b, iface, protocol, event, NULL, b->domain_name, flags, b->userdata);
}
CattaSServiceTypeBrowser *catta_s_service_type_browser_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *domain,
CattaLookupFlags flags,
assert(server);
assert(callback);
- CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, !domain || catta_is_valid_domain_name(domain), CATTA_ERR_INVALID_DOMAIN_NAME);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_FLAGS_VALID(flags, CATTA_LOOKUP_USE_WIDE_AREA|CATTA_LOOKUP_USE_MULTICAST), CATTA_ERR_INVALID_FLAGS);
goto fail;
}
- if (!(b->record_browser = catta_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, b)))
+ if (!(b->record_browser = catta_s_record_browser_new(server, iface, protocol, k, flags, record_browser_callback, b)))
goto fail;
catta_key_unref(k);
static void record_browser_callback(
CattaSRecordBrowser*rr,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
CattaRecord *record,
assert(record->key->type == CATTA_DNS_TYPE_PTR);
- if (event == CATTA_BROWSER_NEW && catta_server_is_service_local(b->server, interface, protocol, record->data.ptr.name))
+ if (event == CATTA_BROWSER_NEW && catta_server_is_service_local(b->server, iface, protocol, record->data.ptr.name))
flags |= CATTA_LOOKUP_RESULT_LOCAL;
if (catta_service_name_split(record->data.ptr.name, service, sizeof(service), type, sizeof(type), domain, sizeof(domain)) < 0) {
return;
}
- b->callback(b, interface, protocol, event, service, type, domain, flags, b->userdata);
+ b->callback(b, iface, protocol, event, service, type, domain, flags, b->userdata);
} else
- b->callback(b, interface, protocol, event, NULL, b->service_type, b->domain_name, flags, b->userdata);
+ b->callback(b, iface, protocol, event, NULL, b->service_type, b->domain_name, flags, b->userdata);
}
CattaSServiceBrowser *catta_s_service_browser_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *service_type,
const char *domain,
assert(callback);
assert(service_type);
- CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, !domain || catta_is_valid_domain_name(domain), CATTA_ERR_INVALID_DOMAIN_NAME);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_FLAGS_VALID(flags, CATTA_LOOKUP_USE_WIDE_AREA|CATTA_LOOKUP_USE_MULTICAST), CATTA_ERR_INVALID_FLAGS);
goto fail;
}
- if (!(b->record_browser = catta_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, b)))
+ if (!(b->record_browser = catta_s_record_browser_new(server, iface, protocol, k, flags, record_browser_callback, b)))
goto fail;
catta_key_unref(k);
unsigned ref;
- CattaIfIndex interface;
+ CattaIfIndex iface;
CattaProtocol protocol;
CattaLookupFlags flags;
CATTA_LLIST_FIELDS(CattaSRBLookup, lookups);
};
-static void lookup_handle_cname(CattaSRBLookup *l, CattaIfIndex interface, CattaProtocol protocol, CattaLookupFlags flags, CattaRecord *r);
-static void lookup_drop_cname(CattaSRBLookup *l, CattaIfIndex interface, CattaProtocol protocol, CattaLookupFlags flags, CattaRecord *r);
+static void lookup_handle_cname(CattaSRBLookup *l, CattaIfIndex iface, CattaProtocol protocol, CattaLookupFlags flags, CattaRecord *r);
+static void lookup_drop_cname(CattaSRBLookup *l, CattaIfIndex iface, CattaProtocol protocol, CattaLookupFlags flags, CattaRecord *r);
static void transport_flags_from_domain(CattaServer *s, CattaLookupFlags *flags, const char *domain) {
assert(flags);
static CattaSRBLookup* lookup_new(
CattaSRecordBrowser *b,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaLookupFlags flags,
CattaKey *key) {
CattaSRBLookup *l;
assert(b);
- assert(CATTA_IF_VALID(interface));
+ assert(CATTA_IF_VALID(iface));
assert(CATTA_PROTO_VALID(protocol));
if (b->n_lookups >= CATTA_LOOKUPS_PER_BROWSER_MAX)
l->ref = 1;
l->record_browser = b;
- l->interface = interface;
+ l->iface = iface;
l->protocol = protocol;
l->key = catta_key_ref(key);
l->wide_area = NULL;
static CattaSRBLookup *lookup_find(
CattaSRecordBrowser *b,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaLookupFlags flags,
CattaKey *key) {
for (l = b->lookups; l; l = l->lookups_next) {
- if ((l->interface == CATTA_IF_UNSPEC || l->interface == interface) &&
- (l->interface == CATTA_PROTO_UNSPEC || l->protocol == protocol) &&
+ if ((l->iface == CATTA_IF_UNSPEC || l->iface == iface) &&
+ (l->iface == CATTA_PROTO_UNSPEC || l->protocol == protocol) &&
l->flags == flags &&
catta_key_equal(l->key, key))
static void lookup_multicast_callback(
CattaMulticastLookupEngine *e,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
CattaLookupResultFlags flags,
if (r->key->clazz == CATTA_DNS_CLASS_IN &&
r->key->type == CATTA_DNS_TYPE_CNAME)
/* It's a CNAME record, so let's follow it. We allow browsing on both multicast and wide area. */
- lookup_handle_cname(l, interface, protocol, b->flags, r);
+ lookup_handle_cname(l, iface, protocol, b->flags, r);
else {
/* It's a normal record, so let's call the user callback */
- if (catta_server_is_record_local(b->server, interface, protocol, r))
+ if (catta_server_is_record_local(b->server, iface, protocol, r))
flags |= CATTA_LOOKUP_RESULT_LOCAL;
- b->callback(b, interface, protocol, event, r, flags, b->userdata);
+ b->callback(b, iface, protocol, event, r, flags, b->userdata);
}
break;
if (r->key->clazz == CATTA_DNS_CLASS_IN &&
r->key->type == CATTA_DNS_TYPE_CNAME)
/* It's a CNAME record, so let's drop that query! */
- lookup_drop_cname(l, interface, protocol, 0, r);
+ lookup_drop_cname(l, iface, protocol, 0, r);
else {
/* It's a normal record, so let's call the user callback */
assert(catta_key_equal(b->key, l->key));
- b->callback(b, interface, protocol, event, r, flags, b->userdata);
+ b->callback(b, iface, protocol, event, r, flags, b->userdata);
}
break;
} else {
assert(l->flags & CATTA_LOOKUP_USE_MULTICAST);
- if (!(l->multicast = catta_multicast_lookup_new(l->record_browser->server->multicast_lookup_engine, l->interface, l->protocol, l->key, lookup_multicast_callback, l)))
+ if (!(l->multicast = catta_multicast_lookup_new(l->record_browser->server->multicast_lookup_engine, l->iface, l->protocol, l->key, lookup_multicast_callback, l)))
return -1;
}
} else {
assert(l->flags & CATTA_LOOKUP_USE_MULTICAST);
- n = (int) catta_multicast_lookup_engine_scan_cache(l->record_browser->server->multicast_lookup_engine, l->interface, l->protocol, l->key, lookup_multicast_callback, l);
+ n = (int) catta_multicast_lookup_engine_scan_cache(l->record_browser->server->multicast_lookup_engine, l->iface, l->protocol, l->key, lookup_multicast_callback, l);
}
return n;
}
-static CattaSRBLookup* lookup_add(CattaSRecordBrowser *b, CattaIfIndex interface, CattaProtocol protocol, CattaLookupFlags flags, CattaKey *key) {
+static CattaSRBLookup* lookup_add(CattaSRecordBrowser *b, CattaIfIndex iface, CattaProtocol protocol, CattaLookupFlags flags, CattaKey *key) {
CattaSRBLookup *l;
assert(b);
assert(!b->dead);
- if ((l = lookup_find(b, interface, protocol, flags, key)))
+ if ((l = lookup_find(b, iface, protocol, flags, key)))
return lookup_ref(l);
- if (!(l = lookup_new(b, interface, protocol, flags, key)))
+ if (!(l = lookup_new(b, iface, protocol, flags, key)))
return NULL;
return l;
return n;
}
-static void lookup_handle_cname(CattaSRBLookup *l, CattaIfIndex interface, CattaProtocol protocol, CattaLookupFlags flags, CattaRecord *r) {
+static void lookup_handle_cname(CattaSRBLookup *l, CattaIfIndex iface, CattaProtocol protocol, CattaLookupFlags flags, CattaRecord *r) {
CattaKey *k;
CattaSRBLookup *n;
assert(r->key->type == CATTA_DNS_TYPE_CNAME);
k = catta_key_new(r->data.ptr.name, l->record_browser->key->clazz, l->record_browser->key->type);
- n = lookup_add(l->record_browser, interface, protocol, flags, k);
+ n = lookup_add(l->record_browser, iface, protocol, flags, k);
catta_key_unref(k);
if (!n) {
lookup_unref(n);
}
-static void lookup_drop_cname(CattaSRBLookup *l, CattaIfIndex interface, CattaProtocol protocol, CattaLookupFlags flags, CattaRecord *r) {
+static void lookup_drop_cname(CattaSRBLookup *l, CattaIfIndex iface, CattaProtocol protocol, CattaLookupFlags flags, CattaRecord *r) {
CattaKey *k;
CattaSRBLookup *n = NULL;
CattaRList *rl;
assert(n);
- if ((n->interface == CATTA_IF_UNSPEC || n->interface == interface) &&
- (n->interface == CATTA_PROTO_UNSPEC || n->protocol == protocol) &&
+ if ((n->iface == CATTA_IF_UNSPEC || n->iface == iface) &&
+ (n->iface == CATTA_PROTO_UNSPEC || n->protocol == protocol) &&
n->flags == flags &&
catta_key_equal(n->key, k))
break;
/* Create initial query */
assert(!b->root_lookup);
- b->root_lookup = lookup_add(b, b->interface, b->protocol, b->flags, b->key);
+ b->root_lookup = lookup_add(b, b->iface, b->protocol, b->flags, b->key);
assert(b->root_lookup);
n = lookup_go(b->root_lookup);
catta_server_set_errno(b->server, CATTA_ERR_FAILURE);
b->callback(
- b, b->interface, b->protocol, CATTA_BROWSER_FAILURE, NULL,
+ b, b->iface, b->protocol, CATTA_BROWSER_FAILURE, NULL,
b->flags & CATTA_LOOKUP_USE_WIDE_AREA ? CATTA_LOOKUP_RESULT_WIDE_AREA : CATTA_LOOKUP_RESULT_MULTICAST,
b->userdata);
/* Tell the client that we're done with the cache */
b->callback(
- b, b->interface, b->protocol, CATTA_BROWSER_CACHE_EXHAUSTED, NULL,
+ b, b->iface, b->protocol, CATTA_BROWSER_CACHE_EXHAUSTED, NULL,
b->flags & CATTA_LOOKUP_USE_WIDE_AREA ? CATTA_LOOKUP_RESULT_WIDE_AREA : CATTA_LOOKUP_RESULT_MULTICAST,
b->userdata);
* entries, we assume that it is complete, and tell the user
* so by firing ALL_FOR_NOW. */
- b->callback(b, b->interface, b->protocol, CATTA_BROWSER_ALL_FOR_NOW, NULL, CATTA_LOOKUP_RESULT_WIDE_AREA, b->userdata);
+ b->callback(b, b->iface, b->protocol, CATTA_BROWSER_ALL_FOR_NOW, NULL, CATTA_LOOKUP_RESULT_WIDE_AREA, b->userdata);
}
}
CattaSRecordBrowser *catta_s_record_browser_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaKey *key,
CattaLookupFlags flags,
assert(key);
assert(callback);
- CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, !catta_key_is_pattern(key), CATTA_ERR_IS_PATTERN);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, catta_key_is_valid(key), CATTA_ERR_INVALID_KEY);
b->dead = 0;
b->server = server;
- b->interface = interface;
+ b->iface = iface;
b->protocol = protocol;
b->key = catta_key_ref(key);
b->flags = flags;
CattaServer *server;
CattaKey *key;
- CattaIfIndex interface;
+ CattaIfIndex iface;
CattaProtocol protocol;
CattaLookupFlags flags;
if (e->time_event)
catta_time_event_free(e->time_event);
- catta_multicast_lookup_engine_notify(c->server->multicast_lookup_engine, c->interface, e->record, CATTA_BROWSER_REMOVE);
+ catta_multicast_lookup_engine_notify(c->server->multicast_lookup_engine, c->iface, e->record, CATTA_BROWSER_REMOVE);
catta_record_unref(e->record);
}
c->server = server;
- c->interface = iface;
+ c->iface = iface;
if (!(c->hashmap = catta_hashmap_new((CattaHashFunc) catta_key_hash, (CattaEqualFunc) catta_key_equal, NULL, NULL))) {
catta_log_error(__FILE__": Out of memory.");
assert(percent > 0);
/* Request a cache update if we are subscribed to this entry */
- if (catta_querier_shall_refresh_cache(e->cache->interface, e->record->key))
- catta_interface_post_query(e->cache->interface, e->record->key, 0, NULL);
+ if (catta_querier_shall_refresh_cache(e->cache->iface, e->record->key))
+ catta_interface_post_query(e->cache->iface, e->record->key, 0, NULL);
/* Check again later */
next_expiry(e->cache, e, percent);
c->n_entries++;
/* Notify subscribers */
- catta_multicast_lookup_engine_notify(c->server->multicast_lookup_engine, c->interface, e->record, CATTA_BROWSER_NEW);
+ catta_multicast_lookup_engine_notify(c->server->multicast_lookup_engine, c->iface, e->record, CATTA_BROWSER_NEW);
}
e->origin = *a;
struct CattaCache {
CattaServer *server;
- CattaInterface *interface;
+ CattaInterface *iface;
CattaHashmap *hashmap;
time_t last_rand_timestamp;
};
-CattaCache *catta_cache_new(CattaServer *server, CattaInterface *interface);
+CattaCache *catta_cache_new(CattaServer *server, CattaInterface *iface);
void catta_cache_free(CattaCache *c);
void catta_cache_update(CattaCache *c, CattaRecord *r, int cache_flush, const CattaAddress *a);
--- /dev/null
+#include "../../wincompat.h"
--- /dev/null
+#include "../../wincompat.h"
--- /dev/null
+#include "../../wincompat.h"
--- /dev/null
+#include "../../wincompat.h"
--- /dev/null
+#include "../../wincompat.h"
--- /dev/null
+#include "../../wincompat.h"
--- /dev/null
+#include "../../wincompat.h"
--- /dev/null
+#include "../../wincompat.h"
--- /dev/null
+#include "../../wincompat.h"
--- /dev/null
+#include "wincompat.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdint.h>
+
+#include <catta/log.h>
+
+// helper: convert WSAGetLastError() to an errno constant
+static int wsa_errno(void)
+{
+ switch(WSAGetLastError()) {
+ case WSAEACCES: return EACCES;
+ case WSAECONNRESET: return ECONNRESET;
+ case WSAEFAULT: return EFAULT;
+ case WSAEINPROGRESS: return EINPROGRESS;
+ case WSAEINTR: return EINTR;
+ case WSAEINVAL: return EINVAL;
+ case WSAEMSGSIZE: return EMSGSIZE;
+ case WSAENETDOWN: return ENETDOWN;
+ case WSAENETRESET: return ENETRESET;
+ case WSAENOBUFS: return ENOBUFS;
+ case WSAENOTCONN: return ENOTCONN;
+ case WSAENOTSOCK: return ENOTSOCK;
+ case WSAEOPNOTSUPP: return EOPNOTSUPP;
+ case WSAESHUTDOWN: return ESHUTDOWN;
+ case WSAETIMEDOUT: return ETIMEDOUT;
+ case WSAEWOULDBLOCK: return EWOULDBLOCK;
+ default:
+ return EINVAL;
+ }
+}
+
+void winsock_init(void)
+{
+ WSADATA wsa;
+ int error;
+
+ if((error = WSAStartup(MAKEWORD(2,2), &wsa)) != 0)
+ catta_log_error("WSAStartup() failed: %d", error);
+}
+
+void winsock_exit(void)
+{
+ if(WSACleanup() == SOCKET_ERROR)
+ catta_log_warn("WSACleanup() failed: %d", WSAGetLastError());
+}
+
+char *errnostrsocket(void)
+{
+ static char buf[256];
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, WSAGetLastError(), 0, buf, sizeof(buf), NULL);
+
+ return buf;
+}
+
+ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
+{
+ LPFN_WSARECVMSG WSARecvMsg = NULL;
+ GUID wsaid = WSAID_WSARECVMSG;
+ DWORD b;
+
+ DWORD bytesrcvd;
+ WSAMSG wsamsg;
+ size_t i;
+ int r;
+
+ // size_t is larger than DWORD on 64bit
+ if(msg->msg_iovlen > UINT32_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // obtain the function pointer to WSARecvMsg
+ r = WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &wsaid, sizeof(wsaid), &WSARecvMsg, sizeof(WSARecvMsg),
+ &b, NULL, NULL);
+ if(r == SOCKET_ERROR) {
+ errno = wsa_errno();
+ return -1;
+ }
+ assert(b == sizeof(WSARecvMsg));
+ assert(WSARecvMsg != NULL);
+
+ // convert msghdr to WSAMSG structure
+ wsamsg.name = msg->msg_name;
+ wsamsg.namelen = msg->msg_namelen;
+ wsamsg.lpBuffers = malloc(msg->msg_iovlen * sizeof(WSABUF));
+ wsamsg.dwBufferCount = msg->msg_iovlen;
+ wsamsg.Control.len = msg->msg_controllen;
+ wsamsg.Control.buf = msg->msg_control;
+ wsamsg.dwFlags = (DWORD)flags;
+
+ // all flags that fit into dwFlags also fit through the flags argument
+ assert(sizeof(DWORD) <= sizeof(flags));
+
+ if(wsamsg.lpBuffers == NULL) {
+ // malloc will have set errno
+ return -1;
+ }
+
+ // re-wrap iovecs as WSABUFs
+ for(i=0; i<msg->msg_iovlen; i++) {
+ // size_t vs. u_long
+ if(msg->msg_iov[i].iov_len > ULONG_MAX) {
+ free(wsamsg.lpBuffers);
+ errno = EINVAL;
+ return -1;
+ }
+
+ wsamsg.lpBuffers[i].len = msg->msg_iov[i].iov_len;
+ wsamsg.lpBuffers[i].buf = msg->msg_iov[i].iov_base;
+ }
+
+ r = WSARecvMsg(sockfd, &wsamsg, &bytesrcvd, NULL, NULL);
+
+ // the allocated WSABUF wrappers are no longer needed
+ free(wsamsg.lpBuffers);
+
+ if(r == SOCKET_ERROR) {
+ // XXX do we need special handling for ENETRESET, EMSGSIZE, ETIMEDOUT?
+ errno = wsa_errno();
+ return -1;
+ }
+
+ // DWORD has one bit more than ssize_t on 32bit
+ // XXX check for this condition before the WSARecvMsg call
+ if(bytesrcvd > SSIZE_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // transfer results from wsamsg to msg
+ // NB: the data and control buffers are shared
+ msg->msg_controllen = wsamsg.Control.len;
+ msg->msg_flags = (int)wsamsg.dwFlags;
+ // all flags that fit into dwFlags also fit into msg_flags (see above)
+
+ return bytesrcvd;
+}
+
+ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
+{
+ LPFN_WSASENDMSG WSASendMsg = NULL;
+ GUID wsaid = WSAID_WSASENDMSG;
+ DWORD b;
+
+ DWORD bytessent;
+ WSAMSG wsamsg;
+ size_t i;
+ int r;
+
+ // size_t is larger than DWORD on 64bit
+ if(msg->msg_iovlen > UINT32_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // obtain the function pointer to WSASendMsg
+ r = WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &wsaid, sizeof(wsaid), &WSASendMsg, sizeof(WSASendMsg),
+ &b, NULL, NULL);
+ if(r == SOCKET_ERROR) {
+ errno = wsa_errno();
+ return -1;
+ }
+ assert(b == sizeof(WSASendMsg));
+ assert(WSASendMsg != NULL);
+
+ // convert msghdr to WSAMSG structure
+ wsamsg.name = msg->msg_name;
+ wsamsg.namelen = msg->msg_namelen;
+ wsamsg.lpBuffers = malloc(msg->msg_iovlen * sizeof(WSABUF));
+ wsamsg.dwBufferCount = msg->msg_iovlen;
+ wsamsg.Control.len = msg->msg_controllen;
+ wsamsg.Control.buf = msg->msg_control;
+ wsamsg.dwFlags = 0; // ignored
+
+ if(wsamsg.lpBuffers == NULL) {
+ // malloc will have set errno
+ return -1;
+ }
+
+ // re-wrap iovecs as WSABUFs
+ for(i=0; i<msg->msg_iovlen; i++) {
+ // size_t vs. u_long
+ if(msg->msg_iov[i].iov_len > ULONG_MAX) {
+ free(wsamsg.lpBuffers);
+ errno = EINVAL;
+ return -1;
+ }
+
+ wsamsg.lpBuffers[i].len = msg->msg_iov[i].iov_len;
+ wsamsg.lpBuffers[i].buf = msg->msg_iov[i].iov_base;
+ }
+
+ r = WSASendMsg(sockfd, &wsamsg, flags, &bytessent, NULL, NULL);
+
+ // the allocated WSABUF wrappers are no longer needed
+ free(wsamsg.lpBuffers);
+
+ if(r == SOCKET_ERROR) {
+ // XXX do we need special handling for ENETRESET, ETIMEDOUT?
+ errno = wsa_errno();
+ return -1;
+ }
+
+ // DWORD has one bit more than ssize_t on 32bit
+ // XXX check for this condition before sending anything
+ if(bytessent > SSIZE_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return bytessent;
+}
+
+int ioctl(int d, unsigned long request, int *p)
+{
+ u_long arg = *p;
+
+ if(ioctlsocket(d, request, &arg) == SOCKET_ERROR) {
+ errno = wsa_errno();
+ return -1;
+ }
+
+ if(arg > INT_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *p = arg;
+ return 0;
+}
+
+int pipe(int pipefd[2])
+{
+ int lsock = INVALID_SOCKET;
+ struct sockaddr_in laddr;
+ socklen_t laddrlen = sizeof(laddr);
+
+ pipefd[0] = pipefd[1] = INVALID_SOCKET;
+
+ // bind a listening socket to a TCP port on localhost
+ laddr.sin_family = AF_INET;
+ laddr.sin_port = 0;
+ laddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ if((lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
+ goto fail;
+ if(bind(lsock, (struct sockaddr *)&laddr, sizeof(laddr)) == SOCKET_ERROR)
+ goto fail;
+ if(listen(lsock, 1) == SOCKET_ERROR)
+ goto fail;
+
+ // determine which address (i.e. port) we got bound to
+ if(getsockname(lsock, (struct sockaddr *)&laddr, &laddrlen) == SOCKET_ERROR)
+ goto fail;
+ assert(laddrlen == sizeof(laddr));
+ laddr.sin_family = AF_INET;
+ laddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ // connect and accept
+ if((pipefd[0] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
+ goto fail;
+ if(connect(pipefd[0], (const struct sockaddr *)&laddr, sizeof(laddr)) == SOCKET_ERROR)
+ goto fail;
+ if((pipefd[1] = accept(lsock, NULL, NULL)) == SOCKET_ERROR)
+ goto fail;
+
+ // close the listener
+ closesocket(lsock);
+
+ return 0;
+
+fail:
+ errno = wsa_errno();
+ closesocket(pipefd[0]);
+ closesocket(lsock);
+ return -1;
+}
+
+int uname(struct utsname *buf)
+{
+ SYSTEM_INFO si;
+ const char *arch = "unknown";
+
+ memset(buf, 0, sizeof(struct utsname));
+
+ // operating system
+ strncpy(buf->sysname, "Windows", sizeof(buf->sysname)-1);
+ strncpy(buf->release, "unknown", sizeof(buf->sysname)-1); // we don't need it
+ strncpy(buf->version, "unknown", sizeof(buf->sysname)-1); // we don't need it
+
+ // computer (node) name
+ if(GetComputerName(buf->nodename, sizeof(buf->nodename)-1) == 0) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ // hardware type
+ GetSystemInfo(&si);
+ switch(si.wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_AMD64: arch = "amd64"; break;
+ case PROCESSOR_ARCHITECTURE_ARM: arch = "arm"; break;
+ case PROCESSOR_ARCHITECTURE_IA64: arch = "ia64"; break;
+ case PROCESSOR_ARCHITECTURE_INTEL: arch = "x86"; break;
+ default: arch = "unknown";
+ }
+ strncpy(buf->machine, arch, sizeof(buf->machine)-1);
+
+ return 0;
+}
--- /dev/null
+#ifndef foowincompatfoo
+#define foowincompatfoo
+
+// This file and its companion wincompat.c provide some Posix interfaces to
+// Windows APIs so the rest of the code can keep using them.
+
+
+// require at least Windows Vista
+#undef WINVER
+#undef _WIN32_WINNT
+#define WINVER 0x0600
+#define _WIN32_WINNT WINVER
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <mswsock.h>
+
+
+// wrappers around WSAStartup/WSACleanup to avoid clutter
+void winsock_init(void);
+void winsock_exit(void);
+
+
+// the equivalent of strerror(errno) for Windows sockets
+char *errnostrsocket(void);
+
+
+// Winsock doesn't have recvmsg/sendmsg but offers the same functionality
+// with WSARecvMsg/WSASendMsg, so we implement the former in terms of the
+// latter.
+
+struct iovec { /* Scatter/gather array items */
+ void *iov_base; /* Starting address */
+ size_t iov_len; /* Number of bytes to transfer */
+};
+
+struct msghdr {
+ void *msg_name; /* optional address */
+ socklen_t msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ size_t msg_iovlen; /* # elements in msg_iov */
+ void *msg_control; /* ancillary data, see below */
+ size_t msg_controllen; /* ancillary data buffer len */
+ int msg_flags; /* flags on received message */
+};
+
+// MSDN says this struct is called wsacmsghdr but MingW uses _WSACMSGHDR.
+// TODO: Verify what it is on actual Windows.
+// cf. http://msdn.microsoft.com/en-us/library/ms741645(v=vs.85).aspx
+#ifdef __MINGW32__
+#define cmsghdr _WSACMSGHDR // as in 'struct cmsghdr'
+#else
+#define cmsghdr wsacmsghdr // as in 'struct cmsghdr'
+#endif
+
+static inline struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *m) {
+ WSAMSG wm;
+ wm.Control.len = m->msg_controllen;
+ wm.Control.buf = m->msg_control;
+ return WSA_CMSG_FIRSTHDR(&wm);
+}
+
+static inline struct cmsghdr *CMSG_NXTHDR(struct msghdr *m, struct cmsghdr *c) {
+ WSAMSG wm;
+ wm.Control.len = m->msg_controllen;
+ wm.Control.buf = m->msg_control;
+ return WSA_CMSG_NXTHDR(&wm, c);
+}
+
+#define CMSG_SPACE(len) WSA_CMSG_SPACE(len)
+#define CMSG_LEN(len) WSA_CMSG_LEN(len)
+
+// we're going to be naughty and redefine CMSG_DATA as an alias even though it
+// is also a constant defined in wincrypt.h which we don't care about.
+#undef CMSG_DATA
+#define CMSG_DATA(c) WSA_CMSG_DATA(c)
+
+ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
+ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
+
+// ESHUTDOWN does not seem to exist on Windows, even though WSAESHUTDOWN does.
+// MingW doesn't define it and MSDN doesn't list it, so we alias it to EBADF.
+// cf. http://msdn.microsoft.com/en-us/library/5814770t.aspx
+#ifndef ESHUTDOWN
+#define ESHUTDOWN EBADF
+#endif
+
+
+// Windows doesn't have ioctl but offers ioctlsocket for some socket-related
+// functions. Unfortunately, argument types differ, so we implement a
+// (restricted) wrapper.
+int ioctl(int d, unsigned long request, int *p);
+
+
+// Windows lacks poll, but WSAPoll is good enough for us.
+#define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout)
+
+// Windows lacks pipe. It has an equivalent CreatePipe but we really need
+// something to give to WSAPoll, so we fake it with a local TCP socket. (ugh)
+int pipe(int pipefd[2]);
+
+// pipe(socket)-specific read/write/close equivalents
+#define closepipe closesocket
+#define writepipe(s,buf,len) send(s, buf, len, 0)
+#define readpipe(s,buf,len) recv(s, buf, len, 0)
+
+
+// Windows logically doesn't have uname, so we supply a replacement.
+
+struct utsname {
+ char sysname[9]; /* Operating system name (e.g., "Linux") */
+ char nodename[MAX_COMPUTERNAME_LENGTH+1];
+ /* Name within "some implementation-defined network" */
+ char release[9]; /* Operating system release (e.g., "2.6.28") */
+ char version[9]; /* Operating system version */
+ char machine[9]; /* Hardware identifier */
+};
+
+int uname(struct utsname *buf);
+
+
+#endif
int catta_server_add_dns_server_address(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *domain,
/** Callback prototype for CattaSDNSServerBrowser events */
typedef void (*CattaSDNSServerBrowserCallback)(
CattaSDNSServerBrowser *b,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
const char *host_name, /**< Host name of the DNS server, probably useless */
/** Create a new CattaSDNSServerBrowser object */
CattaSDNSServerBrowser *catta_s_dns_server_browser_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *domain,
CattaDNSServerType type,
#include <arpa/inet.h>
-#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/socket.h>
}
}
-static int check_record_conflict(CattaServer *s, CattaIfIndex interface, CattaProtocol protocol, CattaRecord *r, CattaPublishFlags flags) {
+static int check_record_conflict(CattaServer *s, CattaIfIndex iface, CattaProtocol protocol, CattaRecord *r, CattaPublishFlags flags) {
CattaEntry *e;
assert(s);
continue;
}
- if ((interface <= 0 ||
- e->interface <= 0 ||
- e->interface == interface) &&
+ if ((iface <= 0 ||
+ e->iface <= 0 ||
+ e->iface == iface) &&
(protocol == CATTA_PROTO_UNSPEC ||
e->protocol == CATTA_PROTO_UNSPEC ||
e->protocol == protocol))
static CattaEntry * server_add_internal(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
CattaRecord *r) {
assert(r);
CATTA_CHECK_VALIDITY_RETURN_NULL(s, s->state != CATTA_SERVER_FAILURE && s->state != CATTA_SERVER_INVALID, CATTA_ERR_BAD_STATE);
- CATTA_CHECK_VALIDITY_RETURN_NULL(s, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_RETURN_NULL(s, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_RETURN_NULL(s, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(s, CATTA_FLAGS_VALID(
flags,
/* Find the first matching entry */
for (e = catta_hashmap_lookup(s->entries_by_key, r->key); e; e = e->by_key_next) {
- if (!e->dead && e->group == g && e->interface == interface && e->protocol == protocol)
+ if (!e->dead && e->group == g && e->iface == iface && e->protocol == protocol)
break;
is_first = 0;
/* Add a new record */
- if (check_record_conflict(s, interface, protocol, r, flags) < 0) {
+ if (check_record_conflict(s, iface, protocol, r, flags) < 0) {
catta_server_set_errno(s, CATTA_ERR_COLLISION);
return NULL;
}
e->server = s;
e->record = catta_record_ref(r);
e->group = g;
- e->interface = interface;
+ e->iface = iface;
e->protocol = protocol;
e->flags = flags;
e->dead = 0;
int catta_server_add(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
CattaRecord *r) {
- if (!server_add_internal(s, g, interface, protocol, flags, r))
+ if (!server_add_internal(s, g, iface, protocol, flags, r))
return catta_server_errno(s);
return CATTA_OK;
if (!(t = catta_record_to_string(e->record)))
return catta_server_set_errno(s, CATTA_ERR_NO_MEMORY);
- snprintf(ln, sizeof(ln), "%s ; iface=%i proto=%i", t, e->interface, e->protocol);
+ snprintf(ln, sizeof(ln), "%s ; iface=%i proto=%i", t, e->iface, e->protocol);
catta_free(t);
callback(ln, userdata);
static CattaEntry *server_add_ptr_internal(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
uint32_t ttl,
}
r->data.ptr.name = catta_normalize_name_strdup(dest);
- e = server_add_internal(s, g, interface, protocol, flags, r);
+ e = server_add_internal(s, g, iface, protocol, flags, r);
catta_record_unref(r);
return e;
}
int catta_server_add_ptr(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
uint32_t ttl,
assert(s);
- if (!(e = server_add_ptr_internal(s, g, interface, protocol, flags, ttl, name, dest)))
+ if (!(e = server_add_ptr_internal(s, g, iface, protocol, flags, ttl, name, dest)))
return catta_server_errno(s);
return CATTA_OK;
int catta_server_add_address(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
assert(s);
assert(a);
- CATTA_CHECK_VALIDITY(s, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY(s, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY(s, CATTA_PROTO_VALID(protocol) && CATTA_PROTO_VALID(a->proto), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY(s, CATTA_FLAGS_VALID(flags,
CATTA_PUBLISH_NO_REVERSE|
r->data.aaaa.address = a->data.ipv6;
}
- entry = server_add_internal(s, g, interface, protocol, (flags & ~ CATTA_PUBLISH_NO_REVERSE) | CATTA_PUBLISH_UNIQUE | CATTA_PUBLISH_ALLOW_MULTIPLE, r);
+ entry = server_add_internal(s, g, iface, protocol, (flags & ~ CATTA_PUBLISH_NO_REVERSE) | CATTA_PUBLISH_UNIQUE | CATTA_PUBLISH_ALLOW_MULTIPLE, r);
catta_record_unref(r);
if (!entry) {
char reverse_n[CATTA_DOMAIN_NAME_MAX];
catta_reverse_lookup_name(a, reverse_n, sizeof(reverse_n));
- if (!(reverse = server_add_ptr_internal(s, g, interface, protocol, flags | CATTA_PUBLISH_UNIQUE, CATTA_DEFAULT_TTL_HOST_NAME, reverse_n, name))) {
+ if (!(reverse = server_add_ptr_internal(s, g, iface, protocol, flags | CATTA_PUBLISH_UNIQUE, CATTA_DEFAULT_TTL_HOST_NAME, reverse_n, name))) {
ret = catta_server_errno(s);
goto finish;
}
static CattaEntry *server_add_txt_strlst_nocopy(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
uint32_t ttl,
}
r->data.txt.string_list = strlst;
- e = server_add_internal(s, g, interface, protocol, flags, r);
+ e = server_add_internal(s, g, iface, protocol, flags, r);
catta_record_unref(r);
return e;
static int server_add_service_strlst_nocopy(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
assert(type);
assert(name);
- CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_FLAGS_VALID(flags,
CATTA_PUBLISH_NO_COOKIE|
/* Add service enumeration PTR record */
- if (!(ptr_entry = server_add_ptr_internal(s, g, interface, protocol, 0, CATTA_DEFAULT_TTL, ptr_name, svc_name))) {
+ if (!(ptr_entry = server_add_ptr_internal(s, g, iface, protocol, 0, CATTA_DEFAULT_TTL, ptr_name, svc_name))) {
ret = catta_server_errno(s);
goto fail;
}
r->data.srv.port = port;
r->data.srv.name = h;
h = NULL;
- srv_entry = server_add_internal(s, g, interface, protocol, CATTA_PUBLISH_UNIQUE, r);
+ srv_entry = server_add_internal(s, g, iface, protocol, CATTA_PUBLISH_UNIQUE, r);
catta_record_unref(r);
if (!srv_entry) {
if (!(flags & CATTA_PUBLISH_NO_COOKIE))
strlst = add_magic_cookie(s, strlst);
- txt_entry = server_add_txt_strlst_nocopy(s, g, interface, protocol, CATTA_PUBLISH_UNIQUE, CATTA_DEFAULT_TTL, svc_name, strlst);
+ txt_entry = server_add_txt_strlst_nocopy(s, g, iface, protocol, CATTA_PUBLISH_UNIQUE, CATTA_DEFAULT_TTL, svc_name, strlst);
strlst = NULL;
if (!txt_entry) {
/* Add service type enumeration record */
- if (!(enum_entry = server_add_ptr_internal(s, g, interface, protocol, 0, CATTA_DEFAULT_TTL, enum_ptr, ptr_name))) {
+ if (!(enum_entry = server_add_ptr_internal(s, g, iface, protocol, 0, CATTA_DEFAULT_TTL, enum_ptr, ptr_name))) {
ret = catta_server_errno(s);
goto fail;
}
int catta_server_add_service_strlst(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
assert(type);
assert(name);
- return server_add_service_strlst_nocopy(s, g, interface, protocol, flags, name, type, domain, host, port, catta_string_list_copy(strlst));
+ return server_add_service_strlst_nocopy(s, g, iface, protocol, flags, name, type, domain, host, port, catta_string_list_copy(strlst));
}
int catta_server_add_service(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
int ret;
va_start(va, port);
- ret = server_add_service_strlst_nocopy(s, g, interface, protocol, flags, name, type, domain, host, port, catta_string_list_new_va(va));
+ ret = server_add_service_strlst_nocopy(s, g, iface, protocol, flags, name, type, domain, host, port, catta_string_list_new_va(va));
va_end(va);
return ret;
static int server_update_service_txt_strlst_nocopy(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
assert(type);
assert(name);
- CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_FLAGS_VALID(flags,
CATTA_PUBLISH_NO_COOKIE|
if (!(flags & CATTA_PUBLISH_NO_COOKIE))
strlst = add_magic_cookie(s, strlst);
- e = server_add_txt_strlst_nocopy(s, g, interface, protocol, CATTA_PUBLISH_UNIQUE | CATTA_PUBLISH_UPDATE, CATTA_DEFAULT_TTL, svc_name, strlst);
+ e = server_add_txt_strlst_nocopy(s, g, iface, protocol, CATTA_PUBLISH_UNIQUE | CATTA_PUBLISH_UPDATE, CATTA_DEFAULT_TTL, svc_name, strlst);
strlst = NULL;
if (!e)
int catta_server_update_service_txt_strlst(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
const char *domain,
CattaStringList *strlst) {
- return server_update_service_txt_strlst_nocopy(s, g, interface, protocol, flags, name, type, domain, catta_string_list_copy(strlst));
+ return server_update_service_txt_strlst_nocopy(s, g, iface, protocol, flags, name, type, domain, catta_string_list_copy(strlst));
}
/** Update the TXT record for a service with the NULL termonate list of strings */
int catta_server_update_service_txt(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
int ret;
va_start(va, domain);
- ret = server_update_service_txt_strlst_nocopy(s, g, interface, protocol, flags, name, type, domain, catta_string_list_new_va(va));
+ ret = server_update_service_txt_strlst_nocopy(s, g, iface, protocol, flags, name, type, domain, catta_string_list_new_va(va));
va_end(va);
return ret;
int catta_server_add_service_subtype(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *name,
assert(type);
assert(subtype);
- CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, CATTA_FLAGS_VALID(flags, CATTA_PUBLISH_USE_MULTICAST|CATTA_PUBLISH_USE_WIDE_AREA), CATTA_ERR_INVALID_FLAGS);
CATTA_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, catta_is_valid_service_name(name), CATTA_ERR_INVALID_SERVICE_NAME);
goto fail;
}
- if ((ret = catta_server_add_ptr(s, g, interface, protocol, 0, CATTA_DEFAULT_TTL, ptr_name, svc_name)) < 0)
+ if ((ret = catta_server_add_ptr(s, g, iface, protocol, 0, CATTA_DEFAULT_TTL, ptr_name, svc_name)) < 0)
goto fail;
fail:
static CattaEntry *server_add_dns_server_name(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *domain,
r->data.srv.weight = 0;
r->data.srv.port = port;
r->data.srv.name = n;
- e = server_add_internal(s, g, interface, protocol, 0, r);
+ e = server_add_internal(s, g, iface, protocol, 0, r);
catta_record_unref(r);
return e;
int catta_server_add_dns_server_address(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
const char *domain,
assert(s);
assert(address);
- CATTA_CHECK_VALIDITY(s, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY(s, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY(s, CATTA_PROTO_VALID(protocol) && CATTA_PROTO_VALID(address->proto), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY(s, CATTA_FLAGS_VALID(flags, CATTA_PUBLISH_USE_MULTICAST|CATTA_PUBLISH_USE_WIDE_AREA), CATTA_ERR_INVALID_FLAGS);
CATTA_CHECK_VALIDITY(s, type == CATTA_DNS_SERVER_UPDATE || type == CATTA_DNS_SERVER_RESOLVE, CATTA_ERR_INVALID_FLAGS);
if (!r)
return catta_server_set_errno(s, CATTA_ERR_NO_MEMORY);
- a_entry = server_add_internal(s, g, interface, protocol, CATTA_PUBLISH_UNIQUE | CATTA_PUBLISH_ALLOW_MULTIPLE, r);
+ a_entry = server_add_internal(s, g, iface, protocol, CATTA_PUBLISH_UNIQUE | CATTA_PUBLISH_ALLOW_MULTIPLE, r);
catta_record_unref(r);
if (!a_entry)
return catta_server_errno(s);
- if (!(s_entry = server_add_dns_server_name(s, g, interface, protocol, flags, domain, type, n, port))) {
+ if (!(s_entry = server_add_dns_server_name(s, g, iface, protocol, flags, domain, type, n, port))) {
if (!(flags & CATTA_PUBLISH_UPDATE))
catta_entry_free(s, a_entry);
return catta_server_errno(s);
"Memory exhausted",
"The object passed in was not valid",
"Daemon not running",
- "Invalid interface index",
+ "Invalid iface index",
"Invalid protocol specification",
"Invalid flags",
#include <sys/select.h>
#include <unistd.h>
-#include <fcntl.h>
#include <assert.h>
+#ifdef HAVE_FCNTL
+#include <fcntl.h>
+#else
+#include <sys/ioctl.h>
+#endif
+
#include "fdutil.h"
int catta_set_cloexec(int fd) {
assert(fd >= 0);
+#if defined(HAVE_FCNTL)
if ((n = fcntl(fd, F_GETFD)) < 0)
return -1;
return 0;
return fcntl(fd, F_SETFD, n|FD_CLOEXEC);
+#elif defined(_WIN32)
+ (void)n;
+ if(!SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0))
+ return -1;
+ return 0;
+#else
+ (void)n;
+ return -1;
+#endif
}
int catta_set_nonblock(int fd) {
assert(fd >= 0);
+#ifdef HAVE_FCNTL
if ((n = fcntl(fd, F_GETFL)) < 0)
return -1;
return 0;
return fcntl(fd, F_SETFL, n|O_NONBLOCK);
+#else
+ n = 1;
+ return ioctl(fd, FIONBIO, &n);
+#endif
}
int catta_wait_for_write(int fd) {
#include "iface.h"
int catta_interface_monitor_init_osdep(CattaInterfaceMonitor *m) {
+ (void)m; // silence "unused parameter" warning
+
return 0;
}
void catta_interface_monitor_free_osdep(CattaInterfaceMonitor *m) {
+ (void)m; // silence "unused parameter" warning
}
void catta_interface_monitor_sync(CattaInterfaceMonitor *m) {
+ (void)m; // silence "unused parameter" warning
}
--- /dev/null
+/***
+ This file is part of catta.
+
+ catta is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ catta 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 Lesser General
+ Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with catta; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#include "iface.h"
+#include "iface-windows.h"
+
+#include <stdlib.h> // wcstombs
+#include <catta/malloc.h>
+#include <catta/log.h>
+#include <iphlpapi.h>
+#include <assert.h>
+#include "hashmap.h"
+#include "util.h" // catta_format_mac_address
+#include "fdutil.h" // catta_set_nonblock
+
+
+typedef enum {
+ INTERFACE_CHANGE_EVENT,
+ ADDRESS_CHANGE_EVENT
+} ChangeEventType;
+
+struct ChangeEvent {
+ CATTA_LLIST_FIELDS(ChangeEvent, event);
+ ChangeEventType type;
+ MIB_NOTIFICATION_TYPE notification_type;
+ union {
+ MIB_IPINTERFACE_ROW iface;
+ MIB_UNICASTIPADDRESS_ROW addr;
+ } data;
+};
+
+
+// helper: determine the global_scope flag for an address
+static void set_global_scope_flag(CattaInterfaceAddress *ifaddr, const CattaAddress *addr)
+{
+ if(addr->proto == CATTA_PROTO_INET6) {
+ const struct in6_addr *ia = (struct in6_addr *)addr->data.ipv6.address;
+ ifaddr->global_scope = !(IN6_IS_ADDR_LINKLOCAL(ia) || IN6_IS_ADDR_MULTICAST(ia));
+ } else {
+ ifaddr->global_scope = 1;
+ }
+}
+
+// integrate the information from an IP_ADAPTER_UNICAST_ADDRESS structure for
+// given CattaHwInterface into the CattaInterfaceMonitor
+static void ip_adapter_unicast_address(CattaInterfaceMonitor *m,
+ CattaHwInterface *hw,
+ IP_ADAPTER_UNICAST_ADDRESS *a)
+{
+ CattaInterface *iface;
+ CattaAddress addr;
+ CattaInterfaceAddress *ifaddr;
+ struct sockaddr *sa = a->Address.lpSockaddr;
+
+ // skip transient addresses; to quote MSDN: "The IP address is a cluster
+ // address and should not be used by most applications."
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366066(v=vs.85).aspx
+ if(a->Flags & IP_ADAPTER_ADDRESS_TRANSIENT)
+ return;
+
+ // fill addr struct for address lookup
+ switch(sa->sa_family) {
+ case AF_INET:
+ memcpy(addr.data.data, &((struct sockaddr_in *)sa)->sin_addr, sizeof(struct in_addr));
+ break;
+ case AF_INET6:
+ memcpy(addr.data.data, &((struct sockaddr_in6 *)sa)->sin6_addr, sizeof(struct in6_addr));
+ break;
+ default:
+ catta_log_debug("unexpected address family on interface %d: %u", hw->index, sa->sa_family);
+ return;
+ }
+ addr.proto = catta_af_to_proto(sa->sa_family);
+
+ // get protocol-specific CattaInterface object
+ if(!(iface = catta_interface_monitor_get_interface(m, hw->index, addr.proto))) {
+ catta_log_error("CattaInterface (index %d, proto %d) not found", hw->index, addr.proto);
+ return;
+ }
+
+ // find or allocate a CattaInterfaceAddress struct for this address
+ if(!(ifaddr = catta_interface_monitor_get_address(m, iface, &addr))) {
+ if(!(ifaddr = catta_interface_address_new(m, iface, &addr, a->OnLinkPrefixLength))) {
+ catta_log_error("out of memory in ip_adapter_unicast_address");
+ return;
+ }
+ }
+
+ set_global_scope_flag(ifaddr, &addr);
+}
+
+// integrate the information from an IP_ADAPTER_ADDRESSES structure
+// as returned by GetAdaptersAddresses into the CattaInterfaceMonitor
+static void ip_adapter(CattaInterfaceMonitor *m, IP_ADAPTER_ADDRESSES *p)
+{
+ IP_ADAPTER_UNICAST_ADDRESS *a;
+ CattaIfIndex idx;
+ CattaHwInterface *hw;
+ size_t n;
+
+ // we want an index specific to the hardware interface, but Windows
+ // has one for IPv4 and one for IPv6. it seems like these are always the
+ // same unless one of the protocols is not available. let's have a bunch of
+ // checks...
+ if(!p->IfIndex && !p->Ipv6IfIndex) {
+ return; // no usable protocols
+ } else if(!p->IfIndex) {
+ idx = p->Ipv6IfIndex; // IPv6 but no IPv4 (huh!)
+ } else if(!p->Ipv6IfIndex) {
+ idx = p->IfIndex; // IPv4 but no IPv6
+ } else if(p->IfIndex == p->Ipv6IfIndex) {
+ idx = p->IfIndex; // same index for both protocols
+ } else {
+ // both indexes valid but not equal
+ catta_log_error("unsupported interface: %ls (IfIndex and Ipv6IfIndex differ: %u/%u)",
+ p->FriendlyName, (unsigned int)p->IfIndex, (unsigned int)p->Ipv6IfIndex);
+ return;
+ }
+
+ // find the CattaHwInterface by index or allocate a new one
+ if((hw = catta_interface_monitor_get_hw_interface(m, idx)) == NULL) {
+ if((hw = catta_hw_interface_new(m, idx)) == NULL) {
+ catta_log_error("catta_hw_interface_new failed in ip_adapter_address");
+ return;
+ }
+ }
+
+ // fill the CattaHwInterface struct with data
+ // notice: this code is essentially duplicated in update_hw_interface()
+ hw->flags_ok =
+ (p->OperStatus == IfOperStatusUp) &&
+ !(p->IfType == IF_TYPE_SOFTWARE_LOOPBACK) &&
+ !(p->Flags & IP_ADAPTER_NO_MULTICAST) &&
+ (m->server->config.allow_point_to_point || !(p->IfType == IF_TYPE_PPP));
+ // XXX what about IF_TYPE_TUNNEL?
+
+ n = wcstombs(NULL, p->FriendlyName, 0) + 1;
+ catta_free(hw->name);
+ hw->name = catta_new(char, n);
+ wcstombs(hw->name, p->FriendlyName, n);
+
+ hw->mtu = p->Mtu;
+
+ hw->mac_address_size = p->PhysicalAddressLength;
+ if(hw->mac_address_size > CATTA_MAC_ADDRESS_MAX)
+ hw->mac_address_size = CATTA_MAC_ADDRESS_MAX;
+ memcpy(hw->mac_address, p->PhysicalAddress, hw->mac_address_size);
+
+ // process addresses
+ // XXX remove addresses that are no longer in the list
+ for(a=p->FirstUnicastAddress; a; a=a->Next)
+ ip_adapter_unicast_address(m, hw, a);
+}
+
+
+// place the event into the queue to be handled (by the main thread)
+// and wake the event handler if necessary
+static void queue_event(CattaInterfaceMonitor *m, ChangeEvent *ev)
+{
+ char c = 'X';
+
+ if(!ev)
+ return;
+
+ if(!pthread_mutex_lock(&m->osdep.mutex)) {
+ // queue the event
+ CATTA_LLIST_APPEND(ChangeEvent, event, m->osdep.events, ev);
+
+ // wake the handler
+ writepipe(m->osdep.pipefd[1], &c, sizeof(c));
+
+ pthread_mutex_unlock(&m->osdep.mutex);
+ } else {
+ catta_log_debug(__FILE__": queue_event: could not lock mutex");
+ catta_free(ev);
+ }
+}
+
+// copy the given data row into an appropriate change event struct
+static ChangeEvent *new_event(ChangeEventType type, MIB_NOTIFICATION_TYPE ntype, void *row, size_t n)
+{
+ ChangeEvent *ev;
+
+ if(!row)
+ return NULL;
+
+ if(!(ev = catta_new(ChangeEvent, 1)))
+ return NULL;
+
+ ev->type = type;
+ ev->notification_type = ntype;
+ memcpy(&ev->data, row, n);
+
+ return ev;
+}
+
+static void WINAPI icn_callback(void *m, MIB_IPINTERFACE_ROW *row, MIB_NOTIFICATION_TYPE type)
+{
+ queue_event(m, new_event(INTERFACE_CHANGE_EVENT, type, row, sizeof(*row)));
+}
+
+static void WINAPI acn_callback(void *m, MIB_UNICASTIPADDRESS_ROW *row, MIB_NOTIFICATION_TYPE type)
+{
+ queue_event(m, new_event(ADDRESS_CHANGE_EVENT, type, row, sizeof(*row)));
+}
+
+static void update_hw_interface(CattaHwInterface *hw)
+{
+ MIB_IF_ROW2 row;
+ DWORD r;
+ size_t n;
+ int multicast; // synthetic flag
+
+ row.InterfaceLuid.Value = 0;
+ row.InterfaceIndex = hw->index;
+ if((r = GetIfEntry2(&row)) != NO_ERROR) {
+ catta_log_error("GetIfEntry2 failed for iface %d (error %u)", hw->index, (unsigned int)r);
+ return;
+ }
+
+ // fill the CattaHwInterface struct with data
+ // notice: this code is essentially duplicated from ip_adapter()
+ // notice: not sure where to find the IP_ADAPTER_NO_MULTICAST flag from an
+ // MIB_IF_ROW2 struct, so try to deduce it otherwise
+ // cf. http://msdn.microsoft.com/en-us/windows/desktop/ff568739(v=vs.100).aspx
+ multicast = row.AccessType == NET_IF_ACCESS_BROADCAST ||
+ row.AccessType == NET_IF_ACCESS_POINT_TO_POINT;
+ hw->flags_ok =
+ (row.OperStatus == IfOperStatusUp) &&
+ !(row.Type == IF_TYPE_SOFTWARE_LOOPBACK) &&
+ multicast &&
+ (hw->monitor->server->config.allow_point_to_point || !(row.Type == IF_TYPE_PPP));
+ // XXX what about IF_TYPE_TUNNEL?
+
+ n = wcstombs(NULL, row.Alias, 0) + 1;
+ catta_free(hw->name);
+ hw->name = catta_new(char, n);
+ wcstombs(hw->name, row.Alias, n);
+
+ hw->mtu = row.Mtu;
+
+ hw->mac_address_size = row.PhysicalAddressLength;
+ if(hw->mac_address_size > CATTA_MAC_ADDRESS_MAX)
+ hw->mac_address_size = CATTA_MAC_ADDRESS_MAX;
+ memcpy(hw->mac_address, row.PhysicalAddress, hw->mac_address_size);
+
+ catta_hw_interface_check_relevant(hw);
+ catta_hw_interface_update_rrs(hw, 0);
+}
+
+static void handle_iface_event(CattaInterfaceMonitor *m, MIB_IPINTERFACE_ROW *row, MIB_NOTIFICATION_TYPE type)
+{
+ CattaIfIndex idx = row->InterfaceIndex;
+ CattaProtocol proto = catta_af_to_proto(row->Family);
+ const char *protostr = catta_proto_to_string(proto);
+ CattaInterface *iface;
+ CattaHwInterface *hw;
+
+ // see if we know this interface
+ iface = catta_interface_monitor_get_interface(m, idx, proto);
+ hw = iface ? iface->hardware : catta_interface_monitor_get_hw_interface(m, idx);
+
+ // print debug messages for some unexpected cases
+ if(type==MibParameterNotification && !iface)
+ catta_log_debug("ParameterNotification received for unknown interface %d (%s)", idx, protostr);
+ if(type==MibDeleteInstance && !iface)
+ catta_log_debug("DeleteInstance received for unknown interface %d (%s)", idx, protostr);
+ if(type==MibAddInstance && iface)
+ catta_log_debug("AddInstance received for existing interface %d (%s)", idx, protostr);
+ if(iface && !hw)
+ catta_log_debug("missing CattaHwInterface for interface %d (%s)", idx, protostr);
+
+ switch(type) {
+ case MibParameterNotification:
+ case MibAddInstance:
+ // create the physical interface if it is missing
+ if(!hw) {
+ if((hw = catta_hw_interface_new(m, idx)) == NULL) {
+ catta_log_error("catta_hw_interface_new failed in handle_iface_event");
+ return;
+ }
+ }
+
+ // create the protocol-specific interface if it is missing
+ if(!iface) {
+ if((iface = catta_interface_new(m, hw, proto)) == NULL) {
+ catta_log_error("catta_interface_new failed in handle_iface_event");
+ return;
+ }
+ }
+
+ assert(iface != NULL);
+ assert(hw != NULL);
+ assert(iface->hardware == hw);
+
+ update_hw_interface(hw);
+ break;
+ case MibDeleteInstance:
+ if(iface)
+ catta_interface_free(iface, 0);
+
+ // free the hardware interface when there are no more protocol-specific interfaces
+ if(hw && !hw->interfaces)
+ catta_hw_interface_free(hw, 0);
+ break;
+ default:
+ catta_log_debug("unexpected type (%d) of interface change notification received", type);
+ }
+}
+
+static void handle_addr_event(CattaInterfaceMonitor *m, MIB_UNICASTIPADDRESS_ROW *row, MIB_NOTIFICATION_TYPE type)
+{
+ CattaIfIndex idx = row->InterfaceIndex;
+ CattaInterfaceAddress *ifaddr;
+ CattaInterface *iface;
+ CattaAddress addr;
+ const char *protostr;
+
+ // fill addr struct for address lookup
+ switch(row->Address.si_family) {
+ case AF_INET:
+ memcpy(addr.data.data, &row->Address.Ipv4.sin_addr, sizeof(struct in_addr));
+ break;
+ case AF_INET6:
+ memcpy(addr.data.data, &row->Address.Ipv6.sin6_addr, sizeof(struct in6_addr));
+ break;
+ default:
+ catta_log_debug("unexpected address family on interface %d: %u", idx, row->Address.si_family);
+ return;
+ }
+ addr.proto = catta_af_to_proto(row->Address.si_family);
+ protostr = catta_proto_to_string(addr.proto);
+
+ // see if we know this address/interface
+ iface = catta_interface_monitor_get_interface(m, idx, addr.proto);
+ ifaddr = iface ? catta_interface_monitor_get_address(m, iface, &addr) : NULL;
+
+ // print debug messages for some unexpected cases
+ if(type==MibParameterNotification && !ifaddr)
+ catta_log_debug("ParameterNotification received for unknown address on interface %d (%s)", idx, protostr);
+ if(type==MibDeleteInstance && !ifaddr)
+ catta_log_debug("DeleteInstance received for unknown address on interface %d (%s)", idx, protostr);
+ if(type==MibAddInstance && ifaddr)
+ catta_log_debug("AddInstance received for existing address on interface %d (%s)", idx, protostr);
+ if(ifaddr && !iface)
+ catta_log_debug("missing CattaInterface for address on interface %d (%s)", idx, protostr);
+
+ switch(type) {
+ case MibParameterNotification:
+ case MibAddInstance:
+ // fetch the full event data
+ if(GetUnicastIpAddressEntry(row) != NO_ERROR) {
+ catta_log_error("GetUnicastIpAddressEntry failed in handle_addr_event");
+ return;
+ }
+
+ // skip addresses that are not suitable as source addresses
+ if(row->SkipAsSource)
+ return;
+
+ // create the interface if it is missing
+ if(!iface) {
+ CattaHwInterface *hw;
+
+ if((hw = catta_interface_monitor_get_hw_interface(m, idx)) == NULL) {
+ catta_log_error("interface %d not found in handle_addr_event", idx);
+ return;
+ }
+
+ if((iface = catta_interface_new(m, hw, addr.proto)) == NULL) {
+ catta_log_error("catta_interface_new failed in handle_addr_event");
+ return;
+ }
+ }
+ assert(iface != NULL);
+
+ // create the interface-associated address if it is missing
+ if(!ifaddr) {
+ unsigned prefixlen = row->OnLinkPrefixLength;
+
+ if((ifaddr = catta_interface_address_new(m, iface, &addr, prefixlen)) == NULL) {
+ catta_log_error("catta_interface_address_new failed in handle_addr_event");
+ return;
+ }
+ }
+ assert(ifaddr != NULL);
+
+ set_global_scope_flag(ifaddr, &addr);
+ break;
+ case MibDeleteInstance:
+ if(ifaddr)
+ catta_interface_address_free(ifaddr);
+ break;
+ default:
+ catta_log_debug("unexpected type (%d) of address change notification received", type);
+ }
+
+ if(iface) {
+ catta_interface_check_relevant(iface);
+ catta_interface_update_rrs(iface, 0);
+ }
+}
+
+static void handle_events(CattaInterfaceMonitor *m)
+{
+ char buf[16];
+ ChangeEvent *ev;
+
+ if(!pthread_mutex_lock(&m->osdep.mutex)) {
+ // clear the pipe
+ while(readpipe(m->osdep.pipefd[0], buf, sizeof(buf)) == sizeof(buf)) {}
+
+ while((ev = m->osdep.events) != NULL) {
+ CATTA_LLIST_REMOVE(ChangeEvent, event, m->osdep.events, ev);
+
+ // dispatch to the appropriate handler
+ switch(ev->type) {
+ case INTERFACE_CHANGE_EVENT:
+ handle_iface_event(m, &ev->data.iface, ev->notification_type);
+ break;
+ case ADDRESS_CHANGE_EVENT:
+ handle_addr_event(m, &ev->data.addr, ev->notification_type);
+ break;
+ default:
+ catta_log_debug("unhandled change event type in handle_events");
+ }
+
+ catta_free(ev);
+ }
+
+ pthread_mutex_unlock(&m->osdep.mutex);
+ }
+}
+
+static void pipe_callback(CattaWatch *w, int fd, CattaWatchEvent event, void *m)
+{
+ // silence "unused parameter" warnings
+ (void)w;
+ (void)fd;
+ (void)event;
+
+ handle_events(m);
+}
+
+
+int catta_interface_monitor_init_osdep(CattaInterfaceMonitor *m)
+{
+ DWORD r;
+
+ pthread_mutex_init(&m->osdep.mutex, NULL);
+
+ CATTA_LLIST_HEAD_INIT(ChangeEvent, m->osdep.events);
+
+ if(pipe(m->osdep.pipefd) < 0) {
+ catta_log_error("pipe() in catta_interface_monitor_init_osdep failed");
+ return -1;
+ }
+ if(catta_set_nonblock(m->osdep.pipefd[0]) < 0 ||
+ catta_set_nonblock(m->osdep.pipefd[1]) < 0)
+ {
+ catta_log_error(__FILE__": catta_set_nonblock failed: %s", errnostrsocket());
+ goto fail;
+ }
+
+ m->osdep.icnhandle = NULL;
+ m->osdep.acnhandle = NULL;
+
+ // register handler for change events
+ m->osdep.watch = m->server->poll_api->watch_new(m->server->poll_api,
+ m->osdep.pipefd[0],
+ CATTA_WATCH_IN,
+ pipe_callback,
+ m);
+ if(!m->osdep.watch) {
+ catta_log_error(__FILE__": Failed to create watch.");
+ goto fail;
+ }
+
+ // request async notification on interface changes
+ r = NotifyIpInterfaceChange(AF_UNSPEC,
+ // icn_callback needs to be WINAPI but
+ // MingW up to 3.1.0 erroneously defines
+ // PIPINTERFACE_CHANGE_CALLBACK without it
+ (PIPINTERFACE_CHANGE_CALLBACK)icn_callback,
+ m, FALSE, &m->osdep.icnhandle);
+ if(r != NO_ERROR)
+ catta_log_error("NotifyIpInterfaceChange failed: %u", (unsigned int)r);
+
+ // request async notification on address changes
+ r = NotifyUnicastIpAddressChange(AF_UNSPEC, acn_callback, m, FALSE,
+ &m->osdep.acnhandle);
+ if(r != NO_ERROR)
+ catta_log_error("NotifyUnicastIpAddressChange failed: %u", (unsigned int)r);
+
+ return 0;
+
+fail:
+ closesocket(m->osdep.pipefd[0]);
+ closesocket(m->osdep.pipefd[1]);
+ return -1;
+}
+
+void catta_interface_monitor_free_osdep(CattaInterfaceMonitor *m)
+{
+ ChangeEvent *ev;
+
+ // unregister callbacks
+ if(m->osdep.icnhandle) CancelMibChangeNotify2(m->osdep.icnhandle);
+ if(m->osdep.acnhandle) CancelMibChangeNotify2(m->osdep.acnhandle);
+
+ // unregister event handler
+ m->server->poll_api->watch_free(m->osdep.watch);
+
+ // close pipe
+ closepipe(m->osdep.pipefd[0]);
+ closepipe(m->osdep.pipefd[1]);
+
+ // make sure no stray events can come in during destruction
+ pthread_mutex_lock(&m->osdep.mutex);
+
+ // free all events that are still in the queue
+ while((ev = m->osdep.events) != NULL) {
+ CATTA_LLIST_REMOVE(ChangeEvent, event, m->osdep.events, ev);
+ catta_free(ev);
+ }
+
+ pthread_mutex_unlock(&m->osdep.mutex);
+ pthread_mutex_destroy(&m->osdep.mutex);
+}
+
+void catta_interface_monitor_sync(CattaInterfaceMonitor *m)
+{
+ IP_ADAPTER_ADDRESSES *buf = NULL;
+ IP_ADAPTER_ADDRESSES *p;
+ ULONG bufsize = 15000;
+ ULONG r;
+
+ // allocate a buffer and call GetAdaptersAddresses
+ // retry with the correct size if the buffer was too small
+ do {
+ catta_free(buf); // no-op on first iteration
+ if((buf = catta_malloc(bufsize)) == NULL) {
+ catta_log_error("malloc failed in catta_interface_monitor_sync");
+ return;
+ }
+
+ r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, buf, &bufsize);
+ } while(r == ERROR_BUFFER_OVERFLOW);
+
+ if(r != NO_ERROR) {
+ catta_log_error("GetAdaptersAddresses failed: %u", (unsigned int)r);
+ return;
+ }
+
+ // XXX remove interfaces for adapters that are no longer in the list
+
+ // create 'CattaInterface's for every adapter
+ for(p=buf; p; p=p->Next)
+ ip_adapter(m, p);
+
+ catta_free(buf);
+
+ m->list_complete = 1;
+ catta_interface_monitor_check_relevant(m);
+ catta_interface_monitor_update_rrs(m, 0);
+ catta_log_info("Network interface enumeration completed.");
+}
--- /dev/null
+#ifndef fooifacewindowshfoo
+#define fooifacewindowshfoo
+
+#include <catta/llist.h>
+#include <pthread.h>
+
+// we register with Windows to receive callbacks when IP interfaces change.
+// we save these events in the structures below and pick them up from our
+// own mainloop which we wake via a pipe.
+
+typedef struct ChangeEvent ChangeEvent;
+
+typedef struct CattaInterfaceMonitorOSDep {
+ pthread_mutex_t mutex; // guards access to event queues and the pipe
+
+ CATTA_LLIST_HEAD(ChangeEvent, events);
+
+ int pipefd[2]; // used to wake up the mainloop and check for events
+
+ // handles for deregistering the handler and notification callbacks
+ HANDLE icnhandle; // interface change notification handle
+ HANDLE acnhandle; // address change notification handle
+ CattaWatch *watch;
+} CattaInterfaceMonitorOSDep;
+
+#endif
if (m->list_complete &&
catta_interface_address_is_relevant(a) &&
- catta_interface_is_relevant(a->interface) &&
+ catta_interface_is_relevant(a->iface) &&
!remove_rrs &&
m->server->config.publish_addresses &&
(m->server->state == CATTA_SERVER_RUNNING ||
char t[CATTA_ADDRESS_STR_MAX];
CattaProtocol p;
- p = (a->interface->protocol == CATTA_PROTO_INET && m->server->config.publish_a_on_ipv6) ||
- (a->interface->protocol == CATTA_PROTO_INET6 && m->server->config.publish_aaaa_on_ipv4) ? CATTA_PROTO_UNSPEC : a->interface->protocol;
+ p = (a->iface->protocol == CATTA_PROTO_INET && m->server->config.publish_a_on_ipv6) ||
+ (a->iface->protocol == CATTA_PROTO_INET6 && m->server->config.publish_aaaa_on_ipv4) ? CATTA_PROTO_UNSPEC : a->iface->protocol;
catta_address_snprint(t, sizeof(t), &a->address);
- catta_log_info("Registering new address record for %s on %s.%s.", t, a->interface->hardware->name, p == CATTA_PROTO_UNSPEC ? "*" : catta_proto_to_string(p));
+ catta_log_info("Registering new address record for %s on %s.%s.", t, a->iface->hardware->name, p == CATTA_PROTO_UNSPEC ? "*" : catta_proto_to_string(p));
- if (catta_server_add_address(m->server, a->entry_group, a->interface->hardware->index, p, m->server->config.publish_no_reverse ? CATTA_PUBLISH_NO_REVERSE : 0, NULL, &a->address) < 0) {
+ if (catta_server_add_address(m->server, a->entry_group, a->iface->hardware->index, p, m->server->config.publish_no_reverse ? CATTA_PUBLISH_NO_REVERSE : 0, NULL, &a->address) < 0) {
catta_log_warn(__FILE__": catta_server_add_address() failed: %s", catta_strerror(m->server->error));
catta_s_entry_group_free(a->entry_group);
a->entry_group = NULL;
char t[CATTA_ADDRESS_STR_MAX];
catta_address_snprint(t, sizeof(t), &a->address);
- catta_log_info("Withdrawing address record for %s on %s.", t, a->interface->hardware->name);
+ catta_log_info("Withdrawing address record for %s on %s.", t, a->iface->hardware->name);
if (catta_s_entry_group_get_state(a->entry_group) == CATTA_ENTRY_GROUP_REGISTERING &&
m->server->state == CATTA_SERVER_REGISTERING)
void catta_interface_address_free(CattaInterfaceAddress *a) {
assert(a);
- assert(a->interface);
+ assert(a->iface);
catta_interface_address_update_rrs(a, 1);
- CATTA_LLIST_REMOVE(CattaInterfaceAddress, address, a->interface->addresses, a);
+ CATTA_LLIST_REMOVE(CattaInterfaceAddress, address, a->iface->addresses, a);
if (a->entry_group)
catta_s_entry_group_free(a->entry_group);
- interface_mdns_mcast_rejoin(a->interface);
+ interface_mdns_mcast_rejoin(a->iface);
catta_free(a);
}
catta_probe_scheduler_free(i->probe_scheduler);
catta_cache_free(i->cache);
- CATTA_LLIST_REMOVE(CattaInterface, interface, i->monitor->interfaces, i);
+ CATTA_LLIST_REMOVE(CattaInterface, iface, i->monitor->interfaces, i);
CATTA_LLIST_REMOVE(CattaInterface, by_hardware, i->hardware->interfaces, i);
catta_free(i);
goto fail; /* OOM */
CATTA_LLIST_PREPEND(CattaInterface, by_hardware, hw->interfaces, i);
- CATTA_LLIST_PREPEND(CattaInterface, interface, m->interfaces, i);
+ CATTA_LLIST_PREPEND(CattaInterface, iface, m->interfaces, i);
return i;
if (!(a = catta_new(CattaInterfaceAddress, 1)))
return NULL;
- a->interface = i;
+ a->iface = i;
a->monitor = m;
a->address = *addr;
a->prefix_len = prefix_len;
assert(m);
- for (i = m->interfaces; i; i = i->interface_next)
+ for (i = m->interfaces; i; i = i->iface_next)
catta_interface_check_relevant(i);
}
CattaInterface *i;
assert(m);
- for (i = m->interfaces; i; i = i->interface_next) {
+ for (i = m->interfaces; i; i = i->iface_next) {
if (catta_interface_is_relevant(i)) {
char ln[256];
snprintf(ln, sizeof(ln), ";;; INTERFACE %s.%s ;;;", i->hardware->name, catta_proto_to_string(i->protocol));
/* Publish link-local and deprecated IP addresses only if they are
* the only ones on the link */
- for (b = a->interface->addresses; b; b = b->address_next) {
+ for (b = a->iface->addresses; b; b = b->address_next) {
if (b == a)
continue;
return 1;
}
-void catta_interface_monitor_walk(CattaInterfaceMonitor *m, CattaIfIndex interface, CattaProtocol protocol, CattaInterfaceMonitorWalkCallback callback, void* userdata) {
+void catta_interface_monitor_walk(CattaInterfaceMonitor *m, CattaIfIndex iface, CattaProtocol protocol, CattaInterfaceMonitorWalkCallback callback, void* userdata) {
assert(m);
assert(callback);
- if (interface != CATTA_IF_UNSPEC) {
+ if (iface != CATTA_IF_UNSPEC) {
if (protocol != CATTA_PROTO_UNSPEC) {
CattaInterface *i;
- if ((i = catta_interface_monitor_get_interface(m, interface, protocol)))
+ if ((i = catta_interface_monitor_get_interface(m, iface, protocol)))
callback(m, i, userdata);
} else {
CattaHwInterface *hw;
CattaInterface *i;
- if ((hw = catta_interface_monitor_get_hw_interface(m, interface)))
+ if ((hw = catta_interface_monitor_get_hw_interface(m, iface)))
for (i = hw->interfaces; i; i = i->by_hardware_next)
- if (catta_interface_match(i, interface, protocol))
+ if (catta_interface_match(i, iface, protocol))
callback(m, i, userdata);
}
} else {
CattaInterface *i;
- for (i = m->interfaces; i; i = i->interface_next)
- if (catta_interface_match(i, interface, protocol))
+ for (i = m->interfaces; i; i = i->iface_next)
+ if (catta_interface_match(i, iface, protocol))
callback(m, i, userdata);
}
}
assert(m);
assert(a);
- for (i = m->interfaces; i; i = i->interface_next)
+ for (i = m->interfaces; i; i = i->iface_next)
for (ia = i->addresses; ia; ia = ia->address_next)
if (catta_address_cmp(a, &ia->address) == 0)
return 1;
* attached. This is sometimes ambiguous, but we have to live with
* it. */
- for (i = m->interfaces; i; i = i->interface_next) {
+ for (i = m->interfaces; i; i = i->iface_next) {
CattaInterfaceAddress *ai;
if (i->protocol != a->proto)
#include "iface-linux.h"
#elif defined(HAVE_PF_ROUTE)
#include "iface-pfroute.h"
+#elif defined(_WIN32)
+#include "iface-windows.h"
#else
typedef struct CattaInterfaceMonitorOSDep CattaInterfaceMonitorOSDep;
struct CattaInterfaceMonitorOSDep {
CattaInterfaceMonitor *monitor;
CattaHwInterface *hardware;
- CATTA_LLIST_FIELDS(CattaInterface, interface);
+ CATTA_LLIST_FIELDS(CattaInterface, iface);
CATTA_LLIST_FIELDS(CattaInterface, by_hardware);
CattaProtocol protocol;
struct CattaInterfaceAddress {
CattaInterfaceMonitor *monitor;
- CattaInterface *interface;
+ CattaInterface *iface;
CATTA_LLIST_FIELDS(CattaInterfaceAddress, address);
void catta_hw_interface_update_rrs(CattaHwInterface *hw, int remove_rrs);
void catta_hw_interface_check_relevant(CattaHwInterface *hw);
-CattaHwInterface* catta_interface_monitor_get_hw_interface(CattaInterfaceMonitor *m, int idx);
+CattaHwInterface* catta_interface_monitor_get_hw_interface(CattaInterfaceMonitor *m, CattaIfIndex idx);
/* CattaInterface */
#define CATTA_RR_HOLDOFF_MSEC_RATE_LIMIT 20000
#define CATTA_RR_RATE_LIMIT_COUNT 15
+#ifndef _WIN32
+#define closesocket close
+#define closepipe close
+#define writepipe write
+#define readpipe read
+#define winsock_init()
+#define winsock_exit()
+#define errnostrsocket() strerror(errno)
+#endif
+
typedef struct CattaLegacyUnicastReflectSlot CattaLegacyUnicastReflectSlot;
struct CattaLegacyUnicastReflectSlot {
uint16_t id, original_id;
CattaAddress address;
uint16_t port;
- int interface;
+ CattaIfIndex iface;
struct timeval elapse_time;
CattaTimeEvent *time_event;
};
CattaPublishFlags flags;
CattaRecord *record;
- CattaIfIndex interface;
+ CattaIfIndex iface;
CattaProtocol protocol;
CATTA_LLIST_FIELDS(CattaEntry, entries);
int catta_server_set_errno(CattaServer *s, int error);
-int catta_server_is_service_local(CattaServer *s, CattaIfIndex interface, CattaProtocol protocol, const char *name);
-int catta_server_is_record_local(CattaServer *s, CattaIfIndex interface, CattaProtocol protocol, CattaRecord *record);
+int catta_server_is_service_local(CattaServer *s, CattaIfIndex iface, CattaProtocol protocol, const char *name);
+int catta_server_is_record_local(CattaServer *s, CattaIfIndex iface, CattaProtocol protocol, CattaRecord *record);
int catta_server_add_ptr(
CattaServer *s,
CattaSEntryGroup *g,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaPublishFlags flags,
uint32_t ttl,
CattaMulticastLookupCallback callback;
void *userdata;
- CattaIfIndex interface;
+ CattaIfIndex iface;
CattaProtocol protocol;
int queriers_added;
catta_time_event_free(l->all_for_now_event);
l->all_for_now_event = NULL;
- l->callback(l->engine, l->interface, l->protocol, CATTA_BROWSER_ALL_FOR_NOW, CATTA_LOOKUP_RESULT_MULTICAST, NULL, l->userdata);
+ l->callback(l->engine, l->iface, l->protocol, CATTA_BROWSER_ALL_FOR_NOW, CATTA_LOOKUP_RESULT_MULTICAST, NULL, l->userdata);
}
CattaMulticastLookup *catta_multicast_lookup_new(
CattaMulticastLookupEngine *e,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaKey *key,
CattaMulticastLookupCallback callback,
struct timeval tv;
assert(e);
- assert(CATTA_IF_VALID(interface));
+ assert(CATTA_IF_VALID(iface));
assert(CATTA_PROTO_VALID(protocol));
assert(key);
assert(callback);
l->cname_key = catta_key_new_cname(l->key);
l->callback = callback;
l->userdata = userdata;
- l->interface = interface;
+ l->iface = iface;
l->protocol = protocol;
l->all_for_now_event = NULL;
l->queriers_added = 0;
CATTA_LLIST_PREPEND(CattaMulticastLookup, lookups, e->lookups, l);
- catta_querier_add_for_all(e->server, interface, protocol, l->key, &tv);
+ catta_querier_add_for_all(e->server, iface, protocol, l->key, &tv);
l->queriers_added = 1;
/* Add a second */
l->callback = NULL;
if (l->queriers_added) {
- catta_querier_remove_for_all(l->engine->server, l->interface, l->protocol, l->key);
+ catta_querier_remove_for_all(l->engine->server, l->iface, l->protocol, l->key);
l->queriers_added = 0;
}
CattaMulticastLookupCallback callback;
void *userdata;
CattaKey *key, *cname_key;
- CattaInterface *interface;
+ CattaInterface *iface;
unsigned n_found;
};
cbdata->callback(
cbdata->engine,
- cbdata->interface->hardware->index,
- cbdata->interface->protocol,
+ cbdata->iface->hardware->index,
+ cbdata->iface->protocol,
CATTA_BROWSER_NEW,
CATTA_LOOKUP_RESULT_CACHED|CATTA_LOOKUP_RESULT_MULTICAST,
e->record,
assert(i);
assert(cbdata);
- cbdata->interface = i;
+ cbdata->iface = i;
catta_cache_walk(i->cache, cbdata->key, scan_cache_callback, cbdata);
if (cbdata->cname_key)
catta_cache_walk(i->cache, cbdata->cname_key, scan_cache_callback, cbdata);
- cbdata->interface = NULL;
+ cbdata->iface = NULL;
}
unsigned catta_multicast_lookup_engine_scan_cache(
CattaMulticastLookupEngine *e,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaKey *key,
CattaMulticastLookupCallback callback,
assert(key);
assert(callback);
- assert(CATTA_IF_VALID(interface));
+ assert(CATTA_IF_VALID(iface));
assert(CATTA_PROTO_VALID(protocol));
cbdata.engine = e;
cbdata.cname_key = catta_key_new_cname(key);
cbdata.callback = callback;
cbdata.userdata = userdata;
- cbdata.interface = NULL;
+ cbdata.iface = NULL;
cbdata.n_found = 0;
- catta_interface_monitor_walk(e->server->monitor, interface, protocol, scan_interface_callback, &cbdata);
+ catta_interface_monitor_walk(e->server->monitor, iface, protocol, scan_interface_callback, &cbdata);
if (cbdata.cname_key)
catta_key_unref(cbdata.cname_key);
if (l->dead || !l->callback)
continue;
- if (l->queriers_added && catta_interface_match(i, l->interface, l->protocol))
+ if (l->queriers_added && catta_interface_match(i, l->iface, l->protocol))
catta_querier_add(i, l->key, NULL);
}
}
if (l->dead || !l->callback)
continue;
- if (catta_interface_match(i, l->interface, l->protocol))
+ if (catta_interface_match(i, l->iface, l->protocol))
l->callback(e, i->hardware->index, i->protocol, event, CATTA_LOOKUP_RESULT_MULTICAST, record, l->userdata);
}
};
struct CattaProbeScheduler {
- CattaInterface *interface;
+ CattaInterface *iface;
CattaTimeEventQueue *time_event_queue;
CATTA_LLIST_HEAD(CattaProbeJob, jobs);
return NULL;
}
- s->interface = i;
+ s->iface = i;
s->time_event_queue = i->monitor->server->time_event_queue;
CATTA_LLIST_HEAD_INIT(CattaProbeJob, s->jobs);
return;
}
- if (!(p = catta_dns_packet_new_query(s->interface->hardware->mtu)))
+ if (!(p = catta_dns_packet_new_query(s->iface->hardware->mtu)))
return; /* OOM */
n = 1;
if (b) {
catta_dns_packet_set_field(p, CATTA_DNS_FIELD_NSCOUNT, 1);
catta_dns_packet_set_field(p, CATTA_DNS_FIELD_QDCOUNT, 1);
- catta_interface_send_packet(s->interface, p);
+ catta_interface_send_packet(s->iface, p);
} else
catta_log_warn("Probe record too large, cannot send");
catta_dns_packet_set_field(p, CATTA_DNS_FIELD_NSCOUNT, n);
/* Send it now */
- catta_interface_send_packet(s->interface, p);
+ catta_interface_send_packet(s->iface, p);
catta_dns_packet_free(p);
}
#include <catta/log.h>
struct CattaQuerier {
- CattaInterface *interface;
+ CattaInterface *iface;
CattaKey *key;
int n_used;
void catta_querier_free(CattaQuerier *q) {
assert(q);
- CATTA_LLIST_REMOVE(CattaQuerier, queriers, q->interface->queriers, q);
- catta_hashmap_remove(q->interface->queriers_by_key, q->key);
+ CATTA_LLIST_REMOVE(CattaQuerier, queriers, q->iface->queriers, q);
+ catta_hashmap_remove(q->iface->queriers_by_key, q->key);
catta_key_unref(q->key);
catta_time_event_free(q->time_event);
return;
}
- if (catta_interface_post_query(q->interface, q->key, 0, &q->post_id)) {
+ if (catta_interface_post_query(q->iface, q->key, 0, &q->post_id)) {
/* The queue accepted our query. We store the query id here,
* that allows us to drop the query at a later point if the
return; /* OOM */
q->key = catta_key_ref(key);
- q->interface = i;
+ q->iface = i;
q->n_used = 1;
q->sec_delay = 1;
q->post_id_valid = 0;
};
struct CattaQueryScheduler {
- CattaInterface *interface;
+ CattaInterface *iface;
CattaTimeEventQueue *time_event_queue;
unsigned next_id;
return NULL; /* OOM */
}
- s->interface = i;
+ s->iface = i;
s->time_event_queue = i->monitor->server->time_event_queue;
s->next_id = 0;
return 0;
/* Add all matching known answers to the list */
- catta_cache_walk(s->interface->cache, qj->key, known_answer_walk_callback, s);
+ catta_cache_walk(s->iface->cache, qj->key, known_answer_walk_callback, s);
job_mark_done(s, qj);
catta_dns_packet_set_field(p, CATTA_DNS_FIELD_FLAGS, catta_dns_packet_get_field(p, CATTA_DNS_FIELD_FLAGS) | CATTA_DNS_FLAG_TC);
catta_dns_packet_set_field(p, CATTA_DNS_FIELD_ANCOUNT, n);
- catta_interface_send_packet(s->interface, p);
+ catta_interface_send_packet(s->iface, p);
catta_dns_packet_free(p);
- p = catta_dns_packet_new_query(s->interface->hardware->mtu);
+ p = catta_dns_packet_new_query(s->iface->hardware->mtu);
n = 0;
}
}
catta_dns_packet_set_field(p, CATTA_DNS_FIELD_ANCOUNT, n);
- catta_interface_send_packet(s->interface, p);
+ catta_interface_send_packet(s->iface, p);
catta_dns_packet_free(p);
}
assert(!s->known_answers);
- if (!(p = catta_dns_packet_new_query(s->interface->hardware->mtu)))
+ if (!(p = catta_dns_packet_new_query(s->iface->hardware->mtu)))
return; /* OOM */
b = packet_add_query_job(s, p, qj);
void* userdata;
CattaRecord *ptr_record;
- CattaIfIndex interface;
+ CattaIfIndex iface;
CattaProtocol protocol;
CattaLookupResultFlags flags;
switch (event) {
case CATTA_RESOLVER_FAILURE:
- r->callback(r, r->interface, r->protocol, event, &r->address, NULL, r->flags, r->userdata);
+ r->callback(r, r->iface, r->protocol, event, &r->address, NULL, r->flags, r->userdata);
break;
case CATTA_RESOLVER_FOUND:
assert(r->ptr_record);
- r->callback(r, r->interface, r->protocol, event, &r->address, r->ptr_record->data.ptr.name, r->flags, r->userdata);
+ r->callback(r, r->iface, r->protocol, event, &r->address, r->ptr_record->data.ptr.name, r->flags, r->userdata);
break;
}
}
static void record_browser_callback(
CattaSRecordBrowser*rr,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
CattaRecord *record,
assert(record);
assert(record->key->type == CATTA_DNS_TYPE_PTR);
- if (r->interface > 0 && interface != r->interface)
+ if (r->iface > 0 && iface != r->iface)
return;
if (r->protocol != CATTA_PROTO_UNSPEC && protocol != r->protocol)
return;
- if (r->interface <= 0)
- r->interface = interface;
+ if (r->iface <= 0)
+ r->iface = iface;
if (r->protocol == CATTA_PROTO_UNSPEC)
r->protocol = protocol;
r->retry_with_multicast = 0;
catta_s_record_browser_free(r->record_browser);
- r->record_browser = catta_s_record_browser_new(r->server, r->interface, r->protocol, r->key, CATTA_LOOKUP_USE_MULTICAST, record_browser_callback, r);
+ r->record_browser = catta_s_record_browser_new(r->server, r->iface, r->protocol, r->key, CATTA_LOOKUP_USE_MULTICAST, record_browser_callback, r);
if (r->record_browser) {
start_timeout(r);
CattaSAddressResolver *catta_s_address_resolver_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const CattaAddress *address,
CattaLookupFlags flags,
assert(address);
assert(callback);
- CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, address->proto == CATTA_PROTO_INET || address->proto == CATTA_PROTO_INET6, CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_FLAGS_VALID(flags, CATTA_LOOKUP_USE_WIDE_AREA|CATTA_LOOKUP_USE_MULTICAST), CATTA_ERR_INVALID_FLAGS);
r->callback = callback;
r->userdata = userdata;
r->ptr_record = NULL;
- r->interface = interface;
+ r->iface = iface;
r->protocol = protocol;
r->flags = 0;
r->retry_with_multicast = 0;
}
}
- r->record_browser = catta_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, r);
+ r->record_browser = catta_s_record_browser_new(server, iface, protocol, k, flags, record_browser_callback, r);
if (!r->record_browser) {
catta_s_address_resolver_free(r);
void* userdata;
CattaRecord *address_record;
- CattaIfIndex interface;
+ CattaIfIndex iface;
CattaProtocol protocol;
CattaLookupResultFlags flags;
abort();
}
- r->callback(r, r->interface, r->protocol, CATTA_RESOLVER_FOUND, r->address_record->key->name, &a, r->flags, r->userdata);
+ r->callback(r, r->iface, r->protocol, CATTA_RESOLVER_FOUND, r->address_record->key->name, &a, r->flags, r->userdata);
break;
}
case CATTA_RESOLVER_FAILURE:
- r->callback(r, r->interface, r->protocol, event, r->host_name, NULL, r->flags, r->userdata);
+ r->callback(r, r->iface, r->protocol, event, r->host_name, NULL, r->flags, r->userdata);
break;
}
}
static void record_browser_callback(
CattaSRecordBrowser*rr,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
CattaRecord *record,
assert(record);
assert(record->key->type == CATTA_DNS_TYPE_A || record->key->type == CATTA_DNS_TYPE_AAAA);
- if (r->interface > 0 && interface != r->interface)
+ if (r->iface > 0 && iface != r->iface)
return;
if (r->protocol != CATTA_PROTO_UNSPEC && protocol != r->protocol)
return;
- if (r->interface <= 0)
- r->interface = interface;
+ if (r->iface <= 0)
+ r->iface = iface;
if (r->protocol == CATTA_PROTO_UNSPEC)
r->protocol = protocol;
CattaSHostNameResolver *catta_s_host_name_resolver_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *host_name,
CattaProtocol aprotocol,
assert(host_name);
assert(callback);
- CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, catta_is_valid_fqdn(host_name), CATTA_ERR_INVALID_HOST_NAME);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_PROTO_VALID(aprotocol), CATTA_ERR_INVALID_PROTOCOL);
r->callback = callback;
r->userdata = userdata;
r->address_record = NULL;
- r->interface = interface;
+ r->iface = iface;
r->protocol = protocol;
r->flags = 0;
if (aprotocol == CATTA_PROTO_INET || aprotocol == CATTA_PROTO_UNSPEC) {
k = catta_key_new(host_name, CATTA_DNS_CLASS_IN, CATTA_DNS_TYPE_A);
- r->record_browser_a = catta_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, r);
+ r->record_browser_a = catta_s_record_browser_new(server, iface, protocol, k, flags, record_browser_callback, r);
catta_key_unref(k);
if (!r->record_browser_a)
if (aprotocol == CATTA_PROTO_INET6 || aprotocol == CATTA_PROTO_UNSPEC) {
k = catta_key_new(host_name, CATTA_DNS_CLASS_IN, CATTA_DNS_TYPE_AAAA);
- r->record_browser_aaaa = catta_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, r);
+ r->record_browser_aaaa = catta_s_record_browser_new(server, iface, protocol, k, flags, record_browser_callback, r);
catta_key_unref(k);
if (!r->record_browser_aaaa)
char *domain_name;
CattaProtocol address_protocol;
- CattaIfIndex interface;
+ CattaIfIndex iface;
CattaProtocol protocol;
CattaSRecordBrowser *record_browser_srv;
r->callback(
r,
- r->interface,
+ r->iface,
r->protocol,
event,
r->service_name,
r->callback(
r,
- r->interface,
+ r->iface,
r->protocol,
event,
r->service_name,
static void record_browser_callback(
CattaSRecordBrowser*rr,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
CattaRecord *record,
int changed = 0;
assert(record);
- if (r->interface > 0 && interface > 0 && interface != r->interface)
+ if (r->iface > 0 && iface > 0 && iface != r->iface)
return;
if (r->protocol != CATTA_PROTO_UNSPEC && protocol != CATTA_PROTO_UNSPEC && protocol != r->protocol)
return;
- if (r->interface <= 0)
- r->interface = interface;
+ if (r->iface <= 0)
+ r->iface = iface;
if (r->protocol == CATTA_PROTO_UNSPEC)
r->protocol = protocol;
if (r->address_protocol == CATTA_PROTO_INET || r->address_protocol == CATTA_PROTO_UNSPEC) {
CattaKey *k = catta_key_new(r->srv_record->data.srv.name, CATTA_DNS_CLASS_IN, CATTA_DNS_TYPE_A);
- r->record_browser_a = catta_s_record_browser_new(r->server, r->interface, r->protocol, k, r->user_flags & ~(CATTA_LOOKUP_NO_TXT|CATTA_LOOKUP_NO_ADDRESS), record_browser_callback, r);
+ r->record_browser_a = catta_s_record_browser_new(r->server, r->iface, r->protocol, k, r->user_flags & ~(CATTA_LOOKUP_NO_TXT|CATTA_LOOKUP_NO_ADDRESS), record_browser_callback, r);
catta_key_unref(k);
}
if (r->address_protocol == CATTA_PROTO_INET6 || r->address_protocol == CATTA_PROTO_UNSPEC) {
CattaKey *k = catta_key_new(r->srv_record->data.srv.name, CATTA_DNS_CLASS_IN, CATTA_DNS_TYPE_AAAA);
- r->record_browser_aaaa = catta_s_record_browser_new(r->server, r->interface, r->protocol, k, r->user_flags & ~(CATTA_LOOKUP_NO_TXT|CATTA_LOOKUP_NO_ADDRESS), record_browser_callback, r);
+ r->record_browser_aaaa = catta_s_record_browser_new(r->server, r->iface, r->protocol, k, r->user_flags & ~(CATTA_LOOKUP_NO_TXT|CATTA_LOOKUP_NO_ADDRESS), record_browser_callback, r);
catta_key_unref(k);
}
}
CattaSServiceResolver *catta_s_service_resolver_new(
CattaServer *server,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
const char *name,
const char *type,
assert(type);
assert(callback);
- CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, CATTA_PROTO_VALID(aprotocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY_RETURN_NULL(server, !domain || catta_is_valid_domain_name(domain), CATTA_ERR_INVALID_DOMAIN_NAME);
r->address_protocol = aprotocol;
r->srv_record = r->txt_record = r->address_record = NULL;
r->srv_flags = r->txt_flags = r->address_flags = 0;
- r->interface = interface;
+ r->iface = iface;
r->protocol = protocol;
r->user_flags = flags;
r->record_browser_a = r->record_browser_aaaa = r->record_browser_srv = r->record_browser_txt = NULL;
CATTA_LLIST_PREPEND(CattaSServiceResolver, resolver, server->service_resolvers, r);
k = catta_key_new(n, CATTA_DNS_CLASS_IN, CATTA_DNS_TYPE_SRV);
- r->record_browser_srv = catta_s_record_browser_new(server, interface, protocol, k, flags & ~(CATTA_LOOKUP_NO_TXT|CATTA_LOOKUP_NO_ADDRESS), record_browser_callback, r);
+ r->record_browser_srv = catta_s_record_browser_new(server, iface, protocol, k, flags & ~(CATTA_LOOKUP_NO_TXT|CATTA_LOOKUP_NO_ADDRESS), record_browser_callback, r);
catta_key_unref(k);
if (!r->record_browser_srv) {
if (!(flags & CATTA_LOOKUP_NO_TXT)) {
k = catta_key_new(n, CATTA_DNS_CLASS_IN, CATTA_DNS_TYPE_TXT);
- r->record_browser_txt = catta_s_record_browser_new(server, interface, protocol, k, flags & ~(CATTA_LOOKUP_NO_TXT|CATTA_LOOKUP_NO_ADDRESS), record_browser_callback, r);
+ r->record_browser_txt = catta_s_record_browser_new(server, iface, protocol, k, flags & ~(CATTA_LOOKUP_NO_TXT|CATTA_LOOKUP_NO_ADDRESS), record_browser_callback, r);
catta_key_unref(k);
if (!r->record_browser_txt) {
};
struct CattaResponseScheduler {
- CattaInterface *interface;
+ CattaInterface *iface;
CattaTimeEventQueue *time_event_queue;
CATTA_LLIST_HEAD(CattaResponseJob, jobs);
return NULL;
}
- s->interface = i;
+ s->iface = i;
s->time_event_queue = i->monitor->server->time_event_queue;
CATTA_LLIST_HEAD_INIT(CattaResponseJob, s->jobs);
/* Ok, this record will definitely be sent, so schedule the
* auxilliary packets, too */
- catta_server_enumerate_aux_records(s->interface->monitor->server, s->interface, rj->record, enumerate_aux_records_callback, rj);
+ catta_server_enumerate_aux_records(s->iface->monitor->server, s->iface, rj->record, enumerate_aux_records_callback, rj);
job_mark_done(s, rj);
return 1;
assert(s);
assert(rj);
- if (!(p = catta_dns_packet_new_response(s->interface->hardware->mtu, 1)))
+ if (!(p = catta_dns_packet_new_response(s->iface->hardware->mtu, 1)))
return; /* OOM */
n = 1;
}
catta_dns_packet_set_field(p, CATTA_DNS_FIELD_ANCOUNT, n);
- catta_interface_send_packet(s->interface, p);
+ catta_interface_send_packet(s->iface, p);
catta_dns_packet_free(p);
}
switch (r->key->type) {
case CATTA_DNS_TYPE_A:
- inet_ntop(AF_INET, &r->data.a.address.address, t = buf, sizeof(buf));
+ inet_ntop(AF_INET, (void *)&r->data.a.address.address, t = buf, sizeof(buf));
break;
case CATTA_DNS_TYPE_AAAA:
- inet_ntop(AF_INET6, &r->data.aaaa.address.address, t = buf, sizeof(buf));
+ inet_ntop(AF_INET6, (void *)&r->data.aaaa.address.address, t = buf, sizeof(buf));
break;
case CATTA_DNS_TYPE_PTR:
if (!s->config.enable_reflector)
return;
- for (j = s->monitor->interfaces; j; j = j->interface_next)
+ for (j = s->monitor->interfaces; j; j = j->iface_next)
if (j != i && (s->config.reflect_ipv || j->protocol == i->protocol))
catta_interface_post_response(j, r, flush_cache, NULL, 1);
}
if (!s->config.enable_reflector)
return;
- for (j = s->monitor->interfaces; j; j = j->interface_next)
+ for (j = s->monitor->interfaces; j; j = j->iface_next)
if (j != i && (s->config.reflect_ipv || j->protocol == i->protocol)) {
/* Post the query to other networks */
catta_interface_post_query(j, k, 1, NULL);
if (!s->config.enable_reflector)
return;
- for (j = s->monitor->interfaces; j; j = j->interface_next)
+ for (j = s->monitor->interfaces; j; j = j->iface_next)
if (j != i && (s->config.reflect_ipv || j->protocol == i->protocol))
catta_interface_post_probe(j, r, 1);
}
slot->original_id = catta_dns_packet_get_field(p, CATTA_DNS_FIELD_ID);
slot->address = *a;
slot->port = port;
- slot->interface = i->hardware->index;
+ slot->iface = i->hardware->index;
catta_elapse_time(&slot->elapse_time, 2000, 0);
slot->time_event = catta_time_event_new(s->time_event_queue, &slot->elapse_time, legacy_unicast_reflect_slot_timeout, slot);
/* Patch the packet with our new locally generatet id */
catta_dns_packet_set_field(p, CATTA_DNS_FIELD_ID, slot->id);
- for (j = s->monitor->interfaces; j; j = j->interface_next)
+ for (j = s->monitor->interfaces; j; j = j->iface_next)
if (j->announcing &&
j != i &&
(s->config.reflect_ipv || j->protocol == i->protocol)) {
socklen_t l = sizeof(lsa);
if (getsockname(s->fd_legacy_unicast_ipv4, (struct sockaddr*) &lsa, &l) != 0)
- catta_log_warn("getsockname(): %s", strerror(errno));
+ catta_log_warn("getsockname(): %s", errnostrsocket());
else
return catta_port_from_sockaddr((struct sockaddr*) &lsa) == port;
socklen_t l = sizeof(lsa);
if (getsockname(s->fd_legacy_unicast_ipv6, (struct sockaddr*) &lsa, &l) != 0)
- catta_log_warn("getsockname(): %s", strerror(errno));
+ catta_log_warn("getsockname(): %s", errnostrsocket());
else
return catta_port_from_sockaddr((struct sockaddr*) &lsa) == port;
}
assert(iface > 0);
assert(src_address->proto == dst_address->proto);
- if (!(i = catta_interface_monitor_get_interface(s->monitor, iface, src_address->proto)) ||
- !i->announcing) {
- catta_log_warn("Received packet from invalid interface.");
+ if (!(i = catta_interface_monitor_get_interface(s->monitor, iface, src_address->proto))) {
+ catta_log_warn("Received packet from unrecognized interface (%d).", iface);
+ return;
+ }
+ if (!i->announcing) {
+ catta_log_warn("Received packet from invalid interface %d (not announcing).", iface);
return;
}
return;
}
- if (!(j = catta_interface_monitor_get_interface(s->monitor, slot->interface, slot->address.proto)) ||
+ if (!(j = catta_interface_monitor_get_interface(s->monitor, slot->iface, slot->address.proto)) ||
!j->announcing)
return;
else
catta_server_config_init(&s->config);
+ winsock_init(); // on Windows, call WSAStartup; no-op on other platforms
if ((e = setup_sockets(s)) < 0) {
if (error)
*error = e;
catta_server_config_free(&s->config);
catta_free(s);
+ winsock_exit();
return NULL;
}
/* Free sockets */
if (s->fd_ipv4 >= 0)
- close(s->fd_ipv4);
+ closesocket(s->fd_ipv4);
if (s->fd_ipv6 >= 0)
- close(s->fd_ipv6);
+ closesocket(s->fd_ipv6);
if (s->fd_legacy_unicast_ipv4 >= 0)
- close(s->fd_legacy_unicast_ipv4);
+ closesocket(s->fd_legacy_unicast_ipv4);
if (s->fd_legacy_unicast_ipv6 >= 0)
- close(s->fd_legacy_unicast_ipv6);
+ closesocket(s->fd_legacy_unicast_ipv6);
/* Free other stuff */
catta_server_config_free(&s->config);
catta_free(s);
+ winsock_exit(); // on Windows, call WSACleanup(); no-op on other platforms
}
const char* catta_server_get_domain_name(CattaServer *s) {
return s->local_service_cookie;
}
-static CattaEntry *find_entry(CattaServer *s, CattaIfIndex interface, CattaProtocol protocol, CattaKey *key) {
+static CattaEntry *find_entry(CattaServer *s, CattaIfIndex iface, CattaProtocol protocol, CattaKey *key) {
CattaEntry *e;
assert(s);
for (e = catta_hashmap_lookup(s->entries_by_key, key); e; e = e->by_key_next)
- if ((e->interface == interface || e->interface <= 0 || interface <= 0) &&
+ if ((e->iface == iface || e->iface <= 0 || iface <= 0) &&
(e->protocol == protocol || e->protocol == CATTA_PROTO_UNSPEC || protocol == CATTA_PROTO_UNSPEC) &&
(!e->group || e->group->state == CATTA_ENTRY_GROUP_ESTABLISHED || e->group->state == CATTA_ENTRY_GROUP_REGISTERING))
return NULL;
}
-int catta_server_get_group_of_service(CattaServer *s, CattaIfIndex interface, CattaProtocol protocol, const char *name, const char *type, const char *domain, CattaSEntryGroup** ret_group) {
+int catta_server_get_group_of_service(CattaServer *s, CattaIfIndex iface, CattaProtocol protocol, const char *name, const char *type, const char *domain, CattaSEntryGroup** ret_group) {
CattaKey *key = NULL;
CattaEntry *e;
int ret;
assert(type);
assert(ret_group);
- CATTA_CHECK_VALIDITY(s, CATTA_IF_VALID(interface), CATTA_ERR_INVALID_INTERFACE);
+ CATTA_CHECK_VALIDITY(s, CATTA_IF_VALID(iface), CATTA_ERR_INVALID_INTERFACE);
CATTA_CHECK_VALIDITY(s, CATTA_PROTO_VALID(protocol), CATTA_ERR_INVALID_PROTOCOL);
CATTA_CHECK_VALIDITY(s, catta_is_valid_service_name(name), CATTA_ERR_INVALID_SERVICE_NAME);
CATTA_CHECK_VALIDITY(s, catta_is_valid_service_type_strict(type), CATTA_ERR_INVALID_SERVICE_TYPE);
if (!(key = catta_key_new(n, CATTA_DNS_CLASS_IN, CATTA_DNS_TYPE_SRV)))
return catta_server_set_errno(s, CATTA_ERR_NO_MEMORY);
- e = find_entry(s, interface, protocol, key);
+ e = find_entry(s, iface, protocol, key);
catta_key_unref(key);
if (e) {
return catta_server_set_errno(s, CATTA_ERR_NOT_FOUND);
}
-int catta_server_is_service_local(CattaServer *s, CattaIfIndex interface, CattaProtocol protocol, const char *name) {
+int catta_server_is_service_local(CattaServer *s, CattaIfIndex iface, CattaProtocol protocol, const char *name) {
CattaKey *key = NULL;
CattaEntry *e;
if (!(key = catta_key_new(name, CATTA_DNS_CLASS_IN, CATTA_DNS_TYPE_SRV)))
return 0;
- e = find_entry(s, interface, protocol, key);
+ e = find_entry(s, iface, protocol, key);
catta_key_unref(key);
if (!e)
return catta_domain_equal(s->host_name_fqdn, e->record->data.srv.name);
}
-int catta_server_is_record_local(CattaServer *s, CattaIfIndex interface, CattaProtocol protocol, CattaRecord *record) {
+int catta_server_is_record_local(CattaServer *s, CattaIfIndex iface, CattaProtocol protocol, CattaRecord *record) {
CattaEntry *e;
assert(s);
for (e = catta_hashmap_lookup(s->entries_by_key, record->key); e; e = e->by_key_next)
- if ((e->interface == interface || e->interface <= 0 || interface <= 0) &&
+ if ((e->iface == iface || e->iface <= 0 || iface <= 0) &&
(e->protocol == protocol || e->protocol == CATTA_PROTO_UNSPEC || protocol == CATTA_PROTO_UNSPEC) &&
(!e->group || e->group->state == CATTA_ENTRY_GROUP_ESTABLISHED || e->group->state == CATTA_ENTRY_GROUP_REGISTERING) &&
catta_record_equal_no_ttl(record, e->record))
#include <catta/malloc.h>
#include <catta/timeval.h>
#include <catta/simple-watch.h>
+#include <catta/log.h>
+#include "fdutil.h" // catta_set_nonblock
+#include "internal.h" // closesocket
struct CattaWatch {
CattaSimplePoll *simple_poll;
char c = 'W';
assert(s);
- write(s->wakeup_pipe[1], &c, sizeof(c));
+ (void)writepipe(s->wakeup_pipe[1], &c, sizeof(c));
s->wakeup_issued = 1;
}
s->wakeup_issued = 0;
- for(;;)
- if (read(s->wakeup_pipe[0], &c, sizeof(c)) != sizeof(c))
+ for(;;) {
+ if (readpipe(s->wakeup_pipe[0], c, sizeof(c)) != sizeof(c))
break;
-}
-
-static int set_nonblock(int fd) {
- int n;
-
- assert(fd >= 0);
-
- if ((n = fcntl(fd, F_GETFL)) < 0)
- return -1;
-
- if (n & O_NONBLOCK)
- return 0;
-
- return fcntl(fd, F_SETFL, n|O_NONBLOCK);
+ }
}
static CattaWatch* watch_new(const CattaPoll *api, int fd, CattaWatchEvent event, CattaWatchCallback callback, void *userdata) {
if (!(s = catta_new(CattaSimplePoll, 1)))
return NULL;
+ winsock_init(); // on Windows, pipe uses sockets; no-op on other platforms
if (pipe(s->wakeup_pipe) < 0) {
- catta_free(s);
- return NULL;
+ catta_log_error(__FILE__": pipe() failed: %s", errnostrsocket());
+ goto fail;
}
- set_nonblock(s->wakeup_pipe[0]);
- set_nonblock(s->wakeup_pipe[1]);
+ if (catta_set_nonblock(s->wakeup_pipe[0]) < 0 ||
+ catta_set_nonblock(s->wakeup_pipe[1]) < 0)
+ {
+ catta_log_error(__FILE__": O_NONBLOCK failed: %s", errnostrsocket());
+ goto fail;
+ }
s->api.userdata = s;
CATTA_LLIST_HEAD_INIT(CattaTimeout, s->timeouts);
return s;
+
+fail:
+ catta_free(s);
+ winsock_exit();
+ return NULL;
}
void catta_simple_poll_free(CattaSimplePoll *s) {
catta_free(s->pollfds);
if (s->wakeup_pipe[0] >= 0)
- close(s->wakeup_pipe[0]);
+ closepipe(s->wakeup_pipe[0]);
if (s->wakeup_pipe[1] >= 0)
- close(s->wakeup_pipe[1]);
+ closepipe(s->wakeup_pipe[1]);
catta_free(s);
+ winsock_exit(); // match the winsock_init in catta_simple_poll_new
}
static int rebuild(CattaSimplePoll *s) {
assert(s->state == STATE_RAN);
s->state = STATE_DISPATCHING;
- /* We execute only on callback in every iteration */
+ /* We execute only one callback in every iteration */
/* Check whether the wakeup time has been reached now */
if ((next_timeout = find_next_timeout(s))) {
#include "fdutil.h"
#include "socket.h"
#include "addr-util.h"
+#include "internal.h"
/* this is a portability hack */
#ifndef IPV6_ADD_MEMBERSHIP
memcpy(&ret_sa->sin6_addr, a, sizeof(CattaIPv6Address));
}
-int catta_mdns_mcast_join_ipv4(int fd, const CattaIPv4Address *a, int idx, int join) {
+int catta_mdns_mcast_join_ipv4(int fd, const CattaIPv4Address *a, CattaIfIndex idx, int join) {
#ifdef HAVE_STRUCT_IP_MREQN
struct ip_mreqn mreq;
#else
* mcast groups when the iface is down, but don't allow rejoining
* when it comes back up. This is an ugly workaround */
if (join)
- setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
+ setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq));
- if (setsockopt(fd, IPPROTO_IP, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
- catta_log_warn("%s failed: %s", join ? "IP_ADD_MEMBERSHIP" : "IP_DROP_MEMBERSHIP", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IP, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
+ catta_log_warn("%s failed: %s", join ? "IP_ADD_MEMBERSHIP" : "IP_DROP_MEMBERSHIP", errnostrsocket());
return -1;
}
return 0;
}
-int catta_mdns_mcast_join_ipv6(int fd, const CattaIPv6Address *a, int idx, int join) {
+int catta_mdns_mcast_join_ipv6(int fd, const CattaIPv6Address *a, CattaIfIndex idx, int join) {
struct ipv6_mreq mreq6;
struct sockaddr_in6 sa6;
mreq6.ipv6mr_interface = idx;
if (join)
- setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));
+ setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (void *)&mreq6, sizeof(mreq6));
- if (setsockopt(fd, IPPROTO_IPV6, join ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
- catta_log_warn("%s failed: %s", join ? "IPV6_ADD_MEMBERSHIP" : "IPV6_DROP_MEMBERSHIP", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, join ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, (void *)&mreq6, sizeof(mreq6)) < 0) {
+ catta_log_warn("%s failed: %s", join ? "IPV6_ADD_MEMBERSHIP" : "IPV6_DROP_MEMBERSHIP", errnostrsocket());
return -1;
}
int yes;
yes = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
- catta_log_warn("SO_REUSEADDR failed: %s", strerror(errno));
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("SO_REUSEADDR failed: %s", errnostrsocket());
return -1;
}
#ifdef SO_REUSEPORT
yes = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0) {
- catta_log_warn("SO_REUSEPORT failed: %s", strerror(errno));
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("SO_REUSEPORT failed: %s", errnostrsocket());
return -1;
}
#endif
assert(sa);
assert(l > 0);
+#ifdef _WIN32
+ // Windows does not allow address reuse when SO_REUSEADDR was set after
+ // bind() on the first socket, so we must set it before.
+ // Note that this spoils the detection trickery below and the warning will
+ // not be logged.
+
+ if (reuseaddr(fd) < 0)
+ return -1;
+#endif
+
if (bind(fd, sa, l) < 0) {
if (errno != EADDRINUSE) {
- catta_log_warn("bind() failed: %s", strerror(errno));
+ catta_log_warn("bind() failed: %s", errnostrsocket());
return -1;
}
return -1;
if (bind(fd, sa, l) < 0) {
- catta_log_warn("bind() failed: %s", strerror(errno));
+ catta_log_warn("bind() failed: %s", errnostrsocket());
return -1;
}
} else {
#ifdef IP_PKTINFO
yes = 1;
- if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IP_PKTINFO failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IP_PKTINFO failed: %s", errnostrsocket());
return -1;
}
#else
#ifdef IP_RECVINTERFACE
yes = 1;
- if (setsockopt (fd, IPPROTO_IP, IP_RECVINTERFACE, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IP_RECVINTERFACE failed: %s", strerror(errno));
+ if (setsockopt (fd, IPPROTO_IP, IP_RECVINTERFACE, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IP_RECVINTERFACE failed: %s", errnostrsocket());
return -1;
}
#elif defined(IP_RECVIF)
yes = 1;
- if (setsockopt (fd, IPPROTO_IP, IP_RECVIF, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IP_RECVIF failed: %s", strerror(errno));
+ if (setsockopt (fd, IPPROTO_IP, IP_RECVIF, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IP_RECVIF failed: %s", errnostrsocket());
return -1;
}
#endif
#ifdef IP_RECVDSTADDR
yes = 1;
- if (setsockopt (fd, IPPROTO_IP, IP_RECVDSTADDR, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IP_RECVDSTADDR failed: %s", strerror(errno));
+ if (setsockopt (fd, IPPROTO_IP, IP_RECVDSTADDR, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IP_RECVDSTADDR failed: %s", errnostrsocket());
return -1;
}
#endif
#ifdef IP_RECVTTL
yes = 1;
- if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IP_RECVTTL failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IP_RECVTTL failed: %s", errnostrsocket());
return -1;
}
#endif
#ifdef IPV6_RECVPKTINFO
yes = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IPV6_RECVPKTINFO failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IPV6_RECVPKTINFO failed: %s", errnostrsocket());
return -1;
}
#elif defined(IPV6_PKTINFO)
yes = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IPV6_PKTINFO failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IPV6_PKTINFO failed: %s", errnostrsocket());
return -1;
}
#endif
#ifdef IPV6_RECVHOPS
yes = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPS, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IPV6_RECVHOPS failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPS, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IPV6_RECVHOPS failed: %s", errnostrsocket());
return -1;
}
#elif defined(IPV6_RECVHOPLIMIT)
yes = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IPV6_RECVHOPLIMIT failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IPV6_RECVHOPLIMIT failed: %s", errnostrsocket());
return -1;
}
#elif defined(IPV6_HOPLIMIT)
yes = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IPV6_HOPLIMIT failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IPV6_HOPLIMIT failed: %s", errnostrsocket());
return -1;
}
#endif
uint8_t ttl, cyes;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- catta_log_warn("socket() failed: %s", strerror(errno));
+ catta_log_warn("socket() failed: %s", errnostrsocket());
goto fail;
}
ttl = 255;
- if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
- catta_log_warn("IP_MULTICAST_TTL failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof(ttl)) < 0) {
+ catta_log_warn("IP_MULTICAST_TTL failed: %s", errnostrsocket());
goto fail;
}
ittl = 255;
- if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ittl, sizeof(ittl)) < 0) {
- catta_log_warn("IP_TTL failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IP, IP_TTL, (void *)&ittl, sizeof(ittl)) < 0) {
+ catta_log_warn("IP_TTL failed: %s", errnostrsocket());
goto fail;
}
cyes = 1;
- if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &cyes, sizeof(cyes)) < 0) {
- catta_log_warn("IP_MULTICAST_LOOP failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&cyes, sizeof(cyes)) < 0) {
+ catta_log_warn("IP_MULTICAST_LOOP failed: %s", errnostrsocket());
goto fail;
}
goto fail;
if (catta_set_cloexec(fd) < 0) {
- catta_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
+ catta_log_warn("FD_CLOEXEC failed: %s", errnostrsocket());
goto fail;
}
if (catta_set_nonblock(fd) < 0) {
- catta_log_warn("O_NONBLOCK failed: %s", strerror(errno));
+ catta_log_warn("O_NONBLOCK failed: %s", errnostrsocket());
goto fail;
}
fail:
if (fd >= 0)
- close(fd);
+ closesocket(fd);
return -1;
}
mdns_mcast_group_ipv6(&sa);
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
- catta_log_warn("socket() failed: %s", strerror(errno));
+ catta_log_warn("socket() failed: %s", errnostrsocket());
goto fail;
}
ttl = 255;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
- catta_log_warn("IPV6_MULTICAST_HOPS failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (void *)&ttl, sizeof(ttl)) < 0) {
+ catta_log_warn("IPV6_MULTICAST_HOPS failed: %s", errnostrsocket());
goto fail;
}
ttl = 255;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
- catta_log_warn("IPV6_UNICAST_HOPS failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (void *)&ttl, sizeof(ttl)) < 0) {
+ catta_log_warn("IPV6_UNICAST_HOPS failed: %s", errnostrsocket());
goto fail;
}
yes = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IPV6_V6ONLY failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IPV6_V6ONLY failed: %s", errnostrsocket());
goto fail;
}
yes = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IPV6_MULTICAST_LOOP failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IPV6_MULTICAST_LOOP failed: %s", errnostrsocket());
goto fail;
}
goto fail;
if (catta_set_cloexec(fd) < 0) {
- catta_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
+ catta_log_warn("FD_CLOEXEC failed: %s", errnostrsocket());
goto fail;
}
if (catta_set_nonblock(fd) < 0) {
- catta_log_warn("O_NONBLOCK failed: %s", strerror(errno));
+ catta_log_warn("O_NONBLOCK failed: %s", errnostrsocket());
goto fail;
}
fail:
if (fd >= 0)
- close(fd);
+ closesocket(fd);
return -1;
}
if (errno == EINTR)
continue;
- if (errno != EAGAIN) {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
char where[64];
- struct sockaddr_in *sin = msg->msg_name;
+ struct sockaddr *sa = msg->msg_name;
- inet_ntop(sin->sin_family, &sin->sin_addr, where, sizeof(where));
- catta_log_debug("sendmsg() to %s failed: %s", where, strerror(errno));
+ if(sa->sa_family == AF_INET)
+ inet_ntop(sa->sa_family, &((struct sockaddr_in *)sa)->sin_addr, where, sizeof(where));
+ else
+ inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)sa)->sin6_addr, where, sizeof(where));
+ catta_log_debug("sendmsg() to %s failed: %s", where, errnostrsocket());
return -1;
}
int catta_send_dns_packet_ipv4(
int fd,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaDnsPacket *p,
const CattaIPv4Address *src_address,
const CattaIPv4Address *dst_address,
msg.msg_controllen = 0;
#ifdef IP_PKTINFO
- if (interface > 0 || src_address) {
+ if (iface > 0 || src_address) {
struct in_pktinfo *pkti;
memset(cmsg_data, 0, sizeof(cmsg_data));
pkti = (struct in_pktinfo*) CMSG_DATA(cmsg);
- if (interface > 0)
- pkti->ipi_ifindex = interface;
+ if (iface > 0)
+ pkti->ipi_ifindex = iface;
+#ifdef HAVE_IPI_SPEC_DST
if (src_address)
pkti->ipi_spec_dst.s_addr = src_address->address;
+#else
+ if (src_address)
+ pkti->ipi_addr.s_addr = src_address->address;
+#endif
}
#elif defined(IP_MULTICAST_IF)
if (src_address) {
struct in_addr any = { INADDR_ANY };
- if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, src_address ? &src_address->address : &any, sizeof(struct in_addr)) < 0) {
- catta_log_warn("IP_MULTICAST_IF failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *)(src_address ? &src_address->address : &any), sizeof(struct in_addr)) < 0) {
+ catta_log_warn("IP_MULTICAST_IF failed: %s", errnostrsocket());
return -1;
}
}
int catta_send_dns_packet_ipv6(
int fd,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaDnsPacket *p,
const CattaIPv6Address *src_address,
const CattaIPv6Address *dst_address,
msg.msg_iovlen = 1;
msg.msg_flags = 0;
- if (interface > 0 || src_address) {
+ if (iface > 0 || src_address) {
struct in6_pktinfo *pkti;
memset(cmsg_data, 0, sizeof(cmsg_data));
pkti = (struct in6_pktinfo*) CMSG_DATA(cmsg);
- if (interface > 0)
- pkti->ipi6_ifindex = interface;
+ if (iface > 0)
+ pkti->ipi6_ifindex = iface;
if (src_address)
memcpy(&pkti->ipi6_addr, src_address->address, sizeof(src_address->address));
assert(fd >= 0);
if (ioctl(fd, FIONREAD, &ms) < 0) {
- catta_log_warn("ioctl(): %s", strerror(errno));
+ catta_log_warn("ioctl(): %s", errnostrsocket());
goto fail;
}
links. (See #60) */
if (errno != EAGAIN)
- catta_log_warn("recvmsg(): %s", strerror(errno));
+ catta_log_warn("recvmsg(): %s", errnostrsocket());
goto fail;
}
assert(fd >= 0);
if (ioctl(fd, FIONREAD, &ms) < 0) {
- catta_log_warn("ioctl(): %s", strerror(errno));
+ catta_log_warn("ioctl(): %s", errnostrsocket());
goto fail;
}
links. (See #60) */
if (errno != EAGAIN)
- catta_log_warn("recvmsg(): %s", strerror(errno));
+ catta_log_warn("recvmsg(): %s", errnostrsocket());
goto fail;
}
int fd = -1;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- catta_log_warn("socket() failed: %s", strerror(errno));
+ catta_log_warn("socket() failed: %s", errnostrsocket());
goto fail;
}
local.sin_family = AF_INET;
if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
- catta_log_warn("bind() failed: %s", strerror(errno));
+ catta_log_warn("bind() failed: %s", errnostrsocket());
goto fail;
}
}
if (catta_set_cloexec(fd) < 0) {
- catta_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
+ catta_log_warn("FD_CLOEXEC failed: %s", errnostrsocket());
goto fail;
}
if (catta_set_nonblock(fd) < 0) {
- catta_log_warn("O_NONBLOCK failed: %s", strerror(errno));
+ catta_log_warn("O_NONBLOCK failed: %s", errnostrsocket());
goto fail;
}
fail:
if (fd >= 0)
- close(fd);
+ closesocket(fd);
return -1;
}
int fd = -1, yes;
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
- catta_log_warn("socket() failed: %s", strerror(errno));
+ catta_log_warn("socket() failed: %s", errnostrsocket());
goto fail;
}
yes = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
- catta_log_warn("IPV6_V6ONLY failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)) < 0) {
+ catta_log_warn("IPV6_V6ONLY failed: %s", errnostrsocket());
goto fail;
}
local.sin6_family = AF_INET6;
if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
- catta_log_warn("bind() failed: %s", strerror(errno));
+ catta_log_warn("bind() failed: %s", errnostrsocket());
goto fail;
}
goto fail;
if (catta_set_cloexec(fd) < 0) {
- catta_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
+ catta_log_warn("FD_CLOEXEC failed: %s", errnostrsocket());
goto fail;
}
if (catta_set_nonblock(fd) < 0) {
- catta_log_warn("O_NONBLOCK failed: %s", strerror(errno));
+ catta_log_warn("O_NONBLOCK failed: %s", errnostrsocket());
goto fail;
}
fail:
if (fd >= 0)
- close(fd);
+ closesocket(fd);
return -1;
}
CattaDnsPacket *catta_recv_dns_packet_ipv4(int fd, CattaIPv4Address *ret_src_address, uint16_t *ret_src_port, CattaIPv4Address *ret_dst_address, CattaIfIndex *ret_iface, uint8_t *ret_ttl);
CattaDnsPacket *catta_recv_dns_packet_ipv6(int fd, CattaIPv6Address *ret_src_address, uint16_t *ret_src_port, CattaIPv6Address *ret_dst_address, CattaIfIndex *ret_iface, uint8_t *ret_ttl);
-int catta_mdns_mcast_join_ipv4(int fd, const CattaIPv4Address *local_address, int iface, int join);
-int catta_mdns_mcast_join_ipv6(int fd, const CattaIPv6Address *local_address, int iface, int join);
+int catta_mdns_mcast_join_ipv4(int fd, const CattaIPv4Address *local_address, CattaIfIndex iface, int join);
+int catta_mdns_mcast_join_ipv6(int fd, const CattaIPv6Address *local_address, CattaIfIndex iface, int join);
#endif
static void* thread(void *userdata){
CattaThreadedPoll *p = userdata;
+
+#ifndef _WIN32
sigset_t mask;
/* Make sure that signals are delivered to the main thread */
sigfillset(&mask);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
+#endif
pthread_mutex_lock(&p->mutex);
p->retval = catta_simple_poll_loop(p->simple_poll);
e->fd_ipv6 = s->config.use_ipv6 ? catta_open_unicast_socket_ipv6() : -1;
if (e->fd_ipv4 < 0 && e->fd_ipv6 < 0) {
- catta_log_error(__FILE__": Failed to create wide area sockets: %s", strerror(errno));
+ catta_log_error(__FILE__": Failed to create wide area sockets: %s", errnostrsocket());
if (e->fd_ipv6 >= 0)
- close(e->fd_ipv6);
+ closesocket(e->fd_ipv6);
if (e->fd_ipv4 >= 0)
- close(e->fd_ipv4);
+ closesocket(e->fd_ipv4);
catta_free(e);
return NULL;
e->server->poll_api->watch_free(e->watch_ipv6);
if (e->fd_ipv6 >= 0)
- close(e->fd_ipv6);
+ closesocket(e->fd_ipv6);
if (e->fd_ipv4 >= 0)
- close(e->fd_ipv4);
+ closesocket(e->fd_ipv4);
catta_free(e);
}
conformance-test \
catta-reflector \
dns-test \
- dns-spin-test \
timeeventq-test \
hashmap-test \
querier-test \
update-test
TESTS = \
- dns-spin-test \
dns-test \
hashmap-test
+
+# disable the dns-spin-test on Windows (needs setitimer)
+if !WINDOWS
+noinst_PROGRAMS += dns-spin-test
+TESTS += dns-spin-test
+endif
endif
static void record_browser_callback(
CattaSRecordBrowser *r,
- CattaIfIndex interface,
+ CattaIfIndex iface,
CattaProtocol protocol,
CattaBrowserEvent event,
CattaRecord *record,
assert(r);
if (record) {
- catta_log_debug("RB: record [%s] on %i.%i is %s", t = catta_record_to_string(record), interface, protocol, browser_event_to_string(event));
+ catta_log_debug("RB: record [%s] on %i.%i is %s", t = catta_record_to_string(record), iface, protocol, browser_event_to_string(event));
catta_free(t);
} else
catta_log_debug("RB: [%s]", browser_event_to_string(event));
srand(time(NULL));
for (i = 0; i < 10000; i++)
- catta_prio_queue_put(q2, catta_prio_queue_put(q, INT_TO_POINTER(random() & 0xFFFF)));
+ catta_prio_queue_put(q2, catta_prio_queue_put(q, INT_TO_POINTER(rand() & 0xFFFF)));
while (q2->root) {
rec(q->root);
size = catta_string_list_serialize(a, data, sizeof(data));
assert(size == n);
- printf("%zu\n", size);
+ printf("%lu\n", (unsigned long)size);
for (t = (char*) data, n = 0; n < size; n++, t++) {
if (*t <= 32)
printf("%li.%li\n", a.tv_sec, a.tv_usec);
- printf("%lli\n", (long long) catta_timeval_diff(&a, &b));
+ printf("%li\n", (long) catta_timeval_diff(&a, &b));
return 0;
}