From 7a441138e549ac5bbc1974a23653bb77c51a8bb1 Mon Sep 17 00:00:00 2001 From: "Nathan S. Evans" Date: Thu, 3 Feb 2011 16:11:49 +0000 Subject: unix domain socket transport, associated test cases --- src/transport/Makefile.am | 84 +- src/transport/plugin_transport_udp.c | 2 + src/transport/plugin_transport_unix.c | 1155 ++++++++++++++++++++ src/transport/test_quota_compliance.c | 25 + .../test_quota_compliance_unix_peer1.conf | 104 ++ .../test_quota_compliance_unix_peer2.conf | 102 ++ src/transport/test_transport_api.c | 12 + src/transport/test_transport_api_reliability.c | 24 +- src/transport/test_transport_api_unix_peer1.conf | 110 ++ src/transport/test_transport_api_unix_peer2.conf | 108 ++ src/transport/test_transport_api_unreliability.c | 922 ++++++++++++++++ 11 files changed, 2632 insertions(+), 16 deletions(-) create mode 100644 src/transport/plugin_transport_unix.c create mode 100644 src/transport/test_quota_compliance_unix_peer1.conf create mode 100644 src/transport/test_quota_compliance_unix_peer2.conf create mode 100644 src/transport/test_transport_api_unix_peer1.conf create mode 100644 src/transport/test_transport_api_unix_peer2.conf create mode 100644 src/transport/test_transport_api_unreliability.c (limited to 'src/transport') diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 0498408f2..c3b90cc9d 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -43,6 +43,10 @@ endif 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 @@ -114,6 +118,7 @@ gnunet_service_transport_DEPENDENCIES = \ plugin_LTLIBRARIES = \ libgnunet_plugin_transport_tcp.la \ libgnunet_plugin_transport_udp.la \ + $(UNIX_PLUGIN_LA) \ $(HTTP_PLUGIN_LA) \ $(HTTPS_PLUGIN_LA) \ $(WLAN_PLUGIN_LA) \ @@ -157,16 +162,16 @@ libgnunet_plugin_transport_udp_la_LIBADD = \ $(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 @@ -199,6 +204,7 @@ check_PROGRAMS = \ 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) \ @@ -208,13 +214,16 @@ check_PROGRAMS = \ 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. @@ -224,6 +233,7 @@ TESTS = \ 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) \ @@ -233,12 +243,15 @@ TESTS = \ 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 @@ -271,19 +284,31 @@ test_transport_api_reliability_udp_SOURCES = \ 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 @@ -324,6 +349,18 @@ test_transport_api_reliability_https_SOURCES = \ 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 @@ -407,6 +444,19 @@ test_quota_compliance_udp_asymmetric_recv_constant_LDADD = \ # $(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 = \ @@ -419,6 +469,8 @@ EXTRA_DIST = \ 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 \ @@ -446,4 +498,6 @@ EXTRA_DIST = \ 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 diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c index 21f2b17d7..ca6bbe138 100644 --- a/src/transport/plugin_transport_udp.c +++ b/src/transport/plugin_transport_udp.c @@ -662,6 +662,8 @@ udp_real_send (void *cls, 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, diff --git a/src/transport/plugin_transport_unix.c b/src/transport/plugin_transport_unix.c new file mode 100644 index 000000000..4d08a252b --- /dev/null +++ b/src/transport/plugin_transport_unix.c @@ -0,0 +1,1155 @@ +/* + 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 */ diff --git a/src/transport/test_quota_compliance.c b/src/transport/test_quota_compliance.c index 767ada25e..20a9b1f15 100644 --- a/src/transport/test_quota_compliance.c +++ b/src/transport/test_quota_compliance.c @@ -139,6 +139,7 @@ static int is_tcp_nat; 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; @@ -731,6 +732,17 @@ run (void *cls, 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) @@ -777,6 +789,10 @@ main (int argc, char *argv[]) { is_udp = GNUNET_YES; } + else if (strstr(argv[0], "unix") != NULL) + { + is_unix = GNUNET_YES; + } if (strstr(argv[0], "asymmetric_recv") != NULL) { @@ -810,6 +826,15 @@ main (int argc, char *argv[]) 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) diff --git a/src/transport/test_quota_compliance_unix_peer1.conf b/src/transport/test_quota_compliance_unix_peer1.conf new file mode 100644 index 000000000..ff8ef0537 --- /dev/null +++ b/src/transport/test_quota_compliance_unix_peer1.conf @@ -0,0 +1,104 @@ +[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 + + diff --git a/src/transport/test_quota_compliance_unix_peer2.conf b/src/transport/test_quota_compliance_unix_peer2.conf new file mode 100644 index 000000000..7be68cbbe --- /dev/null +++ b/src/transport/test_quota_compliance_unix_peer2.conf @@ -0,0 +1,102 @@ +[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 + + diff --git a/src/transport/test_transport_api.c b/src/transport/test_transport_api.c index 3b528d84d..60cb7866f 100644 --- a/src/transport/test_transport_api.c +++ b/src/transport/test_transport_api.c @@ -76,6 +76,8 @@ static int is_tcp_nat; static int is_udp; +static int is_unix; + static int is_udp_nat; static int is_http; @@ -369,6 +371,12 @@ run (void *cls, 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"); @@ -634,6 +642,10 @@ main (int argc, char *argv[]) { 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; diff --git a/src/transport/test_transport_api_reliability.c b/src/transport/test_transport_api_reliability.c index 414a8cdd6..306e88ed8 100644 --- a/src/transport/test_transport_api_reliability.c +++ b/src/transport/test_transport_api_reliability.c @@ -34,6 +34,7 @@ #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 @@ -82,6 +83,8 @@ static int is_https; static int is_udp; +static int is_unix; + static int connected; static unsigned long long total_bytes; @@ -95,7 +98,7 @@ static char * cert_file_p1; 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; @@ -113,6 +116,7 @@ static void end () { unsigned long long delta; + char *value_name; GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; @@ -129,6 +133,9 @@ end () 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; } @@ -665,6 +672,11 @@ run (void *cls, 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"); @@ -768,22 +780,32 @@ main (int argc, char *argv[]) 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 diff --git a/src/transport/test_transport_api_unix_peer1.conf b/src/transport/test_transport_api_unix_peer1.conf new file mode 100644 index 000000000..e1e5a7f57 --- /dev/null +++ b/src/transport/test_transport_api_unix_peer1.conf @@ -0,0 +1,110 @@ +[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 + + diff --git a/src/transport/test_transport_api_unix_peer2.conf b/src/transport/test_transport_api_unix_peer2.conf new file mode 100644 index 000000000..c297ef20e --- /dev/null +++ b/src/transport/test_transport_api_unix_peer2.conf @@ -0,0 +1,108 @@ +[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 + + diff --git a/src/transport/test_transport_api_unreliability.c b/src/transport/test_transport_api_unreliability.c new file mode 100644 index 000000000..caafdbc5d --- /dev/null +++ b/src/transport/test_transport_api_unreliability.c @@ -0,0 +1,922 @@ +/* + 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 */ -- cgit v1.2.3