#include "gnunet_transport_plugin.h"
#include "transport.h"
-#define DEBUG_UNIX GNUNET_YES
+#define DEBUG_UNIX GNUNET_NO
+#define DETAILS GNUNET_NO
#define MAX_PROBES 20
};
+struct RetryList
+{
+ /**
+ * Pointer to next element.
+ */
+ struct RetryList *next;
+
+ /**
+ * Pointer to previous element.
+ */
+ struct RetryList *prev;
+
+ /**
+ * The actual retry context.
+ */
+ struct RetrySendContext *retry_ctx;
+};
+
/**
* Network format for IPv4 addresses.
*/
* The priority of the message.
*/
unsigned int priority;
-};
-
-/**
- * Local network addresses (actual unix path follows).
- */
-struct LocalAddrList
-{
-
- /**
- * This is a doubly linked list.
- */
- struct LocalAddrList *next;
/**
- * This is a doubly linked list.
+ * Entry in the DLL of retry items.
*/
- struct LocalAddrList *prev;
-
- /**
- * Number of bytes of the address that follow
- */
- size_t size;
-
+ struct RetryList *retry_list_entry;
};
*/
uint16_t port;
- /**
- * List of our IP addresses.
- */
- struct LocalAddrList *lal_head;
-
- /**
- * Tail of our IP address list.
- */
- struct LocalAddrList *lal_tail;
-
/**
* FD Read set
*/
};
+/**
+ * Head of retry DLL.
+ */
+static struct RetryList *retry_list_head;
+
+/**
+ * Tail of retry DLL.
+ */
+static struct RetryList *retry_list_tail;
+
/**
* Disconnect from a remote node. Clean up session if we have one for this peer
unix_transport_server_stop (void *cls)
{
struct Plugin *plugin = cls;
+ struct RetryList *pos;
+
+ pos = retry_list_head;
+
+ while(NULL != (pos = retry_list_head))
+ {
+ GNUNET_CONTAINER_DLL_remove(retry_list_head, retry_list_tail, pos);
+ if (GNUNET_SCHEDULER_NO_TASK != pos->retry_ctx->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel(pos->retry_ctx->retry_task);
+ }
+ GNUNET_free(pos->retry_ctx->msg);
+ GNUNET_free(pos->retry_ctx->addr);
+ GNUNET_free(pos->retry_ctx);
+ GNUNET_free(pos);
+ }
if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
{
{
struct RetrySendContext *retry_ctx = cls;
- if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
- return;
+ if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ {
+ GNUNET_free(retry_ctx->msg);
+ GNUNET_free(retry_ctx->addr);
+ GNUNET_free(retry_ctx);
+ return;
+ }
+
unix_real_send (retry_ctx->plugin,
retry_ctx,
retry_ctx->send_handle,
ssize_t sent;
const void *sb;
size_t sbs;
- struct sockaddr_un *un;
+ struct sockaddr_un un;
size_t slen;
+ struct RetryList *retry_list_entry;
+ int retry;
if (send_handle == NULL)
{
sizeof (struct GNUNET_PeerIdentity));
memcpy (&message[1], msgbuf, msgbuf_size);
- un = GNUNET_malloc (sizeof (struct sockaddr_un));
- un->sun_family = AF_UNIX;
+ memset(&un, 0, sizeof(un));
+ un.sun_family = AF_UNIX;
slen = strlen (addr) + 1;
+ if (slen >= sizeof (un.sun_path))
+ slen = sizeof (un.sun_path) - 1;
sent = 0;
- GNUNET_assert(slen < sizeof(un->sun_path));
- memcpy (un->sun_path, addr, slen);
- un->sun_path[slen] = '\0';
+ GNUNET_assert(slen < sizeof(un.sun_path));
+ memcpy (un.sun_path, addr, slen);
+ un.sun_path[slen] = '\0';
+ slen = sizeof (struct sockaddr_un);
#if LINUX
- un->sun_path[0] = '\0';
+ un.sun_path[0] = '\0';
#endif
- slen += sizeof (sa_family_t);
- sb = (struct sockaddr*) un;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ un.sun_len = (u_char) slen;
+#endif
+ sb = (struct sockaddr*) &un;
sbs = slen;
+ retry = GNUNET_NO;
sent = GNUNET_NETWORK_socket_sendto(send_handle, message, ssize, sb, sbs);
- if (GNUNET_SYSERR == sent)
+ if ((GNUNET_SYSERR == sent) && (errno == EAGAIN))
+ retry = GNUNET_YES;
+
+ if ((GNUNET_SYSERR == sent) && (errno == EMSGSIZE))
+ {
+ socklen_t size = 0;
+ socklen_t len = sizeof (size);
+ GNUNET_NETWORK_socket_getsockopt ((struct GNUNET_NETWORK_Handle * ) send_handle,
+ SOL_SOCKET,
+ SO_SNDBUF,
+ &size, &len);
+
+ if (size < ssize)
+ {
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Trying to increase socket buffer size from %i to %i for message size %i\n",
+ size,
+ ((ssize / 1000) + 2) * 1000, ssize);
+#endif
+ size = ((ssize / 1000) + 2) * 1000;
+ if (GNUNET_NETWORK_socket_setsockopt ((struct GNUNET_NETWORK_Handle * ) send_handle,
+ SOL_SOCKET,
+ SO_SNDBUF,
+ &size, sizeof(size)) == GNUNET_OK)
+ retry = GNUNET_YES;
+ else
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
+ }
+ }
+
+ if (retry == GNUNET_YES)
{
if (incoming_retry_context == NULL)
{
+ retry_list_entry = GNUNET_malloc(sizeof(struct RetryList));
retry_ctx = GNUNET_malloc(sizeof(struct RetrySendContext));
retry_ctx->addr = GNUNET_malloc(addrlen);
retry_ctx->msg = GNUNET_malloc(msgbuf_size);
retry_ctx->timeout = GNUNET_TIME_relative_to_absolute(timeout);
memcpy(&retry_ctx->target, target, sizeof(struct GNUNET_PeerIdentity));
retry_ctx->delay = GNUNET_TIME_UNIT_MILLISECONDS;
+ retry_ctx->retry_list_entry = retry_list_entry;
+ retry_list_entry->retry_ctx = retry_ctx;
+ GNUNET_CONTAINER_DLL_insert(retry_list_head, retry_list_tail, retry_list_entry);
}
else
{
retry_ctx->delay = GNUNET_TIME_relative_multiply(retry_ctx->delay, 2);
}
retry_ctx->retry_task = GNUNET_SCHEDULER_add_delayed(retry_ctx->delay, &retry_send_message, retry_ctx);
-#if DETAILS
- GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Error when trying to send %d byte message to %s\n", retry_ctx->msg_size, &un->sun_path[1]);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "UNIX transmit %u-byte message to %s (%d: %s)\n",
- (unsigned int) ssize,
- GNUNET_a2s (sb, sbs),
- (int) sent,
- (sent < 0) ? STRERROR (errno) : "ok");
-#endif
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
+
+ //GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
+ GNUNET_free(message);
return ssize;
}
- if (incoming_retry_context != NULL)
- {
- GNUNET_free(incoming_retry_context->msg);
- GNUNET_free(incoming_retry_context->addr);
- GNUNET_free(incoming_retry_context);
- }
#if DEBUG_UNIX
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"UNIX transmit %u-byte message to %s (%d: %s)\n",
}
}
+ if (incoming_retry_context != NULL)
+ {
+ GNUNET_CONTAINER_DLL_remove(retry_list_head, retry_list_tail, incoming_retry_context->retry_list_entry);
+ GNUNET_free(incoming_retry_context->retry_list_entry);
+ GNUNET_free(incoming_retry_context->msg);
+ GNUNET_free(incoming_retry_context->addr);
+ GNUNET_free(incoming_retry_context);
+ }
+
GNUNET_free (message);
return sent;
}
}
-static void
-add_to_address_list (struct Plugin *plugin,
- const void *arg,
- size_t arg_size)
-{
- struct LocalAddrList *lal;
-
- lal = plugin->lal_head;
- while (NULL != lal)
- {
- if ( (lal->size == arg_size) &&
- (0 == memcmp (&lal[1], arg, arg_size)) )
- return;
- lal = lal->next;
- }
- lal = GNUNET_malloc (sizeof (struct LocalAddrList) + arg_size);
- lal->size = arg_size;
- memcpy (&lal[1], arg, arg_size);
- GNUNET_CONTAINER_DLL_insert (plugin->lal_head,
- plugin->lal_tail,
- lal);
-}
-
-
/**
* Demultiplexer for UNIX messages
*
* @param plugin the main plugin for this transport
* @param sender from which peer the message was received
* @param currhdr pointer to the header of the message
- * @param sender_addr the address from which the message was received
+ * @param un the address from which the message was received
* @param fromlen the length of the address
*/
static void
char buf[65536];
struct UNIXMessage *msg;
struct GNUNET_PeerIdentity sender;
- //socklen_t fromlen;
struct sockaddr_un un;
socklen_t addrlen;
ssize_t ret;
uint16_t csize;
plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
- if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+ if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
return;
addrlen = sizeof(un);
unix_transport_server_start (void *cls)
{
struct Plugin *plugin = cls;
-
struct sockaddr *serverAddr;
socklen_t addrlen;
- int sockets_created;
- struct sockaddr_un *un;
+ struct sockaddr_un un;
size_t slen;
- un = GNUNET_malloc (sizeof (struct sockaddr_un));
- un->sun_family = AF_UNIX;
+ memset(&un, 0, sizeof(un));
+ un.sun_family = AF_UNIX;
slen = strlen (plugin->unix_socket_path) + 1;
+ if (slen >= sizeof (un.sun_path))
+ slen = sizeof (un.sun_path) - 1;
+
+ memcpy (un.sun_path, plugin->unix_socket_path, slen);
+ un.sun_path[slen] = '\0';
+ slen = sizeof (struct sockaddr_un);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ un.sun_len = (u_char) slen;
+#endif
- GNUNET_assert(slen < sizeof(un->sun_path));
- memcpy (un->sun_path, plugin->unix_socket_path, slen);
- un->sun_path[slen] = '\0';
- slen += sizeof (sa_family_t);
- serverAddr = (struct sockaddr*) un;
+ serverAddr = (struct sockaddr*) &un;
addrlen = slen;
- sockets_created = 0;
#if LINUX
- un->sun_path[0] = '\0';
+ un.sun_path[0] = '\0';
#endif
plugin->unix_sock.desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
if (NULL == plugin->unix_sock.desc)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "socket");
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
+ return GNUNET_SYSERR;
}
- else
+ if (GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, serverAddr, addrlen) !=
+ GNUNET_OK)
{
- if (GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, serverAddr, addrlen) !=
- GNUNET_OK)
- {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
+ GNUNET_NETWORK_socket_close (plugin->unix_sock.desc);
+ plugin->unix_sock.desc = NULL;
+ return GNUNET_SYSERR;
+ }
#if DEBUG_UNIX
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "UNIX Binding failed!\n");
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "unix",
+ "Bound to `%s'\n",
+ &un.sun_path[0]);
#endif
- }
- else
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Bound to `%s'\n", &un->sun_path[0]);
- if (plugin->unix_sock.desc != NULL)
- sockets_created++;
- }
-
plugin->rs = GNUNET_NETWORK_fdset_create ();
GNUNET_NETWORK_fdset_zero (plugin->rs);
GNUNET_NETWORK_fdset_set (plugin->rs,
GNUNET_SCHEDULER_NO_TASK,
GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
NULL, &unix_plugin_select, plugin);
- return sockets_created;
+ return 1;
}
GNUNET_TRANSPORT_AddressStringCallback asc,
void *asc_cls)
{
- struct Plugin *plugin = cls;
struct PrettyPrinterContext *ppc;
const void *sb;
size_t sbs;
ppc->asc = asc;
ppc->asc_cls = asc_cls;
ppc->port = port;
- GNUNET_RESOLVER_hostname_get (plugin->env->cfg,
- sb,
+ GNUNET_RESOLVER_hostname_get (sb,
sbs,
!numeric, timeout, &append_port, ppc);
}
const void *addr,
size_t addrlen)
{
- static char rbuf[INET6_ADDRSTRLEN + 10];
- char buf[INET6_ADDRSTRLEN];
- const void *sb;
- struct in_addr a4;
- struct in6_addr a6;
- const struct IPv4UdpAddress *t4;
- const struct IPv6UdpAddress *t6;
- int af;
- uint16_t port;
-
- if (addrlen == sizeof (struct IPv6UdpAddress))
- {
- t6 = addr;
- af = AF_INET6;
- port = ntohs (t6->u6_port);
- memcpy (&a6, &t6->ipv6_addr, sizeof (a6));
- sb = &a6;
- }
- else if (addrlen == sizeof (struct IPv4UdpAddress))
- {
- t4 = addr;
- af = AF_INET;
- port = ntohs (t4->u_port);
- memcpy (&a4, &t4->ipv4_addr, sizeof (a4));
- sb = &a4;
- }
+ if ((addr != NULL) && (addrlen > 0))
+ return (const char *) addr;
else
return NULL;
- inet_ntop (af, sb, buf, INET6_ADDRSTRLEN);
- GNUNET_snprintf (rbuf,
- sizeof (rbuf),
- "%s:%u",
- buf,
- port);
- return rbuf;
+}
+
+/**
+ * Notify transport service about address
+ *
+ * @param cls the plugin
+ * @param tc unused
+ */
+static void
+address_notification (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+ plugin->env->notify_address(plugin->env->cls,
+ GNUNET_YES,
+ plugin->unix_socket_path,
+ strlen(plugin->unix_socket_path) + 1);
}
/**
"PORT",
&port))
port = UNIX_NAT_DEFAULT_PORT;
- else if (port > 65535)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Given `%s' option is out of range: %llu > %u\n"),
- "PORT",
- port,
- 65535);
- return NULL;
- }
-
-
plugin = GNUNET_malloc (sizeof (struct Plugin));
plugin->port = port;
plugin->env = env;
- GNUNET_asprintf(&plugin->unix_socket_path, "/tmp/unix-plugin-sock.%d", plugin->port);
-
+ GNUNET_asprintf (&plugin->unix_socket_path,
+ "/tmp/unix-plugin-sock.%d",
+ plugin->port);
+
api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
api->cls = plugin;
api->address_pretty_printer = &unix_plugin_address_pretty_printer;
api->address_to_string = &unix_address_to_string;
api->check_address = &unix_check_address;
-
- add_to_address_list (plugin, plugin->unix_socket_path, strlen(plugin->unix_socket_path) + 1);
-
sockets_created = unix_transport_server_start (plugin);
if (sockets_created == 0)
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_("Failed to open UNIX sockets\n"));
- plugin->env->notify_address(plugin->env->cls,
- "unix",
- plugin->unix_socket_path,
- strlen(plugin->unix_socket_path) + 1,
- GNUNET_TIME_UNIT_FOREVER_REL);
+ GNUNET_SCHEDULER_add_now(address_notification, plugin);
return api;
}
{
struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
struct Plugin *plugin = api->cls;
- struct LocalAddrList *lal;
unix_transport_server_stop (plugin);
GNUNET_NETWORK_fdset_destroy (plugin->rs);
- while (NULL != (lal = plugin->lal_head))
- {
- GNUNET_CONTAINER_DLL_remove (plugin->lal_head,
- plugin->lal_tail,
- lal);
- GNUNET_free (lal);
- }
+ GNUNET_free (plugin->unix_socket_path);
GNUNET_free (plugin);
GNUNET_free (api);
return NULL;