endif
if LINUX
+UNIX_PLUGIN_LA = libgnunet_plugin_transport_unix.la
+UNIX_PLUGIN_TEST = test_transport_api_unix
+UNIX_REL_TEST = test_transport_api_unreliability_unix
+UNIX_QUOTA_TEST = test_quota_compliance_unix
NATBIN = gnunet-nat-server gnunet-nat-client
install-exec-hook:
chown root $(bindir)/gnunet-nat-server $(bindir)/gnunet-nat-client $(bindir)/gnunet-wlan || true
plugin_LTLIBRARIES = \
libgnunet_plugin_transport_tcp.la \
libgnunet_plugin_transport_udp.la \
+ $(UNIX_PLUGIN_LA) \
$(HTTP_PLUGIN_LA) \
$(HTTPS_PLUGIN_LA) \
$(WLAN_PLUGIN_LA) \
$(top_builddir)/src/util/libgnunetutil.la
libgnunet_plugin_transport_udp_la_LDFLAGS = \
$(GN_PLUGIN_LDFLAGS)
-
-#libgnunet_plugin_transport_udp_nat_la_SOURCES = \
-# plugin_transport_udp_nat.c
-#libgnunet_plugin_transport_udp_nat_la_LIBADD = \
-# $(top_builddir)/src/hello/libgnunethello.la \
-# $(top_builddir)/src/statistics/libgnunetstatistics.la \
-# $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
-# $(top_builddir)/src/util/libgnunetutil.la
-#libgnunet_plugin_transport_udp_nat_la_LDFLAGS = \
-# $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_unix_la_SOURCES = \
+ plugin_transport_unix.c
+libgnunet_plugin_transport_unix_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+libgnunet_plugin_transport_unix_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
libgnunet_plugin_transport_http_la_SOURCES = \
plugin_transport_http.c
test_transport_api_tcp \
test_transport_api_tcp_nat \
test_transport_api_udp \
+ $(UNIX_PLUGIN_TEST) \
test_transport_api_udp_nat \
$(HTTP_PLUGIN_TEST) \
$(HTTP_API_TEST) \
test_transport_api_multi \
test_transport_api_reliability_tcp \
test_transport_api_reliability_tcp_nat \
- test_transport_api_reliability_udp \
+ test_transport_api_unreliability_udp \
+ test_transport_api_unreliability_unix \
+ $(UNIX_REL_TEST) \
$(HTTP_REL_TEST) \
$(HTTPS_REL_TEST) \
test_quota_compliance_tcp \
test_quota_compliance_tcp_asymmetric_recv_constant \
test_quota_compliance_udp \
test_quota_compliance_udp_asymmetric_recv_constant \
+ $(UNIX_QUOTA_TEST) \
$(HTTP_QUOTA_TEST) \
$(HTTPS_QUOTA_TEST)
# TODO: add tests for nat, etc.
test_transport_api_tcp \
test_transport_api_tcp_nat \
test_transport_api_udp \
+ $(UNIX_PLUGIN_TEST) \
test_transport_api_udp_nat \
$(HTTP_PLUGIN_TEST) \
$(HTTP_API_TEST) \
test_transport_api_multi \
test_transport_api_reliability_tcp \
test_transport_api_reliability_tcp_nat \
+ test_transport_api_unreliability_udp \
+ test_transport_api_unreliability_unix \
$(HTTP_REL_TEST) \
$(HTTPS_REL_TEST) \
test_quota_compliance_tcp \
test_quota_compliance_tcp_asymmetric_recv_constant \
test_quota_compliance_udp \
test_quota_compliance_udp_asymmetric_recv_constant \
+ $(UNIX_QUOTA_TEST) \
$(HTTP_QUOTA_TEST) \
$(HTTPS_QUOTA_TEST)
endif
test_transport_api_reliability.c
test_transport_api_reliability_udp_LDADD = \
$(top_builddir)/src/transport/libgnunettransport.la \
- $(top_builddir)/src/util/libgnunetutil.la
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_transport_api_reliability_unix_SOURCES = \
+ test_transport_api_reliability.c
+test_transport_api_reliability_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
test_transport_api_udp_SOURCES = \
test_transport_api.c
test_transport_api_udp_LDADD = \
$(top_builddir)/src/transport/libgnunettransport.la \
$(top_builddir)/src/util/libgnunetutil.la
-
+
test_transport_api_udp_nat_SOURCES = \
test_transport_api.c
test_transport_api_udp_nat_LDADD = \
$(top_builddir)/src/transport/libgnunettransport.la \
- $(top_builddir)/src/util/libgnunetutil.la
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_transport_api_unix_SOURCES = \
+ test_transport_api.c
+test_transport_api_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
test_plugin_transport_http_SOURCES = \
test_plugin_transport_http.c
test_transport_api_reliability_https_LDADD = \
$(top_builddir)/src/transport/libgnunettransport.la \
$(top_builddir)/src/util/libgnunetutil.la
+
+test_transport_api_unreliability_unix_SOURCES = \
+ test_transport_api_unreliability.c
+test_transport_api_unreliability_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_transport_api_unreliability_udp_SOURCES = \
+ test_transport_api_unreliability.c
+test_transport_api_unreliability_udp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
if HAVE_PCAP
if LINUX
# $(top_builddir)/src/transport/libgnunettransport.la \
# $(top_builddir)/src/util/libgnunetutil.la
+test_quota_compliance_unix_SOURCES = \
+ test_quota_compliance.c
+test_quota_compliance_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_quota_compliance_unix_asymmetric_recv_constant_SOURCES = \
+ test_quota_compliance.c
+test_quota_compliance_unix_asymmetric_recv_constant_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+
test_transport_api_multi_SOURCES = \
test_transport_api.c
test_transport_api_multi_LDADD = \
test_transport_api_tcp_peer2.conf \
test_transport_api_udp_peer1.conf \
test_transport_api_udp_peer2.conf \
+ test_transport_api_unix_peer1.conf \
+ test_transport_api_unix_peer2.conf \
test_transport_api_udp_nat_peer1.conf \
test_transport_api_udp_nat_peer2.conf \
test_transport_api_tcp_nat_peer1.conf \
test_quota_compliance_https_peer1.conf \
test_quota_compliance_https_peer2.conf \
test_quota_compliance_udp_peer1.conf \
- test_quota_compliance_udp_peer2.conf
+ test_quota_compliance_udp_peer2.conf \
+ test_quota_compliance_unix_peer1.conf \
+ test_quota_compliance_unix_peer2.conf
GNUNET_NETWORK_socket_sendto (send_handle, message, ssize,
sb,
sbs);
+ if (GNUNET_SYSERR == sent)
+ GNUNET_log_strerror(GNUNET_ERROR_TYPE_DEBUG, "sendto");
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"UDP transmit %u-byte message to %s (%d: %s)\n",
(unsigned int) ssize,
--- /dev/null
+/*
+ This file is part of GNUnet
+ (C) 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_unix.c
+ * @brief Transport plugin using unix domain sockets (!)
+ * Clearly, can only be used locally on Unix/Linux hosts...
+ * ONLY INTENDED FOR TESTING!!!
+ * @author Christian Grothoff
+ * @author Nathan Evans
+ */
+
+#include "platform.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_connection_lib.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_peerinfo_service.h"
+#include "gnunet_protocols.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_signatures.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_transport_plugin.h"
+#include "transport.h"
+
+#define DEBUG_UNIX GNUNET_YES
+
+#define MAX_PROBES 20
+
+/*
+ * Transport cost to peer, always 1 for UNIX (direct connection)
+ */
+#define UNIX_DIRECT_DISTANCE 1
+
+#define DEFAULT_NAT_PORT 0
+
+/**
+ * How long until we give up on transmitting the welcome message?
+ */
+#define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+/**
+ * Starting port for listening and sending, eventually a config value
+ */
+#define UNIX_NAT_DEFAULT_PORT 22086
+
+/**
+ * UNIX Message-Packet header.
+ */
+struct UNIXMessage
+{
+ /**
+ * Message header.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * What is the identity of the sender (GNUNET_hash of public key)
+ */
+ struct GNUNET_PeerIdentity sender;
+
+};
+
+/**
+ * Network format for IPv4 addresses.
+ */
+struct IPv4UdpAddress
+{
+ /**
+ * IPv4 address, in network byte order.
+ */
+ uint32_t ipv4_addr GNUNET_PACKED;
+
+ /**
+ * Port number, in network byte order.
+ */
+ uint16_t u_port GNUNET_PACKED;
+};
+
+
+/**
+ * Network format for IPv6 addresses.
+ */
+struct IPv6UdpAddress
+{
+ /**
+ * IPv6 address.
+ */
+ struct in6_addr ipv6_addr GNUNET_PACKED;
+
+ /**
+ * Port number, in network byte order.
+ */
+ uint16_t u6_port GNUNET_PACKED;
+};
+
+/* Forward definition */
+struct Plugin;
+
+struct PrettyPrinterContext
+{
+ GNUNET_TRANSPORT_AddressStringCallback asc;
+ void *asc_cls;
+ uint16_t port;
+};
+
+struct RetrySendContext
+{
+
+ /**
+ * Main plugin handle.
+ */
+ struct Plugin *plugin;
+
+ /**
+ * Address of recipient.
+ */
+ char *addr;
+
+ /**
+ * Length of address.
+ */
+ ssize_t addrlen;
+
+ /**
+ * Message to send.
+ */
+ char *msg;
+
+ /**
+ * Size of the message.
+ */
+ int msg_size;
+
+ /**
+ * Handle to send message out on.
+ */
+ struct GNUNET_NETWORK_Handle *send_handle;
+
+ /**
+ * Continuation to call on success or
+ * timeout.
+ */
+ GNUNET_TRANSPORT_TransmitContinuation cont;
+
+ /**
+ * Closure for continuation.
+ */
+ void *cont_cls;
+
+ /**
+ * The peer the message is destined for.
+ */
+ struct GNUNET_PeerIdentity target;
+
+ /**
+ * How long before not retrying any longer.
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * How long the last message was delayed.
+ */
+ struct GNUNET_TIME_Relative delay;
+
+ /**
+ * The actual retry task.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier retry_task;
+
+ /**
+ * 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.
+ */
+ struct LocalAddrList *prev;
+
+ /**
+ * Number of bytes of the address that follow
+ */
+ size_t size;
+
+};
+
+
+/**
+ * UNIX NAT "Session"
+ */
+struct PeerSession
+{
+
+ /**
+ * Stored in a linked list.
+ */
+ struct PeerSession *next;
+
+ /**
+ * Pointer to the global plugin struct.
+ */
+ struct Plugin *plugin;
+
+ /**
+ * To whom are we talking to (set to our identity
+ * if we are still waiting for the welcome message)
+ */
+ struct GNUNET_PeerIdentity target;
+
+ /**
+ * Address of the other peer (either based on our 'connect'
+ * call or on our 'accept' call).
+ */
+ void *connect_addr;
+
+ /**
+ * Length of connect_addr.
+ */
+ size_t connect_alen;
+
+ /**
+ * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO)
+ */
+ int expecting_welcome;
+
+ /**
+ * From which socket do we need to send to this peer?
+ */
+ struct GNUNET_NETWORK_Handle *sock;
+
+ /*
+ * Queue of messages for this peer, in the case that
+ * we have to await a connection...
+ */
+ struct MessageQueue *messages;
+
+};
+
+/**
+ * Information we keep for each of our listen sockets.
+ */
+struct UNIX_Sock_Info
+{
+ /**
+ * The network handle
+ */
+ struct GNUNET_NETWORK_Handle *desc;
+
+ /**
+ * The port we bound to
+ */
+ uint16_t port;
+};
+
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin
+{
+ /**
+ * Our environment.
+ */
+ struct GNUNET_TRANSPORT_PluginEnvironment *env;
+
+ /*
+ * Session of peers with whom we are currently connected
+ */
+ struct PeerSession *sessions;
+
+ /**
+ * ID of task used to update our addresses when one expires.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier address_update_task;
+
+ /**
+ * ID of select task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier select_task;
+
+ /**
+ * Integer to append to unix domain socket.
+ */
+ 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
+ */
+ struct GNUNET_NETWORK_FDSet *rs;
+
+ /**
+ * socket that we transmit all data with
+ */
+ struct UNIX_Sock_Info unix_sock;
+
+ /**
+ * Path of our unix domain socket (/tmp/unix-plugin-PORT)
+ */
+ char *unix_socket_path;
+
+};
+
+
+/**
+ * Disconnect from a remote node. Clean up session if we have one for this peer
+ *
+ * @param cls closure for this call (should be handle to Plugin)
+ * @param target the peeridentity of the peer to disconnect
+ * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
+ */
+void
+unix_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
+{
+ /** TODO: Implement! */
+ return;
+}
+
+/**
+ * Shutdown the server process (stop receiving inbound traffic). Maybe
+ * restarted later!
+ *
+ * @param cls Handle to the plugin for this transport
+ *
+ * @return returns the number of sockets successfully closed,
+ * should equal the number of sockets successfully opened
+ */
+static int
+unix_transport_server_stop (void *cls)
+{
+ struct Plugin *plugin = cls;
+
+ if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->select_task);
+ plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->unix_sock.desc));
+ plugin->unix_sock.desc = NULL;
+
+ return GNUNET_OK;
+}
+
+
+struct PeerSession *
+find_session (struct Plugin *plugin,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct PeerSession *pos;
+
+ pos = plugin->sessions;
+ while (pos != NULL)
+ {
+ if (memcmp(&pos->target, peer, sizeof(struct GNUNET_PeerIdentity)) == 0)
+ return pos;
+ pos = pos->next;
+ }
+
+ return pos;
+}
+
+/* Forward Declaration */
+static ssize_t
+unix_real_send (void *cls,
+ struct RetrySendContext *incoming_retry_context,
+ struct GNUNET_NETWORK_Handle *send_handle,
+ const struct GNUNET_PeerIdentity *target,
+ const char *msgbuf,
+ size_t msgbuf_size,
+ unsigned int priority,
+ struct GNUNET_TIME_Relative timeout,
+ const void *addr,
+ size_t addrlen,
+ GNUNET_TRANSPORT_TransmitContinuation cont,
+ void *cont_cls);
+
+/**
+ * Retry sending a message.
+ *
+ * @param cls closure a struct RetrySendContext
+ * @param tc context information
+ */
+void retry_send_message (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+ struct RetrySendContext *retry_ctx = cls;
+
+ if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+ return;
+ unix_real_send (retry_ctx->plugin,
+ retry_ctx,
+ retry_ctx->send_handle,
+ &retry_ctx->target,
+ retry_ctx->msg,
+ retry_ctx->msg_size,
+ retry_ctx->priority,
+ GNUNET_TIME_absolute_get_remaining (retry_ctx->timeout),
+ retry_ctx->addr,
+ retry_ctx->addrlen,
+ retry_ctx->cont,
+ retry_ctx->cont_cls);
+ return;
+}
+
+/**
+ * Actually send out the message, assume we've got the address and
+ * send_handle squared away!
+ *
+ * @param cls closure
+ * @param incoming_retry_context the retry context to use
+ * @param send_handle which handle to send message on
+ * @param target who should receive this message (ignored by UNIX)
+ * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
+ * @param msgbuf_size the size of the msgbuf to send
+ * @param priority how important is the message (ignored by UNIX)
+ * @param timeout when should we time out (give up) if we can not transmit?
+ * @param addr the addr to send the message to, needs to be a sockaddr for us
+ * @param addrlen the len of addr
+ * @param cont continuation to call once the message has
+ * been transmitted (or if the transport is ready
+ * for the next transmission call; or if the
+ * peer disconnected...)
+ * @param cont_cls closure for cont
+ *
+ * @return the number of bytes written, -1 on errors
+ */
+static ssize_t
+unix_real_send (void *cls,
+ struct RetrySendContext *incoming_retry_context,
+ struct GNUNET_NETWORK_Handle *send_handle,
+ const struct GNUNET_PeerIdentity *target,
+ const char *msgbuf,
+ size_t msgbuf_size,
+ unsigned int priority,
+ struct GNUNET_TIME_Relative timeout,
+ const void *addr,
+ size_t addrlen,
+ GNUNET_TRANSPORT_TransmitContinuation cont,
+ void *cont_cls)
+{
+ struct Plugin *plugin = cls;
+ struct UNIXMessage *message;
+ struct RetrySendContext *retry_ctx;
+ int ssize;
+ ssize_t sent;
+ const void *sb;
+ size_t sbs;
+ struct sockaddr_un *un;
+ size_t slen;
+
+ if (send_handle == NULL)
+ {
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "unix_real_send with send_handle NULL!\n");
+#endif
+ /* failed to open send socket for AF */
+ if (cont != NULL)
+ cont (cont_cls, target, GNUNET_SYSERR);
+ return 0;
+ }
+ if ((addr == NULL) || (addrlen == 0))
+ {
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "unix_real_send called without address, returning!\n");
+#endif
+ if (cont != NULL)
+ cont (cont_cls, target, GNUNET_SYSERR);
+ return 0; /* Can never send if we don't have an address!! */
+ }
+
+ /* Build the message to be sent */
+ message = GNUNET_malloc (sizeof (struct UNIXMessage) + msgbuf_size);
+ ssize = sizeof (struct UNIXMessage) + msgbuf_size;
+
+ message->header.size = htons (ssize);
+ message->header.type = htons (0);
+ memcpy (&message->sender, plugin->env->my_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ memcpy (&message[1], msgbuf, msgbuf_size);
+
+ un = GNUNET_malloc (sizeof (struct sockaddr_un));
+ un->sun_family = AF_UNIX;
+ slen = strlen (addr) + 1;
+ sent = 0;
+ GNUNET_assert(slen < sizeof(un->sun_path));
+ memcpy (un->sun_path, addr, slen);
+ un->sun_path[slen] = '\0';
+#if LINUX
+ un->sun_path[0] = '\0';
+#endif
+ slen += sizeof (sa_family_t);
+ sb = (struct sockaddr*) un;
+ sbs = slen;
+
+ sent = GNUNET_NETWORK_socket_sendto(send_handle, message, ssize, sb, sbs);
+
+ if (GNUNET_SYSERR == sent)
+ {
+ if (incoming_retry_context == NULL)
+ {
+ retry_ctx = GNUNET_malloc(sizeof(struct RetrySendContext));
+ retry_ctx->addr = GNUNET_malloc(addrlen);
+ retry_ctx->msg = GNUNET_malloc(msgbuf_size);
+ retry_ctx->plugin = plugin;
+ memcpy(retry_ctx->addr, addr, addrlen);
+ memcpy(retry_ctx->msg, msgbuf, msgbuf_size);
+ retry_ctx->msg_size = msgbuf_size;
+ retry_ctx->addrlen = addrlen;
+ retry_ctx->send_handle = send_handle;
+ retry_ctx->cont = cont;
+ retry_ctx->cont_cls = cont_cls;
+ retry_ctx->priority = priority;
+ 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;
+ }
+ else
+ {
+ retry_ctx = incoming_retry_context;
+ 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");
+ 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",
+ (unsigned int) ssize,
+ GNUNET_a2s (sb, sbs),
+ (int) sent,
+ (sent < 0) ? STRERROR (errno) : "ok");
+#endif
+ if (cont != NULL)
+ {
+ if (sent == GNUNET_SYSERR)
+ cont (cont_cls, target, GNUNET_SYSERR);
+ else
+ {
+ cont (cont_cls, target, GNUNET_OK);
+ }
+ }
+
+ GNUNET_free (message);
+ return sent;
+}
+
+
+/**
+ * Function that can be used by the transport service to transmit
+ * a message using the plugin.
+ *
+ * @param cls closure
+ * @param target who should receive this message (ignored by UNIX)
+ * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
+ * @param msgbuf_size the size of the msgbuf to send
+ * @param priority how important is the message (ignored by UNIX)
+ * @param timeout when should we time out (give up) if we can not transmit?
+ * @param session identifier used for this session (can be NULL)
+ * @param addr the addr to send the message to, needs to be a sockaddr for us
+ * @param addrlen the len of addr
+ * @param force_address not used, we had better have an address to send to
+ * because we are stateless!!
+ * @param cont continuation to call once the message has
+ * been transmitted (or if the transport is ready
+ * for the next transmission call; or if the
+ * peer disconnected...)
+ * @param cont_cls closure for cont
+ *
+ * @return the number of bytes written (may return 0 and the message can
+ * still be transmitted later!)
+ */
+static ssize_t
+unix_plugin_send (void *cls,
+ const struct GNUNET_PeerIdentity *target,
+ const char *msgbuf,
+ size_t msgbuf_size,
+ unsigned int priority,
+ struct GNUNET_TIME_Relative timeout,
+ struct Session *session,
+ const void *addr,
+ size_t addrlen,
+ int force_address,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+ struct Plugin *plugin = cls;
+ ssize_t sent;
+
+ if (force_address == GNUNET_SYSERR)
+ return GNUNET_SYSERR;
+ GNUNET_assert (NULL == session);
+
+#if DEBUG_UNIX
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Asked to send message to `%s'\n", (char *)addr);
+#endif
+ sent = unix_real_send(cls,
+ NULL,
+ plugin->unix_sock.desc,
+ target,
+ msgbuf, msgbuf_size,
+ priority, timeout, addr, addrlen,
+ cont, cont_cls);
+#if DEBUG_UNIX
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sent %d bytes to `%s'\n", sent, (char *)addr);
+#endif
+ if (sent == GNUNET_SYSERR)
+ return 0;
+ 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 fromlen the length of the address
+ */
+static void
+unix_demultiplexer(struct Plugin *plugin,
+ struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *currhdr,
+ const struct sockaddr_un *un,
+ size_t fromlen)
+{
+ struct GNUNET_TRANSPORT_ATS_Information distance[2];
+
+ distance[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
+ distance[0].value = htonl (UNIX_DIRECT_DISTANCE);
+ distance[1].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+ distance[1].value = htonl (0);
+
+ GNUNET_assert(fromlen >= sizeof(struct sockaddr_un));
+
+#if DEBUG_UNIX
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received message from %s\n", un->sun_path);
+#endif
+ plugin->env->receive (plugin->env->cls, sender, currhdr,
+ (const struct GNUNET_TRANSPORT_ATS_Information *) &distance, 2,
+ NULL, un->sun_path, strlen(un->sun_path) + 1);
+}
+
+
+/*
+ * @param cls the plugin handle
+ * @param tc the scheduling context (for rescheduling this function again)
+ *
+ * We have been notified that our writeset has something to read. We don't
+ * know which socket needs to be read, so we have to check each one
+ * Then reschedule this function to be called again once more is available.
+ *
+ */
+static void
+unix_plugin_select (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+ char buf[65536];
+ struct UNIXMessage *msg;
+ struct GNUNET_PeerIdentity sender;
+ //socklen_t fromlen;
+ struct sockaddr_un un;
+ socklen_t addrlen;
+ ssize_t ret;
+ int offset;
+ int tsize;
+ char *msgbuf;
+ const struct GNUNET_MessageHeader *currhdr;
+ uint16_t csize;
+
+ plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
+ if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+ return;
+
+ addrlen = sizeof(un);
+ memset(&un, 0, sizeof(un));
+ GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->unix_sock.desc));
+ ret =
+ GNUNET_NETWORK_socket_recvfrom (plugin->unix_sock.desc, buf, sizeof (buf),
+ (struct sockaddr *)&un, &addrlen);
+
+ if (ret == GNUNET_SYSERR)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom");
+ plugin->select_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
+ NULL, &unix_plugin_select, plugin);
+ return;
+ }
+ else
+ {
+#if LINUX
+ un.sun_path[0] = '/';
+#endif
+#if DEBUG_UNIX
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Read %d bytes from socket %s\n", ret, &un.sun_path[0]);
+#endif
+ }
+
+ GNUNET_assert (AF_UNIX == (un.sun_family));
+
+ msg = (struct UNIXMessage *) buf;
+ csize = ntohs (msg->header.size);
+ if ( (csize < sizeof (struct UNIXMessage)) ||
+ (csize > ret) )
+ {
+ GNUNET_break_op (0);
+ plugin->select_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
+ NULL, &unix_plugin_select, plugin);
+ return;
+ }
+ msgbuf = (char *)&msg[1];
+ memcpy (&sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity));
+ offset = 0;
+ tsize = csize - sizeof (struct UNIXMessage);
+ while (offset + sizeof (struct GNUNET_MessageHeader) <= tsize)
+ {
+ currhdr = (struct GNUNET_MessageHeader *)&msgbuf[offset];
+ csize = ntohs (currhdr->size);
+ if ( (csize < sizeof (struct GNUNET_MessageHeader)) ||
+ (csize > tsize - offset) )
+ {
+ GNUNET_break_op (0);
+ break;
+ }
+ unix_demultiplexer(plugin, &sender, currhdr,
+ &un, sizeof(un));
+ offset += csize;
+ }
+ plugin->select_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
+ NULL, &unix_plugin_select, plugin);
+}
+
+/**
+ * Create a slew of UNIX sockets. If possible, use IPv6 and IPv4.
+ *
+ * @param cls closure for server start, should be a struct Plugin *
+ * @return number of sockets created or GNUNET_SYSERR on error
+*/
+static int
+unix_transport_server_start (void *cls)
+{
+ struct Plugin *plugin = cls;
+
+ struct sockaddr *serverAddr;
+ socklen_t addrlen;
+ int sockets_created;
+ struct sockaddr_un *un;
+ size_t slen;
+
+ un = GNUNET_malloc (sizeof (struct sockaddr_un));
+ un->sun_family = AF_UNIX;
+ slen = strlen (plugin->unix_socket_path) + 1;
+
+ 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;
+ addrlen = slen;
+ sockets_created = 0;
+#if LINUX
+ 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");
+ }
+ else
+ {
+ if (GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, serverAddr, addrlen) !=
+ GNUNET_OK)
+ {
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "UNIX Binding failed!\n");
+#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,
+ plugin->unix_sock.desc);
+
+ plugin->select_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
+ NULL, &unix_plugin_select, plugin);
+ return sockets_created;
+}
+
+
+/**
+ * Function that will be called to check if a binary address for this
+ * plugin is well-formed and corresponds to an address for THIS peer
+ * (as per our configuration). Naturally, if absolutely necessary,
+ * plugins can be a bit conservative in their answer, but in general
+ * plugins should make sure that the address does not redirect
+ * traffic to a 3rd party that might try to man-in-the-middle our
+ * traffic.
+ *
+ * @param cls closure, should be our handle to the Plugin
+ * @param addr pointer to the address
+ * @param addrlen length of addr
+ * @return GNUNET_OK if this is a plausible address for this peer
+ * and transport, GNUNET_SYSERR if not
+ *
+ */
+static int
+unix_check_address (void *cls,
+ const void *addr,
+ size_t addrlen)
+{
+
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Informing transport service about my address `%s'\n",
+ (char *)addr);
+#endif
+ return GNUNET_OK;
+}
+
+
+/**
+ * Append our port and forward the result.
+ */
+static void
+append_port (void *cls, const char *hostname)
+{
+ struct PrettyPrinterContext *ppc = cls;
+ char *ret;
+
+ if (hostname == NULL)
+ {
+ ppc->asc (ppc->asc_cls, NULL);
+ GNUNET_free (ppc);
+ return;
+ }
+ GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
+ ppc->asc (ppc->asc_cls, ret);
+ GNUNET_free (ret);
+}
+
+
+/**
+ * Convert the transports address to a nice, human-readable
+ * format.
+ *
+ * @param cls closure
+ * @param type name of the transport that generated the address
+ * @param addr one of the addresses of the host, NULL for the last address
+ * the specific address format depends on the transport
+ * @param addrlen length of the address
+ * @param numeric should (IP) addresses be displayed in numeric form?
+ * @param timeout after how long should we give up?
+ * @param asc function to call on each string
+ * @param asc_cls closure for asc
+ */
+static void
+unix_plugin_address_pretty_printer (void *cls,
+ const char *type,
+ const void *addr,
+ size_t addrlen,
+ int numeric,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_TRANSPORT_AddressStringCallback asc,
+ void *asc_cls)
+{
+ struct Plugin *plugin = cls;
+ struct PrettyPrinterContext *ppc;
+ const void *sb;
+ size_t sbs;
+ struct sockaddr_in a4;
+ struct sockaddr_in6 a6;
+ const struct IPv4UdpAddress *u4;
+ const struct IPv6UdpAddress *u6;
+ uint16_t port;
+
+ if (addrlen == sizeof (struct IPv6UdpAddress))
+ {
+ u6 = addr;
+ memset (&a6, 0, sizeof (a6));
+ a6.sin6_family = AF_INET6;
+ a6.sin6_port = u6->u6_port;
+ memcpy (&a6.sin6_addr,
+ &u6->ipv6_addr,
+ sizeof (struct in6_addr));
+ port = ntohs (u6->u6_port);
+ sb = &a6;
+ sbs = sizeof (a6);
+ }
+ else if (addrlen == sizeof (struct IPv4UdpAddress))
+ {
+ u4 = addr;
+ memset (&a4, 0, sizeof (a4));
+ a4.sin_family = AF_INET;
+ a4.sin_port = u4->u_port;
+ a4.sin_addr.s_addr = u4->ipv4_addr;
+ port = ntohs (u4->u_port);
+ sb = &a4;
+ sbs = sizeof (a4);
+ }
+ else
+ {
+ /* invalid address */
+ GNUNET_break_op (0);
+ asc (asc_cls, NULL);
+ return;
+ }
+ ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
+ ppc->asc = asc;
+ ppc->asc_cls = asc_cls;
+ ppc->port = port;
+ GNUNET_RESOLVER_hostname_get (plugin->env->cfg,
+ sb,
+ sbs,
+ !numeric, timeout, &append_port, ppc);
+}
+
+/**
+ * Function called for a quick conversion of the binary address to
+ * a numeric address. Note that the caller must not free the
+ * address and that the next call to this function is allowed
+ * to override the address again.
+ *
+ * @param cls closure
+ * @param addr binary address
+ * @param addrlen length of the address
+ * @return string representing the same address
+ */
+static const char*
+unix_address_to_string (void *cls,
+ 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;
+ }
+ else
+ return NULL;
+ inet_ntop (af, sb, buf, INET6_ADDRSTRLEN);
+ GNUNET_snprintf (rbuf,
+ sizeof (rbuf),
+ "%s:%u",
+ buf,
+ port);
+ return rbuf;
+}
+
+/**
+ * The exported method. Makes the core api available via a global and
+ * returns the unix transport API.
+ */
+void *
+libgnunet_plugin_transport_unix_init (void *cls)
+{
+ struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
+ unsigned long long port;
+ struct GNUNET_TRANSPORT_PluginFunctions *api;
+ struct Plugin *plugin;
+ int sockets_created;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (env->cfg,
+ "transport-unix",
+ "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);
+
+ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
+ api->cls = plugin;
+
+ api->send = &unix_plugin_send;
+ api->disconnect = &unix_disconnect;
+ 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);
+ return api;
+}
+
+void *
+libgnunet_plugin_transport_unix_done (void *cls)
+{
+ 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);
+ GNUNET_free (api);
+ return NULL;
+}
+
+/* end of plugin_transport_unix.c */
static int is_http;
static int is_https;
static int is_udp;
+static int is_unix;
static int is_asymmetric_send_constant;
static int is_asymmetric_recv_constant;
setup_peer (&p1, "test_quota_compliance_udp_peer1.conf");
setup_peer (&p2, "test_quota_compliance_udp_peer2.conf");
}
+ else if (is_unix)
+ {
+ if (is_asymmetric_recv_constant == GNUNET_YES)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing asymmetric quota compliance (receiver quota constant) for UNIX transport plugin\n");
+ else if (is_asymmetric_send_constant == GNUNET_YES)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing asymmetric quota compliance (sender quota constant) for UNIX transport plugin\n");
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing symmetric quota compliance for UNIX transport plugin\n");
+ setup_peer (&p1, "test_quota_compliance_unix_peer1.conf");
+ setup_peer (&p2, "test_quota_compliance_unix_peer2.conf");
+ }
else if (is_tcp_nat)
{
if (is_asymmetric_recv_constant == GNUNET_YES)
{
is_udp = GNUNET_YES;
}
+ else if (strstr(argv[0], "unix") != NULL)
+ {
+ is_unix = GNUNET_YES;
+ }
if (strstr(argv[0], "asymmetric_recv") != NULL)
{
else
GNUNET_asprintf(&logger, "test-quota-compliance-%s-%s","udp","symmetric");
}
+ else if (is_unix == GNUNET_YES)
+ {
+ if (is_asymmetric_recv_constant == GNUNET_YES)
+ GNUNET_asprintf(&logger, "test-quota-compliance-%s-%s","unix","asymmetric_recv_constant");
+ else if (is_asymmetric_send_constant == GNUNET_YES)
+ GNUNET_asprintf(&logger, "test-quota-compliance-%s-%s","unix","asymmetric_send_constant");
+ else
+ GNUNET_asprintf(&logger, "test-quota-compliance-%s-%s","unix","symmetric");
+ }
else if (is_http == GNUNET_YES)
{
if (is_asymmetric_recv_constant == GNUNET_YES)
--- /dev/null
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer1/
+DEFAULTCONFIG = test_quota_compliance_unix_peer1.conf
+
+[fs]
+AUTOSTART = NO
+
+[datastore]
+AUTOSTART = NO
+
+[hostlist]
+HTTP-PROXY =
+SERVERS = http://gnunet.org:8080/
+OPTIONS = -b
+BINARY = gnunet-daemon-hostlist
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+HTTPPORT = 8080
+
+[topology]
+BINARY = gnunet-daemon-topology
+CONFIG = $DEFAULTCONFIG
+FRIENDS = $SERVICEHOME/friends
+TARGET-CONNECTION-COUNT = 16
+AUTOCONNECT = YES
+FRIENDS-ONLY = NO
+MINIMUM-FRIENDS = 0
+
+[core]
+AUTOSTART = NO
+
+[transport-unix]
+PORT = 4368
+
+
+[transport]
+plugins = unix
+#DEBUG = YES
+PREFIX =
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+BINARY = gnunet-service-transport
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 4091
+UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer1.sock
+
+[peerinfo]
+TRUST = $SERVICEHOME/data/credit/
+HOSTS = $SERVICEHOME/data/hosts/
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-peerinfo
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 4090
+UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer1.sock
+
+[resolver]
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-resolver
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 4089
+UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer1.sock
+
+[statistics]
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-statistics
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 4088
+UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer1.sock
+
+[arm]
+DEFAULTSERVICES =
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-arm
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 4087
+UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer1.sock
+
+[TESTING]
+WEAKRANDOM = YES
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+
+[dht]
+AUTOSTART = NO
+
+
--- /dev/null
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer2
+DEFAULTCONFIG = test_quota_compliance_unix_peer2.conf
+
+[transport-unix]
+PORT = 3368
+[fs]
+AUTOSTART = NO
+
+[datastore]
+AUTOSTART = NO
+
+[hostlist]
+HTTP-PROXY =
+SERVERS = http://gnunet.org:8080/
+OPTIONS = -b
+BINARY = gnunet-daemon-hostlist
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+HTTPPORT = 8080
+
+[topology]
+BINARY = gnunet-daemon-topology
+CONFIG = $DEFAULTCONFIG
+FRIENDS = $SERVICEHOME/friends
+TARGET-CONNECTION-COUNT = 16
+AUTOCONNECT = YES
+FRIENDS-ONLY = NO
+MINIMUM-FRIENDS = 0
+
+[core]
+AUTOSTART = NO
+
+[transport]
+plugins = unix
+#DEBUG = YES
+PREFIX =
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+BINARY = gnunet-service-transport
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 3091
+UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer2.sock
+
+[peerinfo]
+TRUST = $SERVICEHOME/data/credit/
+HOSTS = $SERVICEHOME/data/hosts/
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-peerinfo
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 3090
+UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer2.sock
+
+[resolver]
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-resolver
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 3089
+UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer2.sock
+
+[statistics]
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-statistics
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 3088
+UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer2.sock
+
+[arm]
+DEFAULTSERVICES =
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-arm
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 3087
+UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer2.sock
+
+[TESTING]
+WEAKRANDOM = YES
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+
+[dht]
+AUTOSTART = NO
+
+
static int is_udp;
+static int is_unix;
+
static int is_udp_nat;
static int is_http;
setup_peer (&p1, "test_transport_api_udp_peer1.conf");
setup_peer (&p2, "test_transport_api_udp_peer2.conf");
}
+ if (is_unix)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Using unix domain socket transport\n");
+ setup_peer (&p1, "test_transport_api_unix_peer1.conf");
+ setup_peer (&p2, "test_transport_api_unix_peer2.conf");
+ }
if (is_multi_protocol)
{
setup_peer (&p1, "test_transport_api_multi_peer1.conf");
{
is_udp = GNUNET_YES;
}
+ else if (strstr(argv[0], "unix") != NULL)
+ {
+ is_unix = GNUNET_YES;
+ }
else if (strstr(argv[0], "https") != NULL)
{
is_https = GNUNET_YES;
#include "gnunet_scheduler_lib.h"
#include "gnunet_server_lib.h"
#include "gnunet_transport_service.h"
+#include "gauger.h"
#include "transport.h"
#define VERBOSE GNUNET_NO
static int is_udp;
+static int is_unix;
+
static int connected;
static unsigned long long total_bytes;
static char * key_file_p2;
static char * cert_file_p2;
-
+static char *test_name;
static int msg_scheduled;
static int msg_sent;
static int msg_recv_expected;
end ()
{
unsigned long long delta;
+ char *value_name;
GNUNET_SCHEDULER_cancel (die_task);
die_task = GNUNET_SCHEDULER_NO_TASK;
fprintf (stderr,
"\nThroughput was %llu kb/s\n",
total_bytes * 1000 / 1024 / delta);
+ GNUNET_asprintf(&value_name, "reliable_kbs_%s", test_name);
+ GAUGER (value_name, (int)(total_bytes * 1000 / 1024 /delta));
+ GNUNET_free(value_name);
ok = 0;
}
setup_peer (&p1, "test_transport_api_udp_peer1.conf");
setup_peer (&p2, "test_transport_api_udp_peer2.conf");
}
+ else if (is_unix)
+ {
+ setup_peer (&p1, "test_transport_api_unix_peer1.conf");
+ setup_peer (&p2, "test_transport_api_unix_peer2.conf");
+ }
else if (is_tcp_nat)
{
setup_peer (&p1, "test_transport_api_tcp_nat_peer1.conf");
if (strstr(argv[0], "tcp_nat") != NULL)
{
is_tcp_nat = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "tcp_nat");
}
else if (strstr(argv[0], "tcp") != NULL)
{
is_tcp = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "tcp");
}
else if (strstr(argv[0], "https") != NULL)
{
is_https = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "https");
}
else if (strstr(argv[0], "http") != NULL)
{
is_http = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "http");
}
else if (strstr(argv[0], "udp") != NULL)
{
is_udp = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "udp");
+ }
+ else if (strstr(argv[0], "unix") != NULL)
+ {
+ is_unix = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "unix");
}
GNUNET_log_setup ("test-transport-api-reliability",
#if VERBOSE
--- /dev/null
+[transport-unix]
+PORT = 12368
+
+[fs]
+AUTOSTART = NO
+
+[datastore]
+AUTOSTART = NO
+
+[core]
+AUTOSTART = NO
+
+[hostlist]
+HTTP-PROXY =
+SERVERS = http://gnunet.org:8080/
+OPTIONS = -b
+BINARY = gnunet-daemon-hostlist
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+HTTPPORT = 8080
+
+[topology]
+BINARY = gnunet-daemon-topology
+CONFIG = $DEFAULTCONFIG
+FRIENDS = $SERVICEHOME/friends
+TARGET-CONNECTION-COUNT = 16
+AUTOCONNECT = YES
+FRIENDS-ONLY = NO
+MINIMUM-FRIENDS = 0
+
+[core]
+AUTOSTART = NO
+
+[transport]
+PLUGINS = unix
+#DEBUG = YES
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+BINARY = gnunet-service-transport
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 12365
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+
+[peerinfo]
+TRUST = $SERVICEHOME/data/credit/
+HOSTS = $SERVICEHOME/data/hosts/
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-peerinfo
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 12369
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[resolver]
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-resolver
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 12364
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[statistics]
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-statistics
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 12367
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[arm]
+DEFAULTSERVICES =
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-arm
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 12366
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[transport-tcp]
+TIMEOUT = 300000
+PORT = 12368
+
+[TESTING]
+WEAKRANDOM = YES
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+DEFAULTCONFIG = test_transport_api_unix_peer1.conf
+SERVICEHOME = /tmp/test-gnunetd-transport-peer-1/
+
+
+[dht]
+AUTOSTART = NO
+
+
--- /dev/null
+[transport-unix]
+PORT = 22368
+
+[fs]
+AUTOSTART = NO
+
+[datastore]
+AUTOSTART = NO
+
+[core]
+AUTOSTART = NO
+
+[hostlist]
+HTTP-PROXY =
+SERVERS = http://gnunet.org:8080/
+OPTIONS = -b
+BINARY = gnunet-daemon-hostlist
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+HTTPPORT = 8080
+
+[topology]
+BINARY = gnunet-daemon-topology
+CONFIG = $DEFAULTCONFIG
+FRIENDS = $SERVICEHOME/friends
+TARGET-CONNECTION-COUNT = 16
+AUTOCONNECT = YES
+FRIENDS-ONLY = NO
+MINIMUM-FRIENDS = 0
+
+[transport]
+PLUGINS = unix
+#DEBUG = YES
+PREFIX =
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+BINARY = gnunet-service-transport
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 22365
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+#PREFIX = valgrind --track-origins=yes --leak-check=full --log-file=valgrind_udp_peer2.log
+
+[peerinfo]
+TRUST = $SERVICEHOME/data/credit/
+HOSTS = $SERVICEHOME/data/hosts/
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-peerinfo
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 22369
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[resolver]
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-resolver
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 22364
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[statistics]
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-statistics
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 22367
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[arm]
+DEFAULTSERVICES =
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+BINARY = gnunet-service-arm
+CONFIG = $DEFAULTCONFIG
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 22366
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[transport-tcp]
+TIMEOUT = 300000
+PORT = 22368
+
+[TESTING]
+WEAKRANDOM = YES
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+DEFAULTCONFIG = test_transport_api_unix_peer2.conf
+SERVICEHOME = /tmp/test-gnunetd-transport-peer-2/
+
+
+[dht]
+AUTOSTART = NO
+
+
--- /dev/null
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api_unreliability.c
+ * @brief test case for transports; ensures messages get
+ * through, regardless of order
+ *
+ * This test case serves as a base for unreliable
+ * transport test cases to check that the transports
+ * achieve reliable message delivery.
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_transport_service.h"
+#include "gauger.h"
+#include "transport.h"
+
+#define VERBOSE GNUNET_NO
+
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * Note that this value must not significantly exceed
+ * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
+ * messages may be dropped even for a reliable transport.
+ */
+#define TOTAL_MSGS (80000 * 3) /* Total messages should be divisible by 8, so we can make a nice bitmap */
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500)
+
+#define UNRELIABLE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
+
+#define MTYPE 12345
+
+struct PeerContext
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct GNUNET_TRANSPORT_Handle *th;
+ struct GNUNET_PeerIdentity id;
+#if START_ARM
+ struct GNUNET_OS_Process *arm_proc;
+#endif
+};
+
+static struct PeerContext p1;
+
+static struct PeerContext p2;
+
+static int ok;
+
+static int is_tcp;
+
+static int is_tcp_nat;
+
+static int is_http;
+
+static int is_https;
+
+static int is_udp;
+
+static int is_unix;
+
+static int connected;
+
+static unsigned long long total_bytes;
+
+static struct GNUNET_TIME_Absolute start_time;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static char *key_file_p1;
+static char *cert_file_p1;
+
+static char *key_file_p2;
+static char *cert_file_p2;
+
+static char *test_name;
+
+static char bitmap[TOTAL_MSGS / 8];
+
+static int msg_scheduled;
+static int msg_sent;
+static int msg_recv_expected;
+static int msg_recv;
+static struct GNUNET_TRANSPORT_TransmitHandle * transmit_handle;
+
+#if VERBOSE
+#define OKPP do { ok++; fprintf (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+/**
+ * Sets a bit active in the bitmap.
+ *
+ * @param bitIdx which bit to set
+ */
+static void
+set_bit (unsigned int bitIdx)
+{
+ size_t arraySlot;
+ unsigned int targetBit;
+ if (bitIdx > sizeof(bitmap) * 8)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "setting bit %d of %d(!)\n", bitIdx, sizeof(bitmap) * 8);
+ return;
+ }
+ GNUNET_assert(bitIdx < sizeof(bitmap) * 8);
+ arraySlot = bitIdx / 8;
+ targetBit = (1L << (bitIdx % 8));
+ bitmap[arraySlot] |= targetBit;
+}
+
+/**
+ * Obtain a bit from bitmap.
+ * @param map the bitmap
+ * @param bit index from bitmap
+ *
+ * @return Bit \a bit from hashcode \a code
+ */
+int
+get_bit (const char *map, unsigned int bit)
+{
+ if (bit >= TOTAL_MSGS)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "get bit %d of %d(!?!?)\n", bit, sizeof(bitmap) * 8);
+ return 0;
+ }
+ return ((map)[bit >> 3] & (1 << (bit & 7))) > 0;
+}
+
+static void
+end ()
+{
+ unsigned long long delta;
+ int i;
+ int result;
+ char *value_name;
+
+ result = 0;
+ for (i = 0; i < TOTAL_MSGS; i++)
+ {
+ if (get_bit(bitmap, i) == 0)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Did not receive message %d\n", i);
+ result = -1;
+ }
+ }
+
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from transports!\n");
+#endif
+ GNUNET_TRANSPORT_disconnect (p1.th);
+ GNUNET_TRANSPORT_disconnect (p2.th);
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transports disconnected, returning success!\n");
+#endif
+ delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value;
+ GNUNET_asprintf(&value_name, "unreliable_kbs_%s", test_name);
+ GAUGER (value_name, (int)(total_bytes * 1000 / 1024 /delta));
+ GNUNET_free(value_name);
+ fprintf (stderr,
+ "\nThroughput was %llu kb/s\n",
+ total_bytes * 1000 / 1024 / delta);
+ ok = result;
+
+}
+
+static void
+end_unreliably ()
+{
+ unsigned long long delta;
+ int i;
+ int num_failed;
+ char *value_name;
+ num_failed = 0;
+ for (i = 0; i < TOTAL_MSGS; i++)
+ {
+ if (get_bit(bitmap, i) == 0)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Did not receive message %d\n", i);
+ num_failed++;
+ }
+ }
+
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from transports!\n");
+#endif
+ GNUNET_TRANSPORT_disconnect (p1.th);
+ GNUNET_TRANSPORT_disconnect (p2.th);
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transports disconnected, returning success!\n");
+#endif
+ delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value;
+ fprintf (stderr,
+ "\nThroughput was %llu kb/s\n",
+ total_bytes * 1000 / 1024 / delta);
+ GNUNET_asprintf(&value_name, "unreliable_kbs_%s", test_name);
+ GAUGER (value_name, (int)(total_bytes * 1000 / 1024 /delta));
+ GNUNET_free(value_name);
+ GNUNET_asprintf(&value_name, "unreliable_failed_%s", test_name);
+ GAUGER (value_name, (int)num_failed);
+ GNUNET_free(value_name);
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Had %d failed messages!\n", num_failed);
+ ok = 0;
+
+}
+
+
+
+static void
+stop_arm (struct PeerContext *p)
+{
+#if START_ARM
+ if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ GNUNET_OS_process_wait (p->arm_proc);
+ GNUNET_OS_process_close (p->arm_proc);
+ p->arm_proc = NULL;
+#endif
+ GNUNET_CONFIGURATION_destroy (p->cfg);
+}
+
+
+static void
+end_badly (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Reliability failed: \nLast message sent %u \nNext message scheduled %u\nLast message received %u\nMessage expected %u \n ", msg_sent, msg_scheduled, msg_recv, msg_recv_expected);
+ GNUNET_break (0);
+ GNUNET_TRANSPORT_disconnect (p1.th);
+ GNUNET_TRANSPORT_disconnect (p2.th);
+ ok = 1;
+}
+
+
+struct TestMessage
+{
+ struct GNUNET_MessageHeader header;
+ uint32_t num;
+};
+
+
+static unsigned int
+get_size (unsigned int iter)
+{
+ unsigned int ret;
+
+ if (iter < 60000)
+ return iter + sizeof (struct TestMessage);
+ ret = (iter * iter * iter);
+ return sizeof (struct TestMessage) + (ret % 60000);
+}
+
+
+static void
+notify_receive (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ static int n;
+ unsigned int s;
+ char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ const struct TestMessage *hdr;
+
+ hdr = (const struct TestMessage*) message;
+
+ if (MTYPE != ntohs (message->type))
+ return;
+ msg_recv_expected = n;
+ msg_recv = ntohl(hdr->num);
+ s = get_size (ntohl(hdr->num));
+
+ if (ntohs (message->size) != s)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u of size %u, got %u bytes of message %u\n",
+ ntohl(hdr->num), s,
+ ntohs (message->size),
+ ntohl (hdr->num));
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+
+ memset (cbuf, ntohl(hdr->num), s - sizeof (struct TestMessage));
+ if (0 != memcmp (cbuf,
+ &hdr[1],
+ s - sizeof (struct TestMessage)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u with bits %u, but body did not match\n",
+ ntohl(hdr->num), (unsigned char) n);
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+#if VERBOSE
+ if (ntohl(hdr->num) % 5 == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got message %u of size %u\n",
+ ntohl (hdr->num),
+ ntohs (message->size));
+ }
+#endif
+ n++;
+ set_bit(ntohl(hdr->num));
+ if (0 == (n % (5000)))
+ {
+ fprintf (stderr, ".");
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
+ &end_badly,
+ NULL);
+ }
+ if (n == TOTAL_MSGS)
+ end ();
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ static int n;
+ char *cbuf = buf;
+ struct TestMessage hdr;
+ unsigned int s;
+ unsigned int ret;
+
+ if (buf == NULL)
+ {
+ GNUNET_break (0);
+ ok = 42;
+ return 0;
+ }
+ ret = 0;
+ s = get_size (n);
+ GNUNET_assert (size >= s);
+ GNUNET_assert (buf != NULL);
+ cbuf = buf;
+ do
+ {
+ hdr.header.size = htons (s);
+ hdr.header.type = htons (MTYPE);
+ hdr.num = htonl (n);
+ msg_sent = n;
+ memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage));
+ ret += sizeof (struct TestMessage);
+ memset (&cbuf[ret], n, s - sizeof (struct TestMessage));
+ ret += s - sizeof (struct TestMessage);
+#if VERBOSE
+ if (n % 5000 == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending message %u of size %u\n",
+ n,
+ s);
+ }
+#endif
+ n++;
+ s = get_size (n);
+ if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16))
+ break; /* sometimes pack buffer full, sometimes not */
+ }
+ while (size - ret >= s);
+ if (n < TOTAL_MSGS)
+ {
+ GNUNET_TRANSPORT_notify_transmit_ready (p2.th,
+ &p1.id,
+ s, 0, TIMEOUT,
+ ¬ify_ready,
+ NULL);
+ msg_scheduled = n;
+ }
+ else
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "All messages scheduled to be sent!!\n");
+ GNUNET_SCHEDULER_cancel(die_task);
+ die_task = GNUNET_SCHEDULER_add_delayed (UNRELIABLE_TIMEOUT, &end_unreliably, NULL);
+ }
+ if (n % 5000 == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Returning total message block of size %u\n",
+ ret);
+ }
+ total_bytes += ret;
+ return ret;
+}
+
+
+static void
+notify_connect (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ if (cls == &p1)
+ {
+ GNUNET_TRANSPORT_set_quota (p1.th,
+ &p2.id,
+ GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
+ GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ NULL, NULL);
+ start_time = GNUNET_TIME_absolute_get ();
+ connected++;
+ }
+ else
+ {
+ GNUNET_TRANSPORT_set_quota (p2.th,
+ &p1.id,
+ GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
+ GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ NULL, NULL);
+ connected++;
+ }
+
+ if (connected == 2)
+ {
+
+ if ((transmit_handle!=NULL) && (cls == NULL))
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel(transmit_handle);
+ if ((transmit_handle!=NULL) && (cls == &transmit_handle))
+ transmit_handle=NULL;
+ GNUNET_TRANSPORT_notify_transmit_ready (p2.th,
+ &p1.id,
+ get_size (0), 0, TIMEOUT,
+ ¬ify_ready,
+ NULL);
+ }
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer `%4s' connected to us (%p)!\n", GNUNET_i2s (peer), cls);
+#endif
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer `%4s' disconnected (%p)!\n",
+ GNUNET_i2s (peer), cls);
+#endif
+}
+
+
+static void
+setup_peer (struct PeerContext *p, const char *cfgname)
+{
+ p->cfg = GNUNET_CONFIGURATION_create ();
+#if START_ARM
+ p->arm_proc = GNUNET_OS_start_process (NULL, NULL,
+ "gnunet-service-arm",
+ "gnunet-service-arm",
+#if VERBOSE_ARM
+ "-L", "DEBUG",
+#endif
+ "-c", cfgname, NULL);
+#endif
+ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
+
+ if (is_https)
+ {
+ struct stat sbuf;
+ if (p==&p1)
+ {
+ if (GNUNET_CONFIGURATION_have_value (p->cfg,
+ "transport-https", "KEY_FILE"))
+ GNUNET_CONFIGURATION_get_value_string (p->cfg, "transport-https", "KEY_FILE", &key_file_p1);
+ if (key_file_p1 == NULL)
+ GNUNET_asprintf(&key_file_p1,"https_p1.key");
+ if (0 == stat (key_file_p1, &sbuf ))
+ {
+ if (0 == remove(key_file_p1))
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Successfully removed existing private key file `%s'\n",key_file_p1);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove private key file `%s'\n",key_file_p1);
+ }
+ if (GNUNET_CONFIGURATION_have_value (p->cfg,"transport-https", "CERT_FILE"))
+ GNUNET_CONFIGURATION_get_value_string (p->cfg, "transport-https", "CERT_FILE", &cert_file_p1);
+ if (cert_file_p1 == NULL)
+ GNUNET_asprintf(&cert_file_p1,"https_p1.cert");
+ if (0 == stat (cert_file_p1, &sbuf ))
+ {
+ if (0 == remove(cert_file_p1))
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Successfully removed existing certificate file `%s'\n",cert_file_p1);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove existing certificate file `%s'\n",cert_file_p1);
+ }
+ }
+ else if (p==&p2)
+ {
+ if (GNUNET_CONFIGURATION_have_value (p->cfg,
+ "transport-https", "KEY_FILE"))
+ GNUNET_CONFIGURATION_get_value_string (p->cfg, "transport-https", "KEY_FILE", &key_file_p2);
+ if (key_file_p2 == NULL)
+ GNUNET_asprintf(&key_file_p2,"https_p2.key");
+ if (0 == stat (key_file_p2, &sbuf ))
+ {
+ if (0 == remove(key_file_p2))
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Successfully removed existing private key file `%s'\n",key_file_p2);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove private key file `%s'\n",key_file_p2);
+ }
+ if (GNUNET_CONFIGURATION_have_value (p->cfg,"transport-https", "CERT_FILE"))
+ GNUNET_CONFIGURATION_get_value_string (p->cfg, "transport-https", "CERT_FILE", &cert_file_p2);
+ if (cert_file_p2 == NULL)
+ GNUNET_asprintf(&cert_file_p2,"https_p2.cert");
+ if (0 == stat (cert_file_p2, &sbuf ))
+ {
+ if (0 == remove(cert_file_p2))
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Successfully removed existing certificate file `%s'\n",cert_file_p2);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove existing certificate file `%s'\n",cert_file_p2);
+ }
+ }
+ }
+
+ p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL,
+ p,
+ ¬ify_receive,
+ ¬ify_connect,
+ ¬ify_disconnect);
+ GNUNET_assert (p->th != NULL);
+}
+
+static size_t
+notify_ready_connect (void *cls, size_t size, void *buf)
+{
+ return 0;
+}
+
+static void
+exchange_hello_last (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct PeerContext *me = cls;
+ transmit_handle = NULL;
+ GNUNET_TRANSPORT_get_hello_cancel (p2.th, &exchange_hello_last, me);
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Exchanging HELLO with peer (%p)!\n", cls);
+#endif
+ GNUNET_assert (ok >= 3);
+ OKPP;
+ GNUNET_assert (message != NULL);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
+ message, &me->id));
+
+ GNUNET_assert(NULL != (transmit_handle = GNUNET_TRANSPORT_notify_transmit_ready (p2.th,
+ &p1.id,
+ sizeof (struct GNUNET_MessageHeader), 0,
+ TIMEOUT,
+ ¬ify_ready_connect,
+ &transmit_handle)));
+
+ /* both HELLOs exchanged, get ready to test transmission! */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Finished exchanging HELLOs, now waiting for transmission!\n");
+}
+
+
+static void
+exchange_hello (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct PeerContext *me = cls;
+
+ GNUNET_TRANSPORT_get_hello_cancel (p1.th, &exchange_hello, me);
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Exchanging HELLO with peer (%p)!\n", cls);
+#endif
+ GNUNET_assert (ok >= 2);
+ OKPP;
+ GNUNET_assert (message != NULL);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
+ message, &me->id));
+
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received HELLO size %d\n",
+ GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
+#endif
+ GNUNET_TRANSPORT_offer_hello (p2.th, message);
+ GNUNET_TRANSPORT_get_hello (p2.th, &exchange_hello_last, &p2);
+}
+
+/**
+ * Return the actual path to a file found in the current
+ * PATH environment variable.
+ *
+ * @param binary the name of the file to find
+ */
+static char *
+get_path_from_PATH (char *binary)
+{
+ char *path;
+ char *pos;
+ char *end;
+ char *buf;
+ const char *p;
+
+ p = getenv ("PATH");
+ if (p == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("PATH environment variable is unset.\n"));
+ return NULL;
+ }
+ path = GNUNET_strdup (p); /* because we write on it */
+ buf = GNUNET_malloc (strlen (path) + 20);
+ pos = path;
+
+ while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
+ {
+ *end = '\0';
+ sprintf (buf, "%s/%s", pos, binary);
+ if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
+ {
+ GNUNET_free (path);
+ return buf;
+ }
+ pos = end + 1;
+ }
+ sprintf (buf, "%s/%s", pos, binary);
+ if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
+ {
+ GNUNET_free (path);
+ return buf;
+ }
+ GNUNET_free (buf);
+ GNUNET_free (path);
+ return NULL;
+}
+
+/**
+ * Check whether the suid bit is set on a file.
+ * Attempts to find the file using the current
+ * PATH environment variable as a search path.
+ *
+ * @param binary the name of the file to check
+ *
+ * @return GNUNET_YES if the binary is found and
+ * can be run properly, GNUNET_NO otherwise
+ */
+static int
+check_gnunet_nat_binary(char *binary)
+{
+ struct stat statbuf;
+ char *p;
+#ifdef MINGW
+ SOCKET rawsock;
+#endif
+
+#ifdef MINGW
+ char *binaryexe;
+ GNUNET_asprintf (&binaryexe, "%s.exe", binary);
+ p = get_path_from_PATH (binaryexe);
+ free (binaryexe);
+#else
+ p = get_path_from_PATH (binary);
+#endif
+ if (p == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not find binary `%s' in PATH!\n"),
+ binary);
+ return GNUNET_NO;
+ }
+ if (0 != STAT (p, &statbuf))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("stat (%s) failed: %s\n"),
+ p,
+ STRERROR (errno));
+ GNUNET_free (p);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (p);
+#ifndef MINGW
+ if ( (0 != (statbuf.st_mode & S_ISUID)) &&
+ (statbuf.st_uid == 0) )
+ return GNUNET_YES;
+ return GNUNET_NO;
+#else
+ rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (INVALID_SOCKET == rawsock)
+ {
+ DWORD err = GetLastError ();
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) have failed! GLE = %d\n", err);
+ return GNUNET_NO; /* not running as administrator */
+ }
+ closesocket (rawsock);
+ return GNUNET_YES;
+#endif
+}
+
+static void
+run (void *cls,
+ char *const *args,
+ const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ GNUNET_assert (ok == 1);
+ OKPP;
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
+ &end_badly,
+ NULL);
+ if (is_tcp)
+ {
+ setup_peer (&p1, "test_transport_api_tcp_peer1.conf");
+ setup_peer (&p2, "test_transport_api_tcp_peer2.conf");
+ }
+ else if (is_http)
+ {
+ setup_peer (&p1, "test_transport_api_rel_http_peer1.conf");
+ setup_peer (&p2, "test_transport_api_rel_http_peer2.conf");
+ }
+ else if (is_https)
+ {
+ setup_peer (&p1, "test_transport_api_rel_https_peer1.conf");
+ setup_peer (&p2, "test_transport_api_rel_https_peer2.conf");
+ }
+ else if (is_udp)
+ {
+ setup_peer (&p1, "test_transport_api_udp_peer1.conf");
+ setup_peer (&p2, "test_transport_api_udp_peer2.conf");
+ }
+ else if (is_unix)
+ {
+ setup_peer (&p1, "test_transport_api_unix_peer1.conf");
+ setup_peer (&p2, "test_transport_api_unix_peer2.conf");
+ }
+ else if (is_tcp_nat)
+ {
+ setup_peer (&p1, "test_transport_api_tcp_nat_peer1.conf");
+ setup_peer (&p2, "test_transport_api_tcp_nat_peer2.conf");
+ }
+ else
+ GNUNET_assert (0);
+ GNUNET_assert(p1.th != NULL);
+ GNUNET_assert(p2.th != NULL);
+ GNUNET_TRANSPORT_get_hello (p1.th, &exchange_hello, &p1);
+}
+
+
+static int
+check ()
+{
+ char *const argv[] = { "test-transport-api-reliability",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions("test_transport_api_data.conf");
+#endif
+ ok = 1;
+
+ if ((GNUNET_YES == is_tcp_nat) && (check_gnunet_nat_binary("gnunet-nat-server") != GNUNET_YES))
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Not running NAT test case, binaries not properly installed.\n");
+ return 0;
+ }
+
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
+ argv, "test-transport-api-reliability", "nohelp",
+ options, &run, &ok);
+ stop_arm (&p1);
+ stop_arm (&p2);
+
+ if (is_https)
+ {
+ struct stat sbuf;
+ if (0 == stat (cert_file_p1, &sbuf ))
+ {
+ if (0 == remove(cert_file_p1))
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully removed existing certificate file `%s'\n",cert_file_p1);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove certfile `%s'\n",cert_file_p1);
+ }
+
+ if (0 == stat (key_file_p1, &sbuf ))
+ {
+ if (0 == remove(key_file_p1))
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully removed private key file `%s'\n",key_file_p1);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to private key file `%s'\n",key_file_p1);
+ }
+
+ if (0 == stat (cert_file_p2, &sbuf ))
+ {
+ if (0 == remove(cert_file_p2))
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully removed existing certificate file `%s'\n",cert_file_p2);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove certfile `%s'\n",cert_file_p2);
+ }
+
+ if (0 == stat (key_file_p2, &sbuf ))
+ {
+ if (0 == remove(key_file_p2))
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully removed private key file `%s'\n",key_file_p2);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to private key file `%s'\n",key_file_p2);
+ }
+ GNUNET_free(key_file_p1);
+ GNUNET_free(key_file_p2);
+ GNUNET_free(cert_file_p1);
+ GNUNET_free(cert_file_p2);
+ }
+
+ return ok;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+#ifdef MINGW
+ return GNUNET_SYSERR;
+#endif
+
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-1");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-2");
+
+ if (strstr(argv[0], "tcp_nat") != NULL)
+ {
+ is_tcp_nat = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "tcp_nat");
+ }
+ else if (strstr(argv[0], "tcp") != NULL)
+ {
+ is_tcp = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "tcp");
+ }
+ else if (strstr(argv[0], "https") != NULL)
+ {
+ is_https = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "https");
+ }
+ else if (strstr(argv[0], "http") != NULL)
+ {
+ is_http = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "http");
+ }
+ else if (strstr(argv[0], "udp") != NULL)
+ {
+ is_udp = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "udp");
+ }
+ else if (strstr(argv[0], "unix") != NULL)
+ {
+ is_unix = GNUNET_YES;
+ GNUNET_asprintf(&test_name, "unix");
+ }
+ GNUNET_log_setup ("test-transport-api-reliability",
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+ ret = check ();
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-1");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-2");
+ GNUNET_free_non_null(test_name);
+ return ret;
+}
+
+/* end of test_transport_api_reliability.c */