* NEW: afpd: POSIX 1e ACL support
* NEW: afpd: automagic Zeroconf registration with avahi, registering both
the service _afpovertcp._tcp and TimeMachine volumes with _adisk._tcp.
+
+Changes in 2.1.3
+================
+
+* FIX: afpd: fix a serious error in networking IO code
* UPD: Support for BerkeleyDB 5.0.
Changes in 2.1.2
-/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
/*
* Author: Daniel S. Haischt <me@daniel.stefan.haischt.name>
* Purpose: Avahi based Zeroconf support
* SRV service type.
*/
static void register_stuff(void) {
- uint port;
- const AFPConfig *config;
- const struct vol *volume;
- DSI *dsi;
- const char *name;
- AvahiStringList *strlist = NULL;
- char tmpname[256];
-
- assert(ctx->client);
-
- if (!ctx->group) {
- if (!(ctx->group = avahi_entry_group_new(ctx->client, publish_reply, ctx))) {
- LOG(log_error, logtype_afpd, "Failed to create entry group: %s",
- avahi_strerror(avahi_client_errno(ctx->client)));
- goto fail;
+ uint port;
+ const AFPConfig *config;
+ const struct vol *volume;
+ DSI *dsi;
+ char name[MAXINSTANCENAMELEN+1];
+ AvahiStringList *strlist = NULL;
+ char tmpname[256];
+
+ assert(ctx->client);
+
+ if (!ctx->group) {
+ if (!(ctx->group = avahi_entry_group_new(ctx->client, publish_reply, ctx))) {
+ LOG(log_error, logtype_afpd, "Failed to create entry group: %s",
+ avahi_strerror(avahi_client_errno(ctx->client)));
+ goto fail;
+ }
}
- }
- if (avahi_entry_group_is_empty(ctx->group)) {
- /* Register our service */
+ if (avahi_entry_group_is_empty(ctx->group)) {
+ /* Register our service */
- /* Build AFP volumes list */
- int i = 0;
- strlist = avahi_string_list_add_printf(strlist, "sys=waMa=0,adVF=0x100");
+ /* Build AFP volumes list */
+ int i = 0;
+ strlist = avahi_string_list_add_printf(strlist, "sys=waMa=0,adVF=0x100");
- for (volume = getvolumes(); volume; volume = volume->v_next) {
-
- if (convert_string(CH_UCS2, CH_UTF8_MAC, volume->v_name, -1, tmpname, 255) <= 0)
- goto fail;
-
- if (volume->v_flags & AFPVOL_TM) {
- if (volume->v_uuid) {
- LOG(log_info, logtype_afpd, "Registering volume '%s' with UUID: '%s' for TimeMachine",
- volume->v_localname, volume->v_uuid);
- strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1,adVU=%s",
- i++, tmpname, volume->v_uuid);
- } else {
- LOG(log_warning, logtype_afpd, "Registering volume '%s' for TimeMachine. But UUID is invalid.",
- volume->v_localname);
- strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1",
- i++, tmpname);
- }
- }
- }
-
- /* AFP server */
- for (config = ctx->configs; config; config = config->next) {
-
- dsi = (DSI *)config->obj.handle;
- name = config->obj.options.server ?
- config->obj.options.server : config->obj.options.hostname;
- port = getip_port((struct sockaddr *)&dsi->server);
-
- if (avahi_entry_group_add_service(ctx->group,
- AVAHI_IF_UNSPEC,
- AVAHI_PROTO_UNSPEC,
- 0,
- name,
- AFP_DNS_SERVICE_TYPE,
- NULL,
- NULL,
- port,
- NULL) < 0) {
- LOG(log_error, logtype_afpd, "Failed to add service: %s",
- avahi_strerror(avahi_client_errno(ctx->client)));
- goto fail;
- }
-
- if (i && avahi_entry_group_add_service_strlst(ctx->group,
- AVAHI_IF_UNSPEC,
- AVAHI_PROTO_UNSPEC,
- 0,
- name,
- "_adisk._tcp",
- NULL,
- NULL,
- 9, /* discard */
- strlist) < 0) {
- LOG(log_error, logtype_afpd, "Failed to add service: %s",
- avahi_strerror(avahi_client_errno(ctx->client)));
- goto fail;
- } /* if */
- } /* for config*/
-
- if (avahi_entry_group_commit(ctx->group) < 0) {
- LOG(log_error, logtype_afpd, "Failed to commit entry group: %s",
- avahi_strerror(avahi_client_errno(ctx->client)));
- goto fail;
- }
-
- } /* if avahi_entry_group_is_empty*/
-
- return;
+ for (volume = getvolumes(); volume; volume = volume->v_next) {
+
+ if (convert_string(CH_UCS2, CH_UTF8_MAC, volume->v_name, -1, tmpname, 255) <= 0) {
+ LOG ( log_error, logtype_afpd, "Could not set Zeroconf volume name for TimeMachine");
+ goto fail;
+ }
+
+ if (volume->v_flags & AFPVOL_TM) {
+ if (volume->v_uuid) {
+ LOG(log_info, logtype_afpd, "Registering volume '%s' with UUID: '%s' for TimeMachine",
+ volume->v_localname, volume->v_uuid);
+ strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1,adVU=%s",
+ i++, tmpname, volume->v_uuid);
+ } else {
+ LOG(log_warning, logtype_afpd, "Registering volume '%s' for TimeMachine. But UUID is invalid.",
+ volume->v_localname);
+ strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1",
+ i++, tmpname);
+ }
+ }
+ }
+
+ /* AFP server */
+ for (config = ctx->configs; config; config = config->next) {
+
+ dsi = (DSI *)config->obj.handle;
+ port = getip_port((struct sockaddr *)&dsi->server);
+
+ if (convert_string(config->obj.options.unixcharset, CH_UTF8,
+ config->obj.options.server ? config->obj.options.server : config->obj.options.hostname, -1,
+ name, MAXINSTANCENAMELEN) <= 0) {
+ LOG ( log_error, logtype_afpd, "Could not set Zeroconf instance name");
+ goto fail;
+ }
+
+ if (avahi_entry_group_add_service(ctx->group,
+ AVAHI_IF_UNSPEC,
+ AVAHI_PROTO_UNSPEC,
+ 0,
+ name,
+ AFP_DNS_SERVICE_TYPE,
+ NULL,
+ NULL,
+ port,
+ NULL) < 0) {
+ LOG(log_error, logtype_afpd, "Failed to add service: %s",
+ avahi_strerror(avahi_client_errno(ctx->client)));
+ goto fail;
+ }
+
+ if (i && avahi_entry_group_add_service_strlst(ctx->group,
+ AVAHI_IF_UNSPEC,
+ AVAHI_PROTO_UNSPEC,
+ 0,
+ name,
+ ADISK_SERVICE_TYPE,
+ NULL,
+ NULL,
+ 9, /* discard */
+ strlist) < 0) {
+ LOG(log_error, logtype_afpd, "Failed to add service: %s",
+ avahi_strerror(avahi_client_errno(ctx->client)));
+ goto fail;
+ } /* if */
+ } /* for config*/
+
+ if (avahi_entry_group_commit(ctx->group) < 0) {
+ LOG(log_error, logtype_afpd, "Failed to commit entry group: %s",
+ avahi_strerror(avahi_client_errno(ctx->client)));
+ goto fail;
+ }
+
+ } /* if avahi_entry_group_is_empty*/
+
+ return;
fail:
- avahi_client_free (ctx->client);
- avahi_threaded_poll_quit(ctx->threaded_poll);
+ avahi_client_free (ctx->client);
+ avahi_threaded_poll_quit(ctx->threaded_poll);
}
/* Called when publishing of service data completes */
AvahiEntryGroupState state,
AVAHI_GCC_UNUSED void *userdata)
{
- assert(ctx->group == NULL || g == ctx->group);
-
- switch (state) {
-
- case AVAHI_ENTRY_GROUP_ESTABLISHED :
- /* The entry group has been established successfully */
- LOG(log_debug, logtype_afpd, "publish_reply: AVAHI_ENTRY_GROUP_ESTABLISHED");
- break;
-
- case AVAHI_ENTRY_GROUP_COLLISION:
- /* With multiple names there's no way to know which one collided */
- LOG(log_error, logtype_afpd, "publish_reply: AVAHI_ENTRY_GROUP_COLLISION",
- avahi_strerror(avahi_client_errno(ctx->client)));
- avahi_client_free(avahi_entry_group_get_client(g));
- avahi_threaded_poll_quit(ctx->threaded_poll);
- break;
+ assert(ctx->group == NULL || g == ctx->group);
+
+ switch (state) {
+
+ case AVAHI_ENTRY_GROUP_ESTABLISHED :
+ /* The entry group has been established successfully */
+ LOG(log_debug, logtype_afpd, "publish_reply: AVAHI_ENTRY_GROUP_ESTABLISHED");
+ break;
+
+ case AVAHI_ENTRY_GROUP_COLLISION:
+ /* With multiple names there's no way to know which one collided */
+ LOG(log_error, logtype_afpd, "publish_reply: AVAHI_ENTRY_GROUP_COLLISION",
+ avahi_strerror(avahi_client_errno(ctx->client)));
+ avahi_client_free(avahi_entry_group_get_client(g));
+ avahi_threaded_poll_quit(ctx->threaded_poll);
+ break;
- case AVAHI_ENTRY_GROUP_FAILURE:
- LOG(log_error, logtype_afpd, "Failed to register service: %s",
- avahi_strerror(avahi_client_errno(ctx->client)));
- avahi_client_free(avahi_entry_group_get_client(g));
- avahi_threaded_poll_quit(ctx->threaded_poll);
- break;
-
- case AVAHI_ENTRY_GROUP_UNCOMMITED:
- break;
- case AVAHI_ENTRY_GROUP_REGISTERING:
- break;
- }
+ case AVAHI_ENTRY_GROUP_FAILURE:
+ LOG(log_error, logtype_afpd, "Failed to register service: %s",
+ avahi_strerror(avahi_client_errno(ctx->client)));
+ avahi_client_free(avahi_entry_group_get_client(g));
+ avahi_threaded_poll_quit(ctx->threaded_poll);
+ break;
+
+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
+ break;
+ case AVAHI_ENTRY_GROUP_REGISTERING:
+ break;
+ }
}
static void client_callback(AvahiClient *client,
AvahiClientState state,
void *userdata)
{
- ctx->client = client;
-
- switch (state) {
- case AVAHI_CLIENT_S_RUNNING:
- /* The server has startup successfully and registered its host
- * name on the network, so it's time to create our services */
- if (!ctx->group)
- register_stuff();
- break;
-
- case AVAHI_CLIENT_S_COLLISION:
- if (ctx->group)
- avahi_entry_group_reset(ctx->group);
- break;
-
- case AVAHI_CLIENT_FAILURE: {
- if (avahi_client_errno(client) == AVAHI_ERR_DISCONNECTED) {
- int error;
-
- avahi_client_free(ctx->client);
- ctx->client = NULL;
- ctx->group = NULL;
-
- /* Reconnect to the server */
- if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll),
- AVAHI_CLIENT_NO_FAIL,
- client_callback,
- ctx,
- &error))) {
-
- LOG(log_error, logtype_afpd, "Failed to contact server: %s",
- avahi_strerror(error));
-
- avahi_client_free (ctx->client);
- avahi_threaded_poll_quit(ctx->threaded_poll);
- }
-
- } else {
- LOG(log_error, logtype_afpd, "Client failure: %s",
- avahi_strerror(avahi_client_errno(client)));
- avahi_client_free (ctx->client);
- avahi_threaded_poll_quit(ctx->threaded_poll);
- }
- break;
- }
-
- case AVAHI_CLIENT_S_REGISTERING:
- break;
- case AVAHI_CLIENT_CONNECTING:
- break;
- }
+ ctx->client = client;
+
+ switch (state) {
+ case AVAHI_CLIENT_S_RUNNING:
+ /* The server has startup successfully and registered its host
+ * name on the network, so it's time to create our services */
+ if (!ctx->group)
+ register_stuff();
+ break;
+
+ case AVAHI_CLIENT_S_COLLISION:
+ if (ctx->group)
+ avahi_entry_group_reset(ctx->group);
+ break;
+
+ case AVAHI_CLIENT_FAILURE: {
+ if (avahi_client_errno(client) == AVAHI_ERR_DISCONNECTED) {
+ int error;
+
+ avahi_client_free(ctx->client);
+ ctx->client = NULL;
+ ctx->group = NULL;
+
+ /* Reconnect to the server */
+ if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll),
+ AVAHI_CLIENT_NO_FAIL,
+ client_callback,
+ ctx,
+ &error))) {
+
+ LOG(log_error, logtype_afpd, "Failed to contact server: %s",
+ avahi_strerror(error));
+
+ avahi_client_free (ctx->client);
+ avahi_threaded_poll_quit(ctx->threaded_poll);
+ }
+
+ } else {
+ LOG(log_error, logtype_afpd, "Client failure: %s",
+ avahi_strerror(avahi_client_errno(client)));
+ avahi_client_free (ctx->client);
+ avahi_threaded_poll_quit(ctx->threaded_poll);
+ }
+ break;
+ }
+
+ case AVAHI_CLIENT_S_REGISTERING:
+ break;
+ case AVAHI_CLIENT_CONNECTING:
+ break;
+ }
}
/************************************************************************
* neccessary config setting.
*/
void av_zeroconf_setup(const AFPConfig *configs) {
- int error, ret;
-
- /* initialize the struct that holds our config settings. */
- if (ctx) {
- LOG(log_debug, logtype_afpd, "Resetting zeroconf records");
- avahi_entry_group_reset(ctx->group);
- } else {
- ctx = calloc(1, sizeof(struct context));
- ctx->configs = configs;
- assert(ctx);
- }
+ int error, ret;
+
+ /* initialize the struct that holds our config settings. */
+ if (ctx) {
+ LOG(log_debug, logtype_afpd, "Resetting zeroconf records");
+ avahi_entry_group_reset(ctx->group);
+ } else {
+ ctx = calloc(1, sizeof(struct context));
+ ctx->configs = configs;
+ assert(ctx);
+ }
/* first of all we need to initialize our threading env */
- if (!(ctx->threaded_poll = avahi_threaded_poll_new())) {
- goto fail;
- }
+ if (!(ctx->threaded_poll = avahi_threaded_poll_new())) {
+ goto fail;
+ }
/* now we need to acquire a client */
- if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll),
- AVAHI_CLIENT_NO_FAIL,
- client_callback,
- NULL,
- &error))) {
- LOG(log_error, logtype_afpd, "Failed to create client object: %s",
- avahi_strerror(avahi_client_errno(ctx->client)));
- goto fail;
- }
-
- return;
+ if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll),
+ AVAHI_CLIENT_NO_FAIL,
+ client_callback,
+ NULL,
+ &error))) {
+ LOG(log_error, logtype_afpd, "Failed to create client object: %s",
+ avahi_strerror(avahi_client_errno(ctx->client)));
+ goto fail;
+ }
+
+ return;
fail:
- if (ctx)
- av_zeroconf_unregister();
+ if (ctx)
+ av_zeroconf_unregister();
- return;
+ return;
}
/*
* This function finally runs the loop impl.
*/
int av_zeroconf_run(void) {
- int ret;
-
- /* Finally, start the event loop thread */
- if (avahi_threaded_poll_start(ctx->threaded_poll) < 0) {
- LOG(log_error, logtype_afpd, "Failed to create thread: %s",
- avahi_strerror(avahi_client_errno(ctx->client)));
- goto fail;
- } else {
- LOG(log_info, logtype_afpd, "Successfully started avahi loop.");
- }
+ int ret;
+
+ /* Finally, start the event loop thread */
+ if (avahi_threaded_poll_start(ctx->threaded_poll) < 0) {
+ LOG(log_error, logtype_afpd, "Failed to create thread: %s",
+ avahi_strerror(avahi_client_errno(ctx->client)));
+ goto fail;
+ } else {
+ LOG(log_info, logtype_afpd, "Successfully started avahi loop.");
+ }
- ctx->thread_running = 1;
- return 0;
+ ctx->thread_running = 1;
+ return 0;
fail:
- if (ctx)
- av_zeroconf_unregister();
+ if (ctx)
+ av_zeroconf_unregister();
- return -1;
+ return -1;
}
/*
* Call this function from outside this thread.
*/
void av_zeroconf_shutdown() {
- /* Call this when the app shuts down */
- avahi_threaded_poll_stop(ctx->threaded_poll);
- avahi_client_free(ctx->client);
- avahi_threaded_poll_free(ctx->threaded_poll);
- free(ctx);
- ctx = NULL;
+ /* Call this when the app shuts down */
+ avahi_threaded_poll_stop(ctx->threaded_poll);
+ avahi_client_free(ctx->client);
+ avahi_threaded_poll_free(ctx->threaded_poll);
+ free(ctx);
+ ctx = NULL;
}
/*
* Call this function from inside this thread.
*/
int av_zeroconf_unregister() {
- if (ctx->thread_running) {
- /* First, block the event loop */
- avahi_threaded_poll_lock(ctx->threaded_poll);
+ if (ctx->thread_running) {
+ /* First, block the event loop */
+ avahi_threaded_poll_lock(ctx->threaded_poll);
- /* Than, do your stuff */
- avahi_threaded_poll_quit(ctx->threaded_poll);
+ /* Than, do your stuff */
+ avahi_threaded_poll_quit(ctx->threaded_poll);
- /* Finally, unblock the event loop */
- avahi_threaded_poll_unlock(ctx->threaded_poll);
- ctx->thread_running = 0;
- }
+ /* Finally, unblock the event loop */
+ avahi_threaded_poll_unlock(ctx->threaded_poll);
+ ctx->thread_running = 0;
+ }
- if (ctx->client)
- avahi_client_free(ctx->client);
+ if (ctx->client)
+ avahi_client_free(ctx->client);
- if (ctx->threaded_poll)
- avahi_threaded_poll_free(ctx->threaded_poll);
+ if (ctx->threaded_poll)
+ avahi_threaded_poll_free(ctx->threaded_poll);
- free(ctx);
- ctx = NULL;
+ free(ctx);
+ ctx = NULL;
- return 0;
+ return 0;
}
#endif /* USE_AVAHI */
#include "afp_config.h"
#define AFP_DNS_SERVICE_TYPE "_afpovertcp._tcp"
+#define ADISK_SERVICE_TYPE "_adisk._tcp"
+
+#define MAXINSTANCENAMELEN 63
struct context {
/* Avahi stuff */
/* this is the enum specifying all availiable logtypes */
enum logtypes {
logtype_default,
- logtype_core,
logtype_logger,
logtype_cnid,
logtype_afpd,
+ logtype_dsi,
logtype_atalkd,
logtype_papd,
logtype_uams,
- logtype_console,
logtype_end_of_list_marker /* don't put any logtypes after this */
};
switch (pid = dsi->proto_open(dsi)) {
case -1:
/* if we fail, just return. it might work later */
- LOG(log_error, logtype_default, "dsi_getsess: %s", strerror(errno));
+ LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
return dsi;
case 0: /* child. mostly handled below. */
/* using SIGQUIT is hokey, but the child might not have
* re-established its signal handler for SIGTERM yet. */
if (server_child_add(children, CHILD_DSIFORK, pid) < 0) {
- LOG(log_error, logtype_default, "dsi_getsess: %s", strerror(errno));
+ LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
dsi->header.dsi_flags = DSIFL_REPLY;
dsi->header.dsi_code = DSIERR_SERVBUSY;
dsi_send(dsi);
* actual count. */
if ((children->count >= children->nsessions) &&
(dsi->header.dsi_command == DSIFUNC_OPEN)) {
- LOG(log_info, logtype_default, "dsi_getsess: too many connections");
+ LOG(log_info, logtype_dsi, "dsi_getsess: too many connections");
dsi->header.dsi_flags = DSIFL_REPLY;
dsi->header.dsi_code = DSIERR_TOOMANY;
dsi_send(dsi);
break;
default: /* just close */
- LOG(log_info, logtype_default, "DSIUnknown %d", dsi->header.dsi_command);
+ LOG(log_info, logtype_dsi, "DSIUnknown %d", dsi->header.dsi_command);
dsi->proto_close(dsi);
exit(EXITERR_CLNT);
}
int len;
int maxfd;
+ LOG(log_maxdebug, logtype_dsi, "dsi_buffer: switching to non-blocking IO");
+
/* non blocking mode */
if (setnonblock(dsi->socket, 1) < 0) {
/* can't do it! exit without error it will sleep to death below */
- LOG(log_error, logtype_default, "dsi_buffer: ioctl non blocking mode %s", strerror(errno));
+ LOG(log_error, logtype_dsi, "dsi_buffer: ioctl non blocking mode %s", strerror(errno));
return 0;
}
break;
}
}
+
+ LOG(log_maxdebug, logtype_dsi, "dsi_buffer: switching back to blocking IO");
+
if (setnonblock(dsi->socket, 0) < 0) {
/* can't do it! afpd will fail very quickly */
- LOG(log_error, logtype_default, "dsi_buffer: ioctl blocking mode %s", strerror(errno));
+ LOG(log_error, logtype_dsi, "dsi_buffer: ioctl blocking mode %s", strerror(errno));
return -1;
}
return 0;
dsi->in_write++;
written = 0;
+
+ LOG(log_maxdebug, logtype_dsi, "dsi_stream_write: sending %u bytes", length);
+
while (written < length) {
- if ((-1 == (len = send(dsi->socket, (u_int8_t *) data + written,
- length - written, flags)) && errno == EINTR) ||
- !len)
- continue;
+ len = send(dsi->socket, (u_int8_t *) data + written, length - written, flags);
+ if ((len == 0) || (len == -1 && errno == EINTR))
+ continue;
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
if (mode == DSI_NOWAIT && written == 0) {
- /* DSI_NOWAIT is used by attention
- give up in this case.
- */
+ /* DSI_NOWAIT is used by attention give up in this case. */
return -1;
}
if (dsi_buffer(dsi)) {
}
continue;
}
- LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
+ LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
break;
}
else {
}
continue;
}
- LOG(log_error, logtype_default, "dsi_stream_write: %s", strerror(errno));
+ LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno));
break;
}
else if (!len) {
}
#endif
-/* ---------------------------------
-*/
+/*
+ * Return all bytes up to count from dsi->buffer if there are any buffered there
+ */
static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count)
{
size_t nbe = 0;
return nbe;
}
+/*
+ * Get bytes from buffer dsi->buffer or read from socket
+ *
+ * 1. Check if there are bytes in the the dsi->buffer buffer.
+ * 2. Return bytes from (1) if yes.
+ * Note: this may return fewer bytes then requested in count !!
+ * 3. If the buffer was empty, read from the socket.
+ */
static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
{
ssize_t nbe;
if (!count)
return 0;
- nbe = from_buf(dsi, buf, count);
+ nbe = from_buf(dsi, buf, count); /* 1. */
if (nbe)
- return nbe;
+ return nbe; /* 2. */
- return read(dsi->socket, buf, count);
-
+ return read(dsi->socket, buf, count); /* 3. */
}
-/* ---------------------------------------
- * read raw data. return actual bytes read. this will wait until
- * it gets length bytes
+/*
+ * Essentially a loop around buf_read() to ensure "length" bytes are read
+ * from dsi->buffer and/or the socket.
*/
size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
{
else { /* eof or error */
/* don't log EOF error if it's just after connect (OSX 10.3 probe) */
if (len || stored || dsi->read_count) {
- LOG(log_error, logtype_default, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
+ LOG(log_error, logtype_dsi, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
}
break;
}
return stored;
}
-/* ---------------------------------------
- * read raw data. return actual bytes read. this will wait until
- * it gets length bytes
+/*
+ * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
+ * this tries to read larger chunks (8192 bytes) into a buffer.
*/
static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
{
size_t buflen;
dsi_init_buffer(dsi);
- len = from_buf(dsi, data, length);
+ len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
dsi->read_count += len;
- if (len == length) {
- return len;
+ if (len == length) { /* got enough bytes from there ? */
+ return len; /* yes */
}
-
+
+ /* fill the buffer with 8192 bytes or until buffer is full */
buflen = min(8192, dsi->end - dsi->eof);
if (buflen > 0) {
ssize_t ret;
if (ret > 0)
dsi->eof += ret;
}
- return dsi_stream_read(dsi, data, length -len);
+
+ /* now get the remaining data */
+ len += dsi_stream_read(dsi, data + len, length - len);
+ return len;
}
/* ---------------------------------------
continue;
}
}
- LOG(log_error, logtype_default, "dsi_stream_send: %s", strerror(errno));
+ LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno));
unblock_sig(dsi);
return 0;
}
but we get a server disconnect without reason in the log
*/
if (!block[1]) {
- LOG(log_error, logtype_default, "dsi_stream_receive: invalid packet, fatal");
+ LOG(log_error, logtype_dsi, "dsi_stream_receive: invalid packet, fatal");
return 0;
}
* we have to test for EINTR
*/
if (setsockopt(dsi->socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
- LOG(log_error, logtype_default, "dsi_tcp_open: unable to set timeout %s", strerror(errno));
+ LOG(log_error, logtype_dsi, "dsi_tcp_open: unable to set timeout %s", strerror(errno));
exit(EXITERR_CLNT);
}
}
/* alarm handler for tcp_open */
static void timeout_handler(int sig _U_)
{
- LOG(log_error, logtype_default, "dsi_tcp_open: connection timed out");
+ LOG(log_error, logtype_dsi, "dsi_tcp_open: connection timed out");
exit(EXITERR_CLNT);
}
request_init(&req, RQ_DAEMON, dsi->program, RQ_FILE, dsi->socket, NULL);
fromhost(&req);
if (!hosts_access(&req)) {
- LOG(deny_severity, logtype_default, "refused connect from %s", eval_client(&req));
+ LOG(deny_severity, logtype_dsi, "refused connect from %s", eval_client(&req));
close(dsi->socket);
errno = ECONNREFUSED;
dsi->socket = -1;
if ((sigaction(SIGALRM, &newact, &oldact) < 0) ||
(setitimer(ITIMER_REAL, &timer, NULL) < 0)) {
- LOG(log_error, logtype_default, "dsi_tcp_open: %s", strerror(errno));
+ LOG(log_error, logtype_dsi, "dsi_tcp_open: %s", strerror(errno));
exit(EXITERR_SYS);
}
#endif
exit(EXITERR_CLNT);
}
if (len < 2 || (block[0] > DSIFL_MAX) || (block[1] > DSIFUNC_MAX)) {
- LOG(log_error, logtype_default, "dsi_tcp_open: invalid header");
+ LOG(log_error, logtype_dsi, "dsi_tcp_open: invalid header");
exit(EXITERR_CLNT);
}
if (len > 0)
stored += len;
else {
- LOG(log_error, logtype_default, "dsi_tcp_open: stream_read: %s", strerror(errno));
+ LOG(log_error, logtype_dsi, "dsi_tcp_open: stream_read: %s", strerror(errno));
exit(EXITERR_CLNT);
}
}
if (len > 0)
stored += len;
else {
- LOG(log_error, logtype_default, "dsi_tcp_open: stream_read: %s", strerror(errno));
+ LOG(log_error, logtype_dsi, "dsi_tcp_open: stream_read: %s", strerror(errno));
exit(EXITERR_CLNT);
}
}
dsi_tcp_timeout(dsi);
- LOG(log_info, logtype_default, "AFP/TCP session from %s:%u",
+ LOG(log_info, logtype_dsi, "AFP/TCP session from %s:%u",
getip_string((struct sockaddr *)&dsi->client),
getip_port((struct sockaddr *)&dsi->client));
}
#define IFF_SLAVE 0
#endif
-static void guess_interface(DSI *dsi, const char *hostname)
+static void guess_interface(DSI *dsi, const char *hostname, const char *port)
{
int fd;
char **start, **list;
memset(&dsi->server, 0, sizeof(struct sockaddr_storage));
sa->sin_family = AF_INET;
- sa->sin_port = htons(548);
+ sa->sin_port = htons(atoi(port));
sa->sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
- LOG(log_info, logtype_default, "dsi_tcp: '%s' on interface '%s' will be used instead.",
- getip_string((struct sockaddr *)&dsi->server), ifr.ifr_name);
+ LOG(log_info, logtype_dsi, "dsi_tcp: '%s:%s' on interface '%s' will be used instead.",
+ getip_string((struct sockaddr *)&dsi->server), port, ifr.ifr_name);
goto iflist_done;
}
- LOG(log_info, logtype_default, "dsi_tcp (Chooser will not select afp/tcp) "
+ LOG(log_info, logtype_dsi, "dsi_tcp (Chooser will not select afp/tcp) "
"Check to make sure %s is in /etc/hosts and the correct domain is in "
"/etc/resolv.conf: %s", hostname, strerror(errno));
hints.ai_flags |= AI_NUMERICHOST;
if ((ret = getaddrinfo(address ? address : NULL, port ? port : "548", &hints, &servinfo)) != 0) {
- LOG(log_error, logtype_default, "dsi_tcp_init: getaddrinfo: %s\n", gai_strerror(ret));
+ LOG(log_error, logtype_dsi, "dsi_tcp_init: getaddrinfo: %s\n", gai_strerror(ret));
return 0;
}
/* loop through all the results and bind to the first we can */
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((dsi->serversock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
- LOG(log_info, logtype_default, "dsi_tcp_init: socket: %s", strerror(errno));
+ LOG(log_info, logtype_dsi, "dsi_tcp_init: socket: %s", strerror(errno));
continue;
}
if (bind(dsi->serversock, p->ai_addr, p->ai_addrlen) == -1) {
close(dsi->serversock);
- LOG(log_info, logtype_default, "dsi_tcp_init: bind: %s\n", strerror(errno));
+ LOG(log_info, logtype_dsi, "dsi_tcp_init: bind: %s\n", strerror(errno));
continue;
}
if (listen(dsi->serversock, DSI_TCPMAXPEND) < 0) {
close(dsi->serversock);
- LOG(log_info, logtype_default, "dsi_tcp_init: listen: %s\n", strerror(errno));
+ LOG(log_info, logtype_dsi, "dsi_tcp_init: listen: %s\n", strerror(errno));
continue;
}
}
if (p == NULL) {
- LOG(log_error, logtype_default, "dsi_tcp_init: no suitable network config for TCP socket");
+ LOG(log_error, logtype_dsi, "dsi_tcp_init: no suitable network config for TCP socket");
freeaddrinfo(servinfo);
return 0;
}
hints.ai_socktype = SOCK_STREAM;
if ((ret = getaddrinfo(hostname, port ? port : "548", &hints, &servinfo)) != 0) {
- LOG(log_info, logtype_default, "dsi_tcp_init: getaddrinfo '%s': %s\n", hostname, gai_strerror(ret));
+ LOG(log_info, logtype_dsi, "dsi_tcp_init: getaddrinfo '%s': %s\n", hostname, gai_strerror(ret));
goto interfaces;
}
freeaddrinfo(servinfo);
return 1;
}
- LOG(log_info, logtype_default, "dsi_tcp: hostname '%s' resolves to loopback address", hostname);
+ LOG(log_info, logtype_dsi, "dsi_tcp: hostname '%s' resolves to loopback address", hostname);
freeaddrinfo(servinfo);
interfaces:
- guess_interface(dsi, hostname);
+ guess_interface(dsi, hostname, port ? port : "548");
return 1;
}
/* these are the string identifiers corresponding to each logtype */
#define LOGTYPE_STRING_IDENTIFIERS { \
"Default", \
- "Core", \
"Logger", \
"CNID", \
"AFPDaemon", \
+ "DSI", \
"ATalkDaemon", \
"PAPDaemon", \
- "UAMSDaemon", \
- "Console", \
+ "UAMS", \
"end_of_list_marker"} \
/* =========================================================================
0: set ?
0: syslog ?
-1: logfiles fd
- log_maxdebug: force first LOG call to call make_log_entry which
- then calls log_init because "inited" is still 0
+ log_none: no logging by default
0: Display options */
-#define DEFAULT_LOG_CONFIG {0, 0, -1, log_maxdebug, 0}
+#define DEFAULT_LOG_CONFIG {0, 0, -1, log_none, 0}
UAM_MODULE_EXPORT logtype_conf_t type_configs[logtype_end_of_list_marker] = {
DEFAULT_LOG_CONFIG, /* logtype_default */
- DEFAULT_LOG_CONFIG, /* logtype_core */
DEFAULT_LOG_CONFIG, /* logtype_logger */
DEFAULT_LOG_CONFIG, /* logtype_cnid */
DEFAULT_LOG_CONFIG, /* logtype_afpd */
+ DEFAULT_LOG_CONFIG, /* logtype_dsi */
DEFAULT_LOG_CONFIG, /* logtype_atalkd */
DEFAULT_LOG_CONFIG, /* logtype_papd */
- DEFAULT_LOG_CONFIG, /* logtype_uams */
- DEFAULT_LOG_CONFIG /* logtype_console */
+ DEFAULT_LOG_CONFIG /* logtype_uams */
};
/* These are used by the LOG macro to store __FILE__ and __LINE__ */
}
}
- /* Check if logging to a console */
- if (logtype == logtype_console) {
- log_config.console = 1;
- logtype = logtype_default;
- }
-
/* Set new values */
type_configs[logtype].level = loglevel;
process_uid = geteuid();
if (process_uid) {
if (seteuid(OPEN_LOGS_AS_UID) == -1) {
- /* XXX failing silently */
- return;
+ process_uid = 0;
}
}
type_configs[logtype].fd = open(filename,
unsetuplog("Default");
#endif
/* filelog testing */
- setuplog("Default LOG_INFO test.log");
- LOG(log_info, logtype_logger, "This should log.");
- LOG(log_info, logtype_default, "This should log.");
- LOG(log_error, logtype_logger, "This should log.");
- LOG(log_error, logtype_default, "This should log.");
- LOG(log_debug, logtype_logger, "This should not log.");
- LOG(log_debug, logtype_default, "This should not log.");
-
- LOG(log_severe, logtype_logger, "Logging Test finishing");
+
+ setuplog("DSI log_maxdebug test.log");
+ LOG(log_info, logtype_dsi, "This should log.");
+ LOG(log_error, logtype_default, "This should not log.");
+
+ setuplog("Default log_debug test.log");
+ LOG(log_debug, logtype_default, "This should log.");
+ LOG(log_maxdebug, logtype_default, "This should not log.");
+
+ LOG(log_maxdebug, logtype_dsi, "This should still log.");
return 0;
}