diff options
Diffstat (limited to 'src/transport')
65 files changed, 7348 insertions, 6817 deletions
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 0692450..b040874 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -61,7 +61,6 @@ UNIX_QUOTA_TEST = test_quota_compliance_unix \ endif noinst_PROGRAMS = \ - $(WLAN_BIN_DUMMY) \ $(WLAN_BIN_SENDER) # gnunet-transport-connect-running-peers @@ -92,11 +91,12 @@ libgnunettransport_la_LIBADD = \ $(GN_LIBINTL) libgnunettransport_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ - -version-info 0:0:0 + -version-info 1:0:0 bin_PROGRAMS = \ gnunet-transport \ $(WLAN_BIN) \ + $(WLAN_BIN_DUMMY) \ gnunet-service-transport \ gnunet-transport-certificate-creation diff --git a/src/transport/Makefile.in b/src/transport/Makefile.in index 36df686..b5f2c64 100644 --- a/src/transport/Makefile.in +++ b/src/transport/Makefile.in @@ -37,9 +37,9 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ -noinst_PROGRAMS = $(am__EXEEXT_21) $(am__EXEEXT_22) +noinst_PROGRAMS = $(am__EXEEXT_22) bin_PROGRAMS = gnunet-transport$(EXEEXT) $(am__EXEEXT_1) \ - gnunet-service-transport$(EXEEXT) \ + $(am__EXEEXT_2) gnunet-service-transport$(EXEEXT) \ gnunet-transport-certificate-creation$(EXEEXT) check_PROGRAMS = test_transport_testing$(EXEEXT) \ test_transport_startonly$(EXEEXT) \ @@ -53,22 +53,22 @@ check_PROGRAMS = test_transport_testing$(EXEEXT) \ test_transport_api_limited_sockets_tcp$(EXEEXT) \ test_transport_api_tcp_nat$(EXEEXT) \ test_transport_api_udp$(EXEEXT) \ - test_transport_api_timeout_udp$(EXEEXT) $(am__EXEEXT_2) \ - $(am__EXEEXT_3) test_transport_api_udp_nat$(EXEEXT) \ - $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \ - $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \ + test_transport_api_timeout_udp$(EXEEXT) $(am__EXEEXT_3) \ + $(am__EXEEXT_4) test_transport_api_udp_nat$(EXEEXT) \ + $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) \ + $(am__EXEEXT_8) $(am__EXEEXT_9) $(am__EXEEXT_10) \ test_transport_api_multi$(EXEEXT) \ test_transport_api_reliability_tcp$(EXEEXT) \ test_transport_api_reliability_tcp_nat$(EXEEXT) \ test_transport_api_unreliability_udp$(EXEEXT) \ test_transport_api_unreliability_constant_udp$(EXEEXT) \ - $(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \ - $(am__EXEEXT_13) $(am__EXEEXT_14) \ + $(am__EXEEXT_11) $(am__EXEEXT_12) $(am__EXEEXT_13) \ + $(am__EXEEXT_14) $(am__EXEEXT_15) \ test_quota_compliance_tcp$(EXEEXT) \ test_quota_compliance_tcp_asymmetric$(EXEEXT) \ - test_quota_compliance_udp$(EXEEXT) $(am__EXEEXT_15) \ - $(am__EXEEXT_16) $(am__EXEEXT_17) $(am__EXEEXT_18) \ - $(am__EXEEXT_19) $(am__EXEEXT_20) + test_quota_compliance_udp$(EXEEXT) $(am__EXEEXT_16) \ + $(am__EXEEXT_17) $(am__EXEEXT_18) $(am__EXEEXT_19) \ + $(am__EXEEXT_20) $(am__EXEEXT_21) @ENABLE_TEST_RUN_TRUE@TESTS = test_transport_testing$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_startonly$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_blacklisting$(EXEEXT) \ @@ -82,25 +82,25 @@ check_PROGRAMS = test_transport_testing$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_tcp_nat$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_udp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_timeout_udp$(EXEEXT) \ -@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_2) $(am__EXEEXT_3) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_3) $(am__EXEEXT_4) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_udp_nat$(EXEEXT) \ -@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_4) $(am__EXEEXT_5) \ -@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_6) $(am__EXEEXT_7) \ -@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_8) $(am__EXEEXT_9) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_5) $(am__EXEEXT_6) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_7) $(am__EXEEXT_8) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_9) $(am__EXEEXT_10) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_multi$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_reliability_tcp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_reliability_tcp_nat$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_unreliability_udp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_unreliability_constant_udp$(EXEEXT) \ -@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_10) $(am__EXEEXT_11) \ -@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_12) $(am__EXEEXT_13) \ -@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_14) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_11) $(am__EXEEXT_12) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_13) $(am__EXEEXT_14) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_15) \ @ENABLE_TEST_RUN_TRUE@ test_quota_compliance_tcp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_quota_compliance_tcp_asymmetric$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_quota_compliance_udp$(EXEEXT) \ -@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_15) $(am__EXEEXT_16) \ -@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_17) $(am__EXEEXT_18) \ -@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_19) $(am__EXEEXT_20) +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_16) $(am__EXEEXT_17) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_18) $(am__EXEEXT_19) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_20) $(am__EXEEXT_21) subdir = src/transport DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/transport.conf.in @@ -279,37 +279,37 @@ libgnunettransporttesting_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_CFLAGS) $(CFLAGS) $(libgnunettransporttesting_la_LDFLAGS) \ $(LDFLAGS) -o $@ @LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-transport-wlan$(EXEEXT) -@MINGW_FALSE@am__EXEEXT_2 = test_transport_api_unix$(EXEEXT) -@MINGW_FALSE@am__EXEEXT_3 = test_transport_api_timeout_unix$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_4 = test_transport_api_http$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_5 = test_transport_api_http_nat$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_6 = \ +@LINUX_TRUE@am__EXEEXT_2 = \ +@LINUX_TRUE@ gnunet-helper-transport-wlan-dummy$(EXEEXT) +@MINGW_FALSE@am__EXEEXT_3 = test_transport_api_unix$(EXEEXT) +@MINGW_FALSE@am__EXEEXT_4 = test_transport_api_timeout_unix$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_5 = test_transport_api_http$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_6 = test_transport_api_http_nat$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_7 = \ @HAVE_MHD_TRUE@ test_transport_api_timeout_http$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_7 = test_transport_api_https$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_8 = test_transport_api_https_nat$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_9 = \ +@HAVE_MHD_TRUE@am__EXEEXT_8 = test_transport_api_https$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_9 = test_transport_api_https_nat$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_10 = \ @HAVE_MHD_TRUE@ test_transport_api_timeout_https$(EXEEXT) -@MINGW_FALSE@am__EXEEXT_10 = \ +@MINGW_FALSE@am__EXEEXT_11 = \ @MINGW_FALSE@ test_transport_api_unreliability_unix$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_11 = \ +@HAVE_MHD_TRUE@am__EXEEXT_12 = \ @HAVE_MHD_TRUE@ test_transport_api_reliability_http$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_12 = test_transport_api_reliability_http_nat$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_13 = \ +@HAVE_MHD_TRUE@am__EXEEXT_13 = test_transport_api_reliability_http_nat$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_14 = \ @HAVE_MHD_TRUE@ test_transport_api_reliability_https$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_14 = test_transport_api_reliability_https_nat$(EXEEXT) -@MINGW_FALSE@am__EXEEXT_15 = test_quota_compliance_unix$(EXEEXT) \ +@HAVE_MHD_TRUE@am__EXEEXT_15 = test_transport_api_reliability_https_nat$(EXEEXT) +@MINGW_FALSE@am__EXEEXT_16 = test_quota_compliance_unix$(EXEEXT) \ @MINGW_FALSE@ test_quota_compliance_unix_asymmetric$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_16 = test_quota_compliance_http$(EXEEXT) \ +@HAVE_MHD_TRUE@am__EXEEXT_17 = test_quota_compliance_http$(EXEEXT) \ @HAVE_MHD_TRUE@ test_quota_compliance_http_asymmetric$(EXEEXT) -@HAVE_MHD_TRUE@am__EXEEXT_17 = test_quota_compliance_https$(EXEEXT) \ +@HAVE_MHD_TRUE@am__EXEEXT_18 = test_quota_compliance_https$(EXEEXT) \ @HAVE_MHD_TRUE@ test_quota_compliance_https_asymmetric$(EXEEXT) -@LINUX_TRUE@am__EXEEXT_18 = test_transport_api_wlan$(EXEEXT) -@LINUX_TRUE@am__EXEEXT_19 = \ -@LINUX_TRUE@ test_transport_api_reliability_wlan$(EXEEXT) +@LINUX_TRUE@am__EXEEXT_19 = test_transport_api_wlan$(EXEEXT) @LINUX_TRUE@am__EXEEXT_20 = \ -@LINUX_TRUE@ test_transport_api_unreliability_wlan$(EXEEXT) +@LINUX_TRUE@ test_transport_api_reliability_wlan$(EXEEXT) @LINUX_TRUE@am__EXEEXT_21 = \ -@LINUX_TRUE@ gnunet-helper-transport-wlan-dummy$(EXEEXT) +@LINUX_TRUE@ test_transport_api_unreliability_wlan$(EXEEXT) @LINUX_TRUE@am__EXEEXT_22 = gnunet-transport-wlan-sender$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am_gnunet_helper_transport_wlan_OBJECTS = \ @@ -947,6 +947,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ @@ -980,6 +981,7 @@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ +MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ @@ -1169,7 +1171,7 @@ libgnunettransport_la_LIBADD = \ libgnunettransport_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ - -version-info 0:0:0 + -version-info 1:0:0 #bin_SCRIPTS = \ diff --git a/src/transport/gnunet-helper-transport-wlan-dummy.c b/src/transport/gnunet-helper-transport-wlan-dummy.c index 6fff758..a7015ac 100644 --- a/src/transport/gnunet-helper-transport-wlan-dummy.c +++ b/src/transport/gnunet-helper-transport-wlan-dummy.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2010 Christian Grothoff (and other contributing authors) + (C) 2010, 2012 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 @@ -27,22 +27,60 @@ #include "gnunet_util_lib.h" #include "plugin_transport_wlan.h" -#define FIFO_FILE1 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_in" -#define FIFO_FILE2 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_out" +/** + * Name of the fifo to use for IPC with the other dummy process. + */ +#define FIFO_FILE1 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_in" + +/** + * Name of the fifo to use for IPC with the other dummy process. + */ +#define FIFO_FILE2 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_out" +/** + * Maximum size of a message allowed in either direction + * (used for our receive and sent buffers). + */ #define MAXLINE 4096 -struct sendbuf + +/** + * IO buffer used for buffering data in transit. + */ +struct SendBuffer { - unsigned int pos; - unsigned int size; + + /** + * How many bytes that were stored in 'buf' did we already write to the + * destination? Always smaller than 'size'. + */ + size_t pos; + + /** + * How many bytes of data are stored in 'buf' for transmission right now? + * Data always starts at offset 0 and extends to 'size'. + */ + size_t size; + + /** + * Buffered data; twice the maximum allowed message size as we add some + * headers. + */ char buf[MAXLINE * 2]; }; -static int first; +/** + * Flag set to 1 if we are to terminate, otherwise 0. + */ static int closeprog; + +/** + * We're being killed, clean up. + * + * @param sig killing signal + */ static void sigfunc (int sig) { @@ -53,7 +91,8 @@ sigfunc (int sig) /** - * function to create GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL message for plugin + * Create control message for plugin + * * @param buffer pointer to buffer for the message * @param mac pointer to the mac address * @return number of bytes written @@ -67,83 +106,90 @@ send_mac_to_plugin (char *buffer, struct GNUNET_TRANSPORT_WLAN_MacAddress *mac) memcpy (&macmsg.mac, (char *) mac, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); macmsg.hdr.size = htons (sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage)); macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL); - memcpy (buffer, &macmsg, sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage)); return sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage); } -static void + +/** + * We got a message from the FIFO, check it, convert the message + * type to the output forward and copy it to the buffer for stdout. + * + * @param cls the 'struct SendBuffer' to copy the converted message to + * @param client unused + * @param hdr inbound message from the FIFO + */ +static int stdin_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) { - struct sendbuf *write_pout = cls; - int sendsize; - struct GNUNET_MessageHeader newheader; - char *to_data; - char *to_radiotap; - char *to_start; - - sendsize = - ntohs (hdr->size) - sizeof (struct Radiotap_Send) + - sizeof (struct Radiotap_rx); - - if (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA != ntohs (hdr->type)) + struct SendBuffer *write_pout = cls; + const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *in; + size_t payload_size; + struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage newheader; + uint16_t sendsize; + + sendsize = ntohs (hdr->size); + in = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr; + if ( (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)) || + (sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) > sendsize) ) { - fprintf (stderr, "Function stdin_send: wrong packet type\n"); + FPRINTF (stderr, "%s", "Received malformed message\n"); exit (1); } - if ((sendsize + write_pout->size) > MAXLINE * 2) + payload_size = sendsize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage); + if ((payload_size + sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage) + write_pout->size) > MAXLINE * 2) { - fprintf (stderr, "Function stdin_send: Packet too big for buffer\n"); + FPRINTF (stderr, "%s", "Packet too big for buffer\n"); exit (1); } - - newheader.size = htons (sendsize); - newheader.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); - - to_start = write_pout->buf + write_pout->size; - memcpy (to_start, &newheader, sizeof (struct GNUNET_MessageHeader)); - write_pout->size += sizeof (struct GNUNET_MessageHeader); - - to_radiotap = to_start + sizeof (struct GNUNET_MessageHeader); - memset (to_radiotap, 0, sizeof (struct Radiotap_rx)); - write_pout->size += sizeof (struct Radiotap_rx); - - to_data = to_radiotap + sizeof (struct Radiotap_rx); - memcpy (to_data, - ((char *) hdr) + sizeof (struct Radiotap_Send) + - sizeof (struct GNUNET_MessageHeader), - ntohs (hdr->size) - sizeof (struct Radiotap_Send) - - sizeof (struct GNUNET_MessageHeader)); - write_pout->size += - ntohs (hdr->size) - sizeof (struct Radiotap_Send) - - sizeof (struct GNUNET_MessageHeader); + memset (&newheader, 0, sizeof (newheader)); + newheader.header.size = htons (payload_size + sizeof (newheader)); + newheader.header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER); + newheader.frame = in->frame; + memcpy (write_pout->buf + write_pout->size, + &newheader, + sizeof (newheader)); + write_pout->size += sizeof (newheader); + memcpy (write_pout->buf + write_pout->size, + &in[1], + payload_size); + write_pout->size += payload_size; + return GNUNET_OK; } -static void +/** + * We read a full message from stdin. Copy it to our send buffer. + * + * @param cls the 'struct SendBuffer' to copy to + * @param client unused + * @param hdr the message we received to copy to the buffer + */ +static int file_in_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) { - struct sendbuf *write_std = cls; + struct SendBuffer *write_std = cls; uint16_t sendsize; sendsize = ntohs (hdr->size); - - if (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA != ntohs (hdr->type)) - { - fprintf (stderr, "Function file_in_send: wrong packet type\n"); - exit (1); - } if ((sendsize + write_std->size) > MAXLINE * 2) { - fprintf (stderr, "Function file_in_send: Packet too big for buffer\n"); + FPRINTF (stderr, "%s", "Packet too big for buffer\n"); exit (1); } - memcpy (write_std->buf + write_std->size, hdr, sendsize); write_std->size += sendsize; + return GNUNET_OK; } +/** + * Main function of a program that pretends to be a WLAN card. + * + * @param argc should be 2 + * @param argv either '1' or '2', depending on which of the two cards this dummy is to emulate + * @return 1 on error, 0 if terminated normally via signal + */ int main (int argc, char *argv[]) { @@ -154,105 +200,104 @@ main (int argc, char *argv[]) int fdpin; int fdpout; char readbuf[MAXLINE]; - int readsize = 0; - struct sendbuf write_std; - struct sendbuf write_pout; - int ret = 0; - int maxfd = 0; + int readsize; + struct SendBuffer write_std; + struct SendBuffer write_pout; + int ret; + int maxfd; fd_set rfds; fd_set wfds; struct timeval tv; int retval; - struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst; - struct GNUNET_SERVER_MessageStreamTokenizer *file_in_mst; + struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst = NULL; + struct GNUNET_SERVER_MessageStreamTokenizer *file_in_mst = NULL; struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr; + int first; - if (2 != argc) + if ( (2 != argc) || + ((0 != strcmp (argv[1], "1")) && (0 != strcmp (argv[1], "2"))) ) { - fprintf (stderr, - "This program must be started with the operating mode (1 or 2) as the only argument.\n"); + FPRINTF (stderr, + "%s", + "This program must be started with the operating mode (1 or 2) as the only argument.\n"); return 1; } - if ((0 != strstr (argv[1], "1")) && (0 != strstr (argv[1], "2"))) - return 1; - //make the fifos if needed - if (0 != stat (FIFO_FILE1, &st)) + /* make the fifos if needed */ + umask (0); + if ( (GNUNET_OK != GNUNET_DISK_directory_create_for_file (FIFO_FILE1)) || + (GNUNET_OK != GNUNET_DISK_directory_create_for_file (FIFO_FILE2)) ) { - if (0 == stat (FIFO_FILE2, &st)) - { - fprintf (stderr, "FIFO_FILE2 exists, but FIFO_FILE1 not\n"); - exit (1); - } - umask (0); - erg = mkfifo (FIFO_FILE1, 0666); - if (0 != erg) - { - fprintf (stderr, "Error in mkfifo(%s): %s\n", FIFO_FILE1, - strerror (errno)); - //exit(1); - } - erg = mkfifo (FIFO_FILE2, 0666); - if (0 != erg) + FPRINTF (stderr, "Failed to create directory for file `%s'\n", FIFO_FILE1); + return 1; + } + if (0 == strcmp (argv[1], "1") ) + { + if (0 != stat (FIFO_FILE1, &st)) { - fprintf (stderr, "Error in mkfifo(%s): %s\n", FIFO_FILE2, - strerror (errno)); - //exit(1); + erg = mkfifo (FIFO_FILE1, 0666); + if ( (0 != erg) && (EEXIST != errno) ) + FPRINTF (stderr, "Error in mkfifo(%s): %s\n", FIFO_FILE1, + strerror (errno)); } - } else { if (0 != stat (FIFO_FILE2, &st)) { - fprintf (stderr, "FIFO_FILE1 exists, but FIFO_FILE2 not\n"); - exit (1); + erg = mkfifo (FIFO_FILE2, 0666); + if ( (0 != erg) && (EEXIST != errno) ) + FPRINTF (stderr, "Error in mkfifo(%s): %s\n", FIFO_FILE2, + strerror (errno)); } } - if (strstr (argv[1], "1")) + if (0 == strcmp (argv[1], "1")) { - //fprintf(stderr, "First\n"); first = 1; fpin = fopen (FIFO_FILE1, "r"); if (NULL == fpin) { - fprintf (stderr, "fopen of read FIFO_FILE1\n"); + FPRINTF (stderr, "fopen of read FIFO_FILE1 failed: %s\n", STRERROR (errno)); goto end; } - fpout = fopen (FIFO_FILE2, "w"); + if (NULL == (fpout = fopen (FIFO_FILE2, "w"))) + { + erg = mkfifo (FIFO_FILE2, 0666); + fpout = fopen (FIFO_FILE2, "w"); + } if (NULL == fpout) { - fprintf (stderr, "fopen of write FIFO_FILE2\n"); + FPRINTF (stderr, "fopen of write FIFO_FILE2 failed: %s\n", STRERROR (errno)); goto end; } - } else { first = 0; - //fprintf(stderr, "Second\n"); - fpout = fopen (FIFO_FILE1, "w"); + if (NULL == (fpout = fopen (FIFO_FILE1, "w"))) + { + erg = mkfifo (FIFO_FILE1, 0666); + fpout = fopen (FIFO_FILE1, "w"); + } if (NULL == fpout) { - fprintf (stderr, "fopen of write FIFO_FILE1\n"); + FPRINTF (stderr, "fopen of write FIFO_FILE1 failed: %s\n", STRERROR (errno)); goto end; } fpin = fopen (FIFO_FILE2, "r"); if (NULL == fpin) { - fprintf (stderr, "fopen of read FIFO_FILE2\n"); + FPRINTF (stderr, "fopen of read FIFO_FILE2 failed: %s\n", STRERROR (errno)); goto end; } - } fdpin = fileno (fpin); GNUNET_assert (fpin >= 0); - if (fdpin >= FD_SETSIZE) { - fprintf (stderr, "File fdpin number too large (%d > %u)\n", fdpin, + FPRINTF (stderr, "File fdpin number too large (%d > %u)\n", fdpin, (unsigned int) FD_SETSIZE); goto end; } @@ -262,10 +307,9 @@ main (int argc, char *argv[]) if (fdpout >= FD_SETSIZE) { - fprintf (stderr, "File fdpout number too large (%d > %u)\n", fdpout, + FPRINTF (stderr, "File fdpout number too large (%d > %u)\n", fdpout, (unsigned int) FD_SETSIZE); goto end; - } signal (SIGINT, &sigfunc); @@ -278,7 +322,7 @@ main (int argc, char *argv[]) stdin_mst = GNUNET_SERVER_mst_create (&stdin_send, &write_pout); file_in_mst = GNUNET_SERVER_mst_create (&file_in_send, &write_std); - //Send random mac address + /* Send 'random' mac address */ macaddr.mac[0] = 0x13; macaddr.mac[1] = 0x22; macaddr.mac[2] = 0x33; @@ -290,12 +334,12 @@ main (int argc, char *argv[]) while (0 == closeprog) { maxfd = -1; - //set timeout tv.tv_sec = 5; tv.tv_usec = 0; FD_ZERO (&rfds); - // if output queue is empty + FD_ZERO (&wfds); + /* if output queue is empty, read */ if (0 == write_pout.size) { FD_SET (STDIN_FILENO, &rfds); @@ -306,8 +350,8 @@ main (int argc, char *argv[]) FD_SET (fdpin, &rfds); maxfd = MAX (fdpin, maxfd); } - FD_ZERO (&wfds); - // if there is something to write + + /* if there is something to write, try to write */ if (0 < write_std.size) { FD_SET (STDOUT_FILENO, &wfds); @@ -324,7 +368,7 @@ main (int argc, char *argv[]) continue; if (0 > retval) { - fprintf (stderr, "select failed: %s\n", strerror (errno)); + FPRINTF (stderr, "select failed: %s\n", STRERROR (errno)); closeprog = 1; break; } @@ -337,14 +381,14 @@ main (int argc, char *argv[]) if (0 > ret) { closeprog = 1; - fprintf (stderr, "Write ERROR to STDOUT_FILENO: %s\n", - strerror (errno)); + FPRINTF (stderr, "Write ERROR to STDOUT_FILENO: %s\n", + STRERROR (errno)); break; } else { write_std.pos += ret; - // check if finished + /* check if finished writing */ if (write_std.pos == write_std.size) { write_std.pos = 0; @@ -362,12 +406,12 @@ main (int argc, char *argv[]) if (0 > ret) { closeprog = 1; - fprintf (stderr, "Write ERROR to fdpout: %s\n", strerror (errno)); + FPRINTF (stderr, "Write ERROR to fdpout failed: %s\n", STRERROR (errno)); } else { write_pout.pos += ret; - // check if finished + /* check if finished writing */ if (write_pout.pos == write_pout.size) { write_pout.pos = 0; @@ -383,8 +427,8 @@ main (int argc, char *argv[]) if (0 > readsize) { closeprog = 1; - fprintf (stderr, "Error reading from STDIN_FILENO: %s\n", - strerror (errno)); + FPRINTF (stderr, "Error reading from STDIN_FILENO: %s\n", + STRERROR (errno)); } else if (0 < readsize) { @@ -394,7 +438,7 @@ main (int argc, char *argv[]) } else { - //eof + /* eof */ closeprog = 1; } } @@ -405,7 +449,7 @@ main (int argc, char *argv[]) if (0 > readsize) { closeprog = 1; - fprintf (stderr, "Error reading from fdpin: %s\n", strerror (errno)); + FPRINTF (stderr, "Error reading from fdpin: %s\n", STRERROR (errno)); break; } else if (0 < readsize) @@ -415,20 +459,22 @@ main (int argc, char *argv[]) } else { - //eof + /* eof */ closeprog = 1; } } } - //clean up - GNUNET_SERVER_mst_destroy (stdin_mst); - GNUNET_SERVER_mst_destroy (file_in_mst); - end: - if (fpout != NULL) + /* clean up */ + if (NULL != stdin_mst) + GNUNET_SERVER_mst_destroy (stdin_mst); + if (NULL != file_in_mst) + GNUNET_SERVER_mst_destroy (file_in_mst); + + if (NULL != fpout) fclose (fpout); - if (fpin != NULL) + if (NULL != fpin) fclose (fpin); if (1 == first) { diff --git a/src/transport/gnunet-helper-transport-wlan.c b/src/transport/gnunet-helper-transport-wlan.c index 582df7c..363925c 100644 --- a/src/transport/gnunet-helper-transport-wlan.c +++ b/src/transport/gnunet-helper-transport-wlan.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2010, 2011 Christian Grothoff (and other contributing authors) + (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors) Copyright (c) 2007, 2008, Andy Green <andy@warmcat.com> Copyright (C) 2009 Thomas d'Otreppe @@ -21,12 +21,48 @@ */ /** * @file src/transport/gnunet-helper-transport-wlan.c - * @brief wlan layer two server; must run as root (SUID will do) + * @brief mediator between the wlan interface and gnunet; must run as root (SUID will do) * This code will work under GNU/Linux only. * @author David Brodski + * @author Christian Grothoff * - * This program serves as the mediator between the wlan interface and - * gnunet + * This program will allow receiving and sending traffic from the WLAN + * interface. It will force traffic to be in 'ad-hoc' mode, use the + * proper MAC address of the WLAN interface and use a GNUnet-specific + * SSID (and a GNUnet-specific SNAP header). It only takes a single + * argument, which is the name of the WLAN interface to use. The + * program detects if the interface is not a WLAN interface and exits + * with an error in that case. + * + * Once initialized, the program will first send a 'struct + * GNUNET_TRANSPORT_WLAN_HelperControlMessage' to 'stdout'. That + * message contains the MAC address of the WLAN interface. It will + * then read messages from the WLAN interface and send them together + * with performance information as 'struct + * GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage' messages to 'stdout'. + * Furthermore, it will read a stream of messages from 'stdin' that + * have the format from 'struct + * GNUNET_TRANSPORT_WLAN_RadiotapSendMessage'. Those messages will + * then be sent via the WLAN interface; however, the sender MAC + * address will be forced to be the correct address from our WLAN + * card. If 'stdin' closes, receiving from the WLAN interface will + * continue. If 'stdout' causes a SIGPIPE, the process dies from the + * signal. Errors cause an error message to be reported to 'stderr', + * in most cases the process also exits (with status code '1'). The + * program never terminates normally; it is safe to kill the + * process with SIGTERM or SIGKILL at any time. + * + * Since it uses RAW sockets, the binary must be installed SUID or run + * as 'root'. In order to keep the security risk of the resulting + * SUID binary minimal, the program ONLY opens the RAW socket with + * root privileges, then drops them and only then starts to process + * command line arguments. The code also does not link against any + * shared libraries (except libc) and is strictly minimal (except for + * checking for errors). The following list of people have reviewed + * this code and considered it safe since the last modification (if + * you reviewed it, please have your name added to the list): + * + * - Christian Grothoff (Apr 3rd 2012) */ /*- @@ -70,10 +106,10 @@ * Modifications to fit into the linux IEEE 802.11 stack, * Mike Kershaw (dragorn@kismetwireless.net) */ - -/** +/* * parts taken from aircrack-ng, parts changend. */ + #define _GNU_SOURCE #include <sys/socket.h> #include <sys/ioctl.h> @@ -102,183 +138,429 @@ #include "gnunet_protocols.h" #include "plugin_transport_wlan.h" +/** + * Packet format type for the messages we receive from + * the kernel. This is for plain messages (with no + * performance information included). + */ #define ARPHRD_IEEE80211 801 + +/** + * Packet format type for the messages we receive from + * the kernel. This is for the PRISM format. + */ #define ARPHRD_IEEE80211_PRISM 802 -#define ARPHRD_IEEE80211_FULL 803 /** - * size of 802.11 address + * Packet format type for the messages we receive from + * the kernel. This is for messages with a + * 'struct Ieee80211RadiotapHeader' (see below). */ -#define IEEE80211_ADDR_LEN 6 +#define ARPHRD_IEEE80211_FULL 803 + /** - * Maximum size of a message allowed in either direction. + * Maximum size of a message allowed in either direction + * (used for our receive and sent buffers). */ #define MAXLINE 4096 -#define IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK 0x80000000 +/* ********* structure of messages of type ARPHRD_IEEE80211_PRISM *********** */ -/* Name Data type Units - * ---- --------- ----- - * - * IEEE80211_RADIOTAP_TSFT __le64 microseconds - * - * Value in microseconds of the MAC's 64-bit 802.11 Time - * Synchronization Function timer when the first bit of the - * MPDU arrived at the MAC. For received frames, only. - * - * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap - * - * Tx/Rx frequency in MHz, followed by flags (see below). - * - * IEEE80211_RADIOTAP_FHSS __le16 see below - * - * For frequency-hopping radios, the hop set (first byte) - * and pattern (second byte). - * - * IEEE80211_RADIOTAP_RATE uint8_t 500kb/s - * - * Tx/Rx data rate - * - * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from - * one milliwatt (dBm) - * - * RF signal power at the antenna, decibel difference from - * one milliwatt. - * - * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from - * one milliwatt (dBm) - * - * RF noise power at the antenna, decibel difference from one - * milliwatt. - * - * IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB) - * - * RF signal power at the antenna, decibel difference from an - * arbitrary, fixed reference. - * - * IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB) - * - * RF noise power at the antenna, decibel difference from an - * arbitrary, fixed reference point. - * - * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless - * - * Quality of Barker code lock. Unitless. Monotonically - * nondecreasing with "better" lock strength. Called "Signal - * Quality" in datasheets. (Is there a standard way to measure - * this?) - * - * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless - * - * Transmit power expressed as unitless distance from max - * power set at factory calibration. 0 is max power. - * Monotonically nondecreasing with lower power levels. - * - * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB) - * - * Transmit power expressed as decibel distance from max power - * set at factory calibration. 0 is max power. Monotonically - * nondecreasing with lower power levels. - * - * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from - * one milliwatt (dBm) - * - * Transmit power expressed as dBm (decibels from a 1 milliwatt - * reference). This is the absolute power level measured at - * the antenna port. - * - * IEEE80211_RADIOTAP_FLAGS uint8_t bitmap - * - * Properties of transmitted and received frames. See flags - * defined below. - * - * IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index - * - * Unitless indication of the Rx/Tx antenna for this packet. - * The first antenna is antenna 0. - * - * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap - * - * Properties of received frames. See flags defined below. - * - * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap - * - * Properties of transmitted frames. See flags defined below. - * - * IEEE80211_RADIOTAP_RTS_RETRIES uint8_t data - * - * Number of rts retries a transmitted frame used. - * - * IEEE80211_RADIOTAP_DATA_RETRIES uint8_t data - * - * Number of unicast retries a transmitted frame used. - * +/** + * Device name length in PRISM frames. + * (In the kernel, this is "WLAN_DEVNAMELEN_MAX") + */ +#define PRISM_DEVICE_NAME_LENGTH 16 + +/** + * Monitor Frame (indicator that we have a 'struct PrismHeader'). + */ +#define PRISM_MSGCODE_MONITOR 0x0041 + +/** + * Mac time element. In micro-seconds. + * Drivers appear to use a 64bit counter to hold mactime internal + * the then fill the prism header with the lower 32 bits + */ +#define PRISM_DID_MACTIME 0x2041 + +/** + * Channel element + */ +#define PRISM_DID_CHANNEL 0x3041 + +/** + * Signal element. Should be the signal strength in dbm, some people + * suggest that instead "100 - (strength in dbm)" is used (to make this + * a positive integer). + */ +#define PRISM_DID_SIGNAL 0x6041 + +/** + * Noise element + */ +#define PRISM_DID_NOISE 0x7041 + +/** + * Rate element, in units/multiples of 500Khz + */ +#define PRISM_DID_RATE 0x8041 + + +/** + * Value is set (supplied) + */ +#define PRISM_STATUS_OK 0 + +/** + * Value not supplied. + */ +#define PRISM_STATUS_NO_VALUE 1 + + +/** + * Values in the 'struct PrismHeader'. All in host byte order (!). + */ +struct PrismValue +{ + /** + * This has a different ID for each parameter, see + * PRISM_DID_* constants. + */ + uint32_t did; + + /** + * See PRISM_STATUS_*-constants. Note that they are unusual: 0 = set; 1 = not set + */ + uint16_t status; + + /** + * length of data (which is always a uint32_t, but presumably this can be used + * to specify that fewer bytes are used (with values in 'len' from 0-4). We + * ignore this field. + */ + uint16_t len; + + /** + * The data value + */ + uint32_t data; + +} __attribute__ ((packed)); + + +/** + * Prism header format ('struct p80211msg' in Linux). All in host byte order (!). + */ +struct PrismHeader +{ + /** + * We expect this to be a PRISM_MSGCODE_*. + */ + uint32_t msgcode; + + /** + * The length of the entire header. + */ + uint32_t msglen; + + /** + * Name of the device that captured the packet. + */ + char devname[PRISM_DEVICE_NAME_LENGTH]; + + /* followed by 'struct PrismValue's. Documentation suggests that these + are typically the hosttime, mactime, channel, rssi, sq, signal, noise, + rate, istx and frmlen values, but documentation is sparse. So we + will use the 'did' fields to find out what we actually got. */ + +} __attribute__ ((packed)); + + +/* ****** end of structure of messages of type ARPHRD_IEEE80211_PRISM ******* */ + +/* ********** structure of messages of type ARPHRD_IEEE80211_FULL *********** */ + +/** + * Bits in the 'it_present' bitmask from the 'struct + * Ieee80211RadiotapHeader'. For each value, we give the name, data + * type, unit and then a description below. Note that the actual size + * of the extension can be bigger as arguments must be padded so that + * args of a given length must begin at a boundary of that length. + * However, note that compound args are allowed (eg, 2 x uint16_t for + * IEEE80211_RADIOTAP_CHANNEL) so total argument length is not a + * reliable indicator of alignment requirement. See also + * 'man 9 ieee80211_radiotap'. */ enum RadiotapType { + + /** + * IEEE80211_RADIOTAP_TSFT __le64 microseconds + * + * Value in microseconds of the MAC's 64-bit 802.11 Time + * Synchronization Function timer when the first bit of the + * MPDU arrived at the MAC. For received frames, only. + */ IEEE80211_RADIOTAP_TSFT = 0, + + /** + * IEEE80211_RADIOTAP_FLAGS uint8_t bitmap + * + * Properties of transmitted and received frames. See flags + * defined below. + */ IEEE80211_RADIOTAP_FLAGS = 1, + + /** + * IEEE80211_RADIOTAP_RATE uint8_t 500kb/s + * + * Tx/Rx data rate + */ IEEE80211_RADIOTAP_RATE = 2, + + /** + * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap + * + * Tx/Rx frequency in MHz, followed by flags (see below). + */ IEEE80211_RADIOTAP_CHANNEL = 3, + /** + * IEEE80211_RADIOTAP_FHSS __le16 see below + * + * For frequency-hopping radios, the hop set (first byte) + * and pattern (second byte). + */ IEEE80211_RADIOTAP_FHSS = 4, + + /** + * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from + * one milliwatt (dBm) + * + * RF signal power at the antenna, decibel difference from + * one milliwatt. + */ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, + + /** + * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from + * one milliwatt (dBm) + * + * RF noise power at the antenna, decibel difference from one + * milliwatt. + */ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, + + /** + * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless + * + * Quality of Barker code lock. Unitless. Monotonically + * nondecreasing with "better" lock strength. Called "Signal + * Quality" in datasheets. (Is there a standard way to measure + * this?) + */ IEEE80211_RADIOTAP_LOCK_QUALITY = 7, + + /** + * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless + * + * Transmit power expressed as unitless distance from max + * power set at factory calibration. 0 is max power. + * Monotonically nondecreasing with lower power levels. + */ IEEE80211_RADIOTAP_TX_ATTENUATION = 8, + + /** + * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB) + * + * Transmit power expressed as decibel distance from max power + * set at factory calibration. 0 is max power. Monotonically + * nondecreasing with lower power levels. + */ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, + + /** + * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from + * one milliwatt (dBm) + * + * Transmit power expressed as dBm (decibels from a 1 milliwatt + * reference). This is the absolute power level measured at + * the antenna port. + */ IEEE80211_RADIOTAP_DBM_TX_POWER = 10, + + /** + * IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index + * + * Unitless indication of the Rx/Tx antenna for this packet. + * The first antenna is antenna 0. + */ IEEE80211_RADIOTAP_ANTENNA = 11, + + /** + * IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB) + * + * RF signal power at the antenna, decibel difference from an + * arbitrary, fixed reference. + */ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, + + /** + * IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB) + * + * RF noise power at the antenna, decibel difference from an + * arbitrary, fixed reference point. + */ IEEE80211_RADIOTAP_DB_ANTNOISE = 13, + + /** + * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap + * + * Properties of received frames. See flags defined below. + */ IEEE80211_RADIOTAP_RX_FLAGS = 14, + + /** + * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap + * + * Properties of transmitted frames. See flags defined below. + */ IEEE80211_RADIOTAP_TX_FLAGS = 15, + + /** + * IEEE80211_RADIOTAP_RTS_RETRIES uint8_t data + * + * Number of rts retries a transmitted frame used. + */ IEEE80211_RADIOTAP_RTS_RETRIES = 16, + + /** + * IEEE80211_RADIOTAP_DATA_RETRIES uint8_t data + * + * Number of unicast retries a transmitted frame used. + */ IEEE80211_RADIOTAP_DATA_RETRIES = 17, + + /** + * Extension bit, used to indicate that more bits are needed for + * the bitmask. + */ IEEE80211_RADIOTAP_EXT = 31 }; -/* For IEEE80211_RADIOTAP_FLAGS */ -#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received - * during CFP - */ -#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received - * with short - * preamble - */ -#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received - * with WEP encryption - */ -#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received - * with fragmentation - */ -#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ -#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between - * 802.11 header and payload - * (to 32-bit boundary) - */ -/* For IEEE80211_RADIOTAP_RX_FLAGS */ -#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ - -/* For IEEE80211_RADIOTAP_TX_FLAGS */ -#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive - * retries */ -#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ -#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ -#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* frame should not be ACKed */ -#define IEEE80211_RADIOTAP_F_TX_NOSEQ 0x0010 /* sequence number handled - * by userspace */ +/** + * Bitmask indicating an extension of the bitmask is used. + * (Mask corresponding to IEEE80211_RADIOTAP_EXT). + */ +#define IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK (1 << IEEE80211_RADIOTAP_EXT) + + + +/** + * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get + * as part of a 'struct Ieee80211RadiotapHeader' extension + * if the IEEE80211_RADIOTAP_FLAGS bit is set in + * 'it_present'). The radiotap flags are an 8-bit field. + * + * Frame was sent/received during CFP (Contention Free Period) + */ +#define IEEE80211_RADIOTAP_F_CFP 0x01 +/** + * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get + * as part of a 'struct Ieee80211RadiotapHeader' extension + * if the IEEE80211_RADIOTAP_FLAGS bit is set in + * 'it_present'). The radiotap flags are an 8-bit field. + * + * Frame was sent/received with short preamble + */ +#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 + +/** + * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get + * as part of a 'struct Ieee80211RadiotapHeader' extension + * if the IEEE80211_RADIOTAP_FLAGS bit is set in + * 'it_present'). The radiotap flags are an 8-bit field. + * + * Frame was sent/received with WEP encryption + */ +#define IEEE80211_RADIOTAP_F_WEP 0x04 /** - * A generic radio capture format is desirable. There is one for - * Linux, but it is neither rigidly defined (there were not even - * units given for some fields) nor easily extensible. + * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get + * as part of a 'struct Ieee80211RadiotapHeader' extension + * if the IEEE80211_RADIOTAP_FLAGS bit is set in + * 'it_present'). The radiotap flags are an 8-bit field. * - * I suggest the following extensible radio capture format. It is - * based on a bitmap indicating which fields are present. + * Frame was sent/received with fragmentation + */ +#define IEEE80211_RADIOTAP_F_FRAG 0x08 + +/** + * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get + * as part of a 'struct Ieee80211RadiotapHeader' extension + * if the IEEE80211_RADIOTAP_FLAGS bit is set in + * 'it_present'). The radiotap flags are an 8-bit field. + * + * Frame includes FCS (CRC at the end that needs to be removeD). + */ +#define IEEE80211_RADIOTAP_F_FCS 0x10 + +/** + * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get + * as part of a 'struct Ieee80211RadiotapHeader' extension + * if the IEEE80211_RADIOTAP_FLAGS bit is set in + * 'it_present'). The radiotap flags are an 8-bit field. + * + * Frame has padding between 802.11 header and payload + * (to 32-bit boundary) + */ +#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 + + +/** + * For IEEE80211_RADIOTAP_RX_FLAGS: + * frame failed crc check + */ +#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 + +/** + * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'): + * failed due to excessive retries + */ +#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 + +/** + * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'): + * used cts 'protection' + */ +#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 + +/** + * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'): + * used rts/cts handshake + */ +#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 + +/** + * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'): + * frame should not be ACKed + */ +#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 + +/** + * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'): + * sequence number handled by userspace + */ +#define IEEE80211_RADIOTAP_F_TX_NOSEQ 0x0010 + + +/** + * Generic header for radiotap messages (receiving and sending). A + * bit mask (it_present) determines which specific records follow. * * I am trying to describe precisely what the application programmer * should expect in the following, and for that reason I tell the @@ -290,13 +572,17 @@ enum RadiotapType * The radio capture header precedes the 802.11 header. * All data in the header is little endian on all platforms. */ -struct ieee80211_radiotap_header +struct Ieee80211RadiotapHeader { /** * Version 0. Only increases for drastic changes, introduction of * compatible new fields does not count. */ uint8_t it_version; + + /** + * Padding. Set to 0. + */ uint8_t it_pad; /** @@ -313,89 +599,106 @@ struct ieee80211_radiotap_header uint32_t it_present; }; + /** - * + * Format of the header we need to prepend to messages to be sent to the + * Kernel. */ -struct RadioTapheader +struct RadiotapTransmissionHeader { + /** - * + * First we begin with the 'generic' header we also get when receiving + * messages. */ - struct ieee80211_radiotap_header header; + struct Ieee80211RadiotapHeader header; /** - * + * Transmission rate (we use 0, kernel makes up its mind anyway). */ uint8_t rate; /** - * + * Padding (we use 0). There is a requirement to pad args, so that + * args of a given length must begin at a boundary of that length. + * As our next argument is the 'it_len' with 2 bytes, we need 1 byte + * of padding. */ uint8_t pad1; /** - * + * Transmission flags from on the IEEE80211_RADIOTAP_F_TX_* constant family. */ uint16_t txflags; + }; +/** + * The above 'struct RadiotapTransmissionHeader' should have the + * following value for 'header.it_present' based on the presence of + * the 'rate' and 'txflags' in the overall struct. + */ +#define IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK ((1 << IEEE80211_RADIOTAP_RATE) | (1 << IEEE80211_RADIOTAP_TX_FLAGS)) + + /** - * IO buffer used for buffering data in transit (to wireless or to stdout). + * struct Ieee80211RadiotapHeaderIterator - tracks walk through present radiotap arguments + * in the radiotap header. Used when we parse radiotap packets received from the kernel. */ -struct SendBuffer +struct Ieee80211RadiotapHeaderIterator { /** - * How many bytes of data are stored in 'buf' for transmission right now? - * Data always starts at offset 0 and extends to 'size'. + * pointer to the radiotap header we are walking through */ - size_t size; + const struct Ieee80211RadiotapHeader *rtheader; /** - * How many bytes that were stored in 'buf' did we already write to the - * destination? Always smaller than 'size'. + * pointer to current radiotap arg */ - size_t pos; - + const uint8_t *this_arg; + /** - * Buffered data; twice the maximum allowed message size as we add some - * headers. + * internal next argument pointer */ - char buf[MAXLINE * 2]; -}; + const uint8_t *arg; -/** - * Buffer for data read from stdin to be transmitted to the wirless card. - */ -static struct SendBuffer write_pout; + /** + * internal pointer to next present uint32_t (if IEEE80211_RADIOTAP_EXT is used). + */ + const uint32_t *next_bitmap; -/** - * Buffer for data read from the wireless card to be transmitted to stdout. - */ -static struct SendBuffer write_std; + /** + * length of radiotap header in host byte ordering + */ + size_t max_length; + /** + * internal shifter for current uint32_t bitmap, (it_present in host byte order), + * If bit 0 is set, the 'arg_index' argument is present. + */ + uint32_t bitmap_shifter; -GNUNET_NETWORK_STRUCT_BEGIN + /** + * IEEE80211_RADIOTAP_... index of current arg + */ + unsigned int this_arg_index; + + /** + * internal next argument index + */ + unsigned int arg_index; + +}; -/** - * generic definitions for IEEE 802.11 frames - */ -struct ieee80211_frame -{ - uint8_t i_fc[2]; - uint8_t i_dur[2]; - uint8_t i_addr1[IEEE80211_ADDR_LEN]; - uint8_t i_addr2[IEEE80211_ADDR_LEN]; - uint8_t i_addr3[IEEE80211_ADDR_LEN]; - uint8_t i_seq[2]; - /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ - /* see below */ -} GNUNET_PACKED; -GNUNET_NETWORK_STRUCT_END +/* ************** end of structure of ARPHRD_IEEE80211_FULL ************** */ + +/* ************************** our globals ******************************* */ /** - * struct for storing the information of the hardware + * struct for storing the information of the hardware. There is only + * one of these. */ struct HardwareInfos { @@ -424,56 +727,48 @@ struct HardwareInfos /** - * struct ieee80211_radiotap_iterator - tracks walk through present radiotap arguments - * in the radiotap header. + * IO buffer used for buffering data in transit (to wireless or to stdout). */ -struct ieee80211_radiotap_iterator +struct SendBuffer { /** - * pointer to the radiotap header we are walking through - */ - const struct ieee80211_radiotap_header *rtheader; - - /** - * length of radiotap header in cpu byte ordering - */ - size_t max_length; - - /** - * IEEE80211_RADIOTAP_... index of current arg + * How many bytes of data are stored in 'buf' for transmission right now? + * Data always starts at offset 0 and extends to 'size'. */ - unsigned int this_arg_index; + size_t size; /** - * pointer to current radiotap arg + * How many bytes that were stored in 'buf' did we already write to the + * destination? Always smaller than 'size'. */ - uint8_t *this_arg; - + size_t pos; + /** - * internal next argument index + * Buffered data; twice the maximum allowed message size as we add some + * headers. */ - unsigned int arg_index; + char buf[MAXLINE * 2]; +}; - /** - * internal next argument pointer - */ - uint8_t *arg; - /** - * internal pointer to next present uint32_t - */ - uint32_t *next_bitmap; +/** + * Buffer for data read from stdin to be transmitted to the wirless card. + */ +static struct SendBuffer write_pout; - /** - * internal shifter for curr uint32_t bitmap, b0 set == arg present - */ - uint32_t bitmap_shifter; -}; +/** + * Buffer for data read from the wireless card to be transmitted to stdout. + */ +static struct SendBuffer write_std; -/* specialized version of server_mst.c begins here */ +/* *********** specialized version of server_mst.c begins here ********** */ +/** + * To what multiple do we align messages? 8 byte should suffice for everyone + * for now. + */ #define ALIGN_FACTOR 8 /** @@ -533,7 +828,6 @@ struct MessageStreamTokenizer }; - /** * Create a message stream tokenizer. * @@ -549,10 +843,16 @@ mst_create (MessageTokenizerCallback cb, ret = malloc (sizeof (struct MessageStreamTokenizer)); if (NULL == ret) + { + fprintf (stderr, "Failed to allocate buffer for tokenizer\n"); exit (1); + } ret->hdr = malloc (MIN_BUFFER_SIZE); if (NULL == ret->hdr) - exit (2); + { + fprintf (stderr, "Failed to allocate buffer for alignment\n"); + exit (1); + } ret->curr_buf = MIN_BUFFER_SIZE; ret->cb = cb; ret->cb_cls = cb_cls; @@ -613,8 +913,9 @@ do_align: want = ntohs (hdr->size); if (want < sizeof (struct GNUNET_MessageHeader)) { - // GNUNET_break_op (0); - return GNUNET_SYSERR; + fprintf (stderr, + "Received invalid message from stdin\n"); + exit (1); } if (mst->curr_buf - mst->off < want) { @@ -627,7 +928,10 @@ do_align: { mst->hdr = realloc (mst->hdr, want); if (NULL == mst->hdr) - exit (3); + { + fprintf (stderr, "Failed to allocate buffer for alignment\n"); + exit (1); + } ibuf = (char *) mst->hdr; mst->curr_buf = want; } @@ -666,9 +970,9 @@ do_align: want = ntohs (hdr->size); if (want < sizeof (struct GNUNET_MessageHeader)) { - // GNUNET_break_op (0); - mst->off = 0; - return GNUNET_SYSERR; + fprintf (stderr, + "Received invalid message from stdin\n"); + exit (1); } if (size < want) break; /* or not, buffer incomplete, so copy to private buffer... */ @@ -689,11 +993,19 @@ do_align: { mst->hdr = realloc (mst->hdr, size + mst->pos); if (NULL == mst->hdr) - exit (4); + { + fprintf (stderr, "Failed to allocate buffer for alignment\n"); + exit (1); + } ibuf = (char *) mst->hdr; mst->curr_buf = size + mst->pos; } - // GNUNET_assert (mst->pos + size <= mst->curr_buf); + if (mst->pos + size > mst->curr_buf) + { + fprintf (stderr, + "Assertion failed\n"); + exit (1); + } memcpy (&ibuf[mst->pos], buf, size); mst->pos += size; } @@ -713,16 +1025,16 @@ mst_destroy (struct MessageStreamTokenizer *mst) free (mst); } -/* end of server_mst.c copy */ - +/* ***************** end of server_mst.c clone ***************** **/ +/* ************** code for handling of ARPHRD_IEEE80211_FULL ************** */ /** * Radiotap header iteration * * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator - * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) + * struct Ieee80211RadiotapHeaderIterator (no need to init the struct beforehand) * then loop calling __ieee80211_radiotap_iterator_next()... it returns -1 * if there are no more args in the header, or the next argument type index * that is present. The iterator's this_arg member points to the start of the @@ -736,9 +1048,8 @@ mst_destroy (struct MessageStreamTokenizer *mst) * @return 0 on success, -1 on error */ static int -ieee80211_radiotap_iterator_init (struct ieee80211_radiotap_iterator *iterator, - const struct ieee80211_radiotap_header - *radiotap_header, +ieee80211_radiotap_iterator_init (struct Ieee80211RadiotapHeaderIterator *iterator, + const struct Ieee80211RadiotapHeader *radiotap_header, size_t max_length) { if ( (iterator == NULL) || @@ -750,26 +1061,22 @@ ieee80211_radiotap_iterator_init (struct ieee80211_radiotap_iterator *iterator, return -1; /* sanity check for allowed length and radiotap length field */ - if ( (max_length < sizeof (struct ieee80211_radiotap_header)) || + if ( (max_length < sizeof (struct Ieee80211RadiotapHeader)) || (max_length < (GNUNET_le16toh (radiotap_header->it_len))) ) return -1; + memset (iterator, 0, sizeof (struct Ieee80211RadiotapHeaderIterator)); iterator->rtheader = radiotap_header; iterator->max_length = GNUNET_le16toh (radiotap_header->it_len); - iterator->arg_index = 0; iterator->bitmap_shifter = GNUNET_le32toh (radiotap_header->it_present); - iterator->arg = - ((uint8_t *) radiotap_header) + sizeof (struct ieee80211_radiotap_header); - iterator->this_arg = 0; + iterator->arg = ((uint8_t *) radiotap_header) + sizeof (struct Ieee80211RadiotapHeader); /* find payload start allowing for extended bitmap(s) */ - if ((iterator->bitmap_shifter & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK)) + if (0 != (iterator->bitmap_shifter & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK)) { - while (GNUNET_le32toh (*((uint32_t *) iterator->arg)) & - IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK) + while (GNUNET_le32toh (*((uint32_t *) iterator->arg)) & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK) { iterator->arg += sizeof (uint32_t); - /* * check for insanity where the present bitmaps * keep claiming to extend up to or even beyond the @@ -791,7 +1098,7 @@ ieee80211_radiotap_iterator_init (struct ieee80211_radiotap_iterator *iterator, /** - * @brief ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg + * Returns the next radiotap parser iterator arg. * * This function returns the next radiotap arg index (IEEE80211_RADIOTAP_...) * and sets iterator->this_arg to point to the payload for the arg. It takes @@ -800,13 +1107,11 @@ ieee80211_radiotap_iterator_init (struct ieee80211_radiotap_iterator *iterator, * format. * * @param iterator: radiotap_iterator to move to next arg (if any) - * * @return next present arg index on success or -1 if no more or error */ static int -ieee80211_radiotap_iterator_next (struct ieee80211_radiotap_iterator *iterator) +ieee80211_radiotap_iterator_next (struct Ieee80211RadiotapHeaderIterator *iterator) { - /* * small length lookup table for all radiotap types we heard of * starting from b0 in the bitmap, so we can walk the payload @@ -851,120 +1156,103 @@ ieee80211_radiotap_iterator_next (struct ieee80211_radiotap_iterator *iterator) * for every radiotap entry we can at * least skip (by knowing the length)... */ - while (iterator->arg_index < sizeof (rt_sizes)) { - int hit = 0; - - if (!(iterator->bitmap_shifter & 1)) - goto next_entry; /* arg not present */ - - /* - * arg is present, account for alignment padding - * 8-bit args can be at any alignment - * 16-bit args must start on 16-bit boundary - * 32-bit args must start on 32-bit boundary - * 64-bit args must start on 64-bit boundary - * - * note that total arg size can differ from alignment of - * elements inside arg, so we use upper nybble of length - * table to base alignment on - * - * also note: these alignments are ** relative to the - * start of the radiotap header **. There is no guarantee - * that the radiotap header itself is aligned on any - * kind of boundary. - */ - - if ((((void *) iterator->arg) - - ((void *) iterator->rtheader)) & ((rt_sizes[iterator->arg_index] >> 4) - - 1)) - iterator->arg_index += - (rt_sizes[iterator->arg_index] >> 4) - - ((((void *) iterator->arg) - - ((void *) iterator->rtheader)) & ((rt_sizes[iterator->arg_index] >> - 4) - 1)); - - /* - * this is what we will return to user, but we need to - * move on first so next call has something fresh to test - */ - - iterator->this_arg_index = iterator->arg_index; - iterator->this_arg = iterator->arg; - hit = 1; - - /* internally move on the size of this arg */ - - iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; - - /* - * check for insanity where we are given a bitmap that - * claims to have more arg content than the length of the - * radiotap section. We will normally end up equalling this - * max_length on the last arg, never exceeding it. - */ - - if ((((void *) iterator->arg) - ((void *) iterator->rtheader)) > - iterator->max_length) - return -1; + int hit = (0 != (iterator->bitmap_shifter & 1)); -next_entry: + if (hit) + { + unsigned int wanted_alignment; + unsigned int unalignment; + /* + * arg is present, account for alignment padding + * 8-bit args can be at any alignment + * 16-bit args must start on 16-bit boundary + * 32-bit args must start on 32-bit boundary + * 64-bit args must start on 64-bit boundary + * + * note that total arg size can differ from alignment of + * elements inside arg, so we use upper nybble of length table + * to base alignment on. First, 'wanted_alignment' is set to be + * 1 for 8-bit, 2 for 16-bit, 4 for 32-bit and 8 for 64-bit + * arguments. Then, we calculate the 'unalignment' (how many + * bytes we are over by taking the difference of 'arg' and the + * overall starting point modulo the desired alignment. As + * desired alignments are powers of two, we can do modulo with + * binary "&" (and also avoid the possibility of a division by + * zero if the 'rt_sizes' table contains bogus entries). + * + * also note: these alignments are relative to the start of the + * radiotap header. There is no guarantee that the radiotap + * header itself is aligned on any kind of boundary, thus we + * need to really look at the delta here. + */ + wanted_alignment = rt_sizes[iterator->arg_index] >> 4; + unalignment = (((void *) iterator->arg) - ((void *) iterator->rtheader)) & (wanted_alignment - 1); + if (0 != unalignment) + { + /* need padding (by 'wanted_alignment - unalignment') */ + iterator->arg_index += wanted_alignment - unalignment; + } + + /* + * this is what we will return to user, but we need to + * move on first so next call has something fresh to test + */ + iterator->this_arg_index = iterator->arg_index; + iterator->this_arg = iterator->arg; + + /* internally move on the size of this arg (using lower nybble from + the table) */ + iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; + + /* + * check for insanity where we are given a bitmap that + * claims to have more arg content than the length of the + * radiotap section. We will normally end up equalling this + * max_length on the last arg, never exceeding it. + */ + if ((((void *) iterator->arg) - ((void *) iterator->rtheader)) > iterator->max_length) + return -1; + } + /* Now, move on to next bit / next entry */ iterator->arg_index++; - if (((iterator->arg_index & 31) == 0)) + + if (0 == (iterator->arg_index % 32)) { /* completed current uint32_t bitmap */ - if (iterator->bitmap_shifter & 1) + if (0 != (iterator->bitmap_shifter & 1)) { - /* b31 was set, there is more */ - /* move to next uint32_t bitmap */ + /* bit 31 was set, there is more; move to next uint32_t bitmap */ iterator->bitmap_shifter = GNUNET_le32toh (*iterator->next_bitmap); iterator->next_bitmap++; } else { - /* no more bitmaps: end */ + /* no more bitmaps: end (by setting arg_index to high, unsupported value) */ iterator->arg_index = sizeof (rt_sizes); } } else - { /* just try the next bit */ + { + /* just try the next bit (while loop will move on) */ iterator->bitmap_shifter >>= 1; } /* if we found a valid arg earlier, return it now */ - if (hit) return iterator->this_arg_index; - } - /* we don't know how to handle any more args, we're done */ + /* we don't know how to handle any more args (or there are no more), + so we're done (this is not an error) */ return -1; } /** - * Return the channel from the frequency (in Mhz) - * @param frequency of the channel - * @return number of the channel - */ -static int -get_channel_from_frequency (int frequency) -{ - if (frequency >= 2412 && frequency <= 2472) - return (frequency - 2407) / 5; - if (frequency == 2484) - return 14; - if (frequency >= 5000 && frequency <= 6100) - return (frequency - 5000) / 5; - return -1; -} - - -/** - * function to calculate the crc, the start of the calculation + * Calculate crc32, the start of the calculation * * @param buf buffer to calc the crc * @param len len of the buffer @@ -1049,7 +1337,7 @@ calc_crc_osdep (const unsigned char *buf, size_t len) /** - * Function to calculate and check crc of the wlan packet + * Calculate and check crc of the wlan packet * * @param buf buffer of the packet, with len + 4 bytes of data, * the last 4 bytes being the checksum @@ -1070,6 +1358,30 @@ check_crc_buf_osdep (const unsigned char *buf, size_t len) } +/* ************end of code for handling of ARPHRD_IEEE80211_FULL ************** */ + + +/* ************beginning of code for reading packets from kernel ************** */ + +/** + * Return the channel from the frequency (in Mhz) + * + * @param frequency of the channel + * @return number of the channel + */ +static int +get_channel_from_frequency (int32_t frequency) +{ + if (frequency >= 2412 && frequency <= 2472) + return (frequency - 2407) / 5; + if (frequency == 2484) + return 14; + if (frequency >= 5000 && frequency <= 6100) + return (frequency - 5000) / 5; + return -1; +} + + /** * Get the channel used by our WLAN interface. * @@ -1080,46 +1392,46 @@ static int linux_get_channel (const struct HardwareInfos *dev) { struct iwreq wrq; - int fd; - int frequency; - int chan; + int32_t frequency; memset (&wrq, 0, sizeof (struct iwreq)); strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ); - fd = dev->fd_raw; - if (0 > ioctl (fd, SIOCGIWFREQ, &wrq)) + if (0 > ioctl (dev->fd_raw, SIOCGIWFREQ, &wrq)) return -1; - - frequency = wrq.u.freq.m; + frequency = wrq.u.freq.m; /* 'iw_freq' defines 'm' as '__s32', so we keep it signed */ if (100000000 < frequency) frequency /= 100000; else if (1000000 < frequency) frequency /= 1000; if (1000 < frequency) - chan = get_channel_from_frequency (frequency); - else - chan = frequency; - return chan; + return get_channel_from_frequency (frequency); + return frequency; } /** - * function to read from a wlan card + * Read from the raw socket (the wlan card), parse the packet and + * put the result into the buffer for transmission to 'stdout'. + * * @param dev pointer to the struct of the wlan card - * @param buf buffer to read to + * @param buf buffer to read to; first bytes will be the 'struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame', + * followed by the actual payload * @param buf_size size of the buffer - * @param ri radiotap_rx info - * @return size read from the buffer + * @param ri where to write radiotap_rx info + * @return number of bytes written to 'buf' */ static ssize_t -linux_read (struct HardwareInfos *dev, unsigned char *buf, size_t buf_size, - struct Radiotap_rx *ri) +linux_read (struct HardwareInfos *dev, + unsigned char *buf, size_t buf_size, + struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *ri) { unsigned char tmpbuf[buf_size]; ssize_t caplen; - int n, got_signal, got_noise, got_channel, fcs_removed; - - n = got_signal = got_noise = got_channel = fcs_removed = 0; + size_t n; + int got_signal = 0; + int got_noise = 0; + int got_channel = 0; + int fcs_removed = 0; caplen = read (dev->fd_raw, tmpbuf, buf_size); if (0 > caplen) @@ -1130,171 +1442,181 @@ linux_read (struct HardwareInfos *dev, unsigned char *buf, size_t buf_size, return -1; } - memset (buf, 0, buf_size); - memset (ri, 0, sizeof (*ri)); - + memset (ri, 0, sizeof (*ri)); switch (dev->arptype_in) { case ARPHRD_IEEE80211_PRISM: - { - /* skip the prism header */ - if (tmpbuf[7] == 0x40) { - /* prism54 uses a different format */ - ri->ri_power = tmpbuf[0x33]; - ri->ri_noise = *(unsigned int *) (tmpbuf + 0x33 + 12); - ri->ri_rate = (*(unsigned int *) (tmpbuf + 0x33 + 24)) * 500000; - got_signal = 1; - got_noise = 1; - n = 0x40; - } - else - { - ri->ri_mactime = *(uint64_t *) (tmpbuf + 0x5C - 48); - ri->ri_channel = *(unsigned int *) (tmpbuf + 0x5C - 36); - ri->ri_power = *(unsigned int *) (tmpbuf + 0x5C); - ri->ri_noise = *(unsigned int *) (tmpbuf + 0x5C + 12); - ri->ri_rate = (*(unsigned int *) (tmpbuf + 0x5C + 24)) * 500000; - got_channel = 1; - got_signal = 1; - got_noise = 1; - n = *(int *) (tmpbuf + 4); + const struct PrismHeader *ph; + + ph = (const struct PrismHeader*) tmpbuf; + n = ph->msglen; + if ( (n < 8) || (n >= caplen) ) + return 0; /* invalid format */ + if ( (PRISM_MSGCODE_MONITOR == ph->msgcode) && + (n >= sizeof (struct PrismHeader)) ) + { + const char *pos; + size_t left; + struct PrismValue pv; + + left = n - sizeof (struct PrismHeader); + pos = (const char *) &ph[1]; + while (left > sizeof (struct PrismValue)) + { + left -= sizeof (struct PrismValue); + memcpy (&pv, pos, sizeof (struct PrismValue)); + pos += sizeof (struct PrismValue); + + switch (pv.did) + { + case PRISM_DID_NOISE: + if (PRISM_STATUS_OK == pv.status) + { + ri->ri_noise = pv.data; + got_noise = 1; + } + break; + case PRISM_DID_RATE: + if (PRISM_STATUS_OK == pv.status) + ri->ri_rate = pv.data * 500000; + break; + case PRISM_DID_CHANNEL: + if (PRISM_STATUS_OK == pv.status) + { + ri->ri_channel = pv.data; + got_channel = 1; + } + break; + case PRISM_DID_MACTIME: + if (PRISM_STATUS_OK == pv.status) + ri->ri_mactime = pv.data; + break; + case PRISM_DID_SIGNAL: + if (PRISM_STATUS_OK == pv.status) + { + ri->ri_power = pv.data; + got_signal = 1; + } + break; + } + } + } + if ( (n < 8) || (n >= caplen) ) + return 0; /* invalid format */ } - - if ( (n < 8) || (n >= caplen) ) - return 0; - } break; - case ARPHRD_IEEE80211_FULL: - { - struct ieee80211_radiotap_iterator iterator; - struct ieee80211_radiotap_header *rthdr; - - rthdr = (struct ieee80211_radiotap_header *) tmpbuf; - - if (0 != ieee80211_radiotap_iterator_init (&iterator, rthdr, caplen)) - return 0; - - /* go through the radiotap arguments we have been given - * by the driver - */ - - while (ieee80211_radiotap_iterator_next (&iterator) >= 0) { - - switch (iterator.this_arg_index) + struct Ieee80211RadiotapHeaderIterator iterator; + struct Ieee80211RadiotapHeader *rthdr; + + memset (&iterator, 0, sizeof (iterator)); + rthdr = (struct Ieee80211RadiotapHeader *) tmpbuf; + n = GNUNET_le16toh (rthdr->it_len); + if ( (n < sizeof (struct Ieee80211RadiotapHeader)) || (n >= caplen)) + return 0; /* invalid 'it_len' */ + if (0 != ieee80211_radiotap_iterator_init (&iterator, rthdr, caplen)) + return 0; + /* go through the radiotap arguments we have been given by the driver */ + while (0 <= ieee80211_radiotap_iterator_next (&iterator)) { - - case IEEE80211_RADIOTAP_TSFT: - ri->ri_mactime = GNUNET_le64toh (*((uint64_t *) iterator.this_arg)); - break; - - case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: - if (!got_signal) - { - if (*iterator.this_arg < 127) - ri->ri_power = *iterator.this_arg; - else - ri->ri_power = *iterator.this_arg - 255; - - got_signal = 1; - } - break; - - case IEEE80211_RADIOTAP_DB_ANTSIGNAL: - if (!got_signal) - { - if (*iterator.this_arg < 127) - ri->ri_power = *iterator.this_arg; - else - ri->ri_power = *iterator.this_arg - 255; - - got_signal = 1; - } - break; - - case IEEE80211_RADIOTAP_DBM_ANTNOISE: - if (!got_noise) - { - if (*iterator.this_arg < 127) - ri->ri_noise = *iterator.this_arg; - else - ri->ri_noise = *iterator.this_arg - 255; - - got_noise = 1; - } - break; - - case IEEE80211_RADIOTAP_DB_ANTNOISE: - if (!got_noise) - { - if (*iterator.this_arg < 127) - ri->ri_noise = *iterator.this_arg; - else - ri->ri_noise = *iterator.this_arg - 255; - - got_noise = 1; - } - break; - - case IEEE80211_RADIOTAP_ANTENNA: - ri->ri_antenna = *iterator.this_arg; - break; - - case IEEE80211_RADIOTAP_CHANNEL: - ri->ri_channel = *iterator.this_arg; - got_channel = 1; - break; - - case IEEE80211_RADIOTAP_RATE: - ri->ri_rate = (*iterator.this_arg) * 500000; - break; - - case IEEE80211_RADIOTAP_FLAGS: - /* is the CRC visible at the end? - * remove - */ - if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) - { - fcs_removed = 1; - caplen -= 4; - } - - if (*iterator.this_arg & IEEE80211_RADIOTAP_F_RX_BADFCS) - return (0); - - break; - } - } - n = GNUNET_le16toh (rthdr->it_len); - if (n <= 0 || n >= caplen) - return 0; - } + switch (iterator.this_arg_index) + { + case IEEE80211_RADIOTAP_TSFT: + ri->ri_mactime = GNUNET_le64toh (*((uint64_t *) iterator.this_arg)); + break; + case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: + if (!got_signal) + { + ri->ri_power = * ((int8_t*) iterator.this_arg); + got_signal = 1; + } + break; + case IEEE80211_RADIOTAP_DB_ANTSIGNAL: + if (!got_signal) + { + ri->ri_power = * ((int8_t*) iterator.this_arg); + got_signal = 1; + } + break; + case IEEE80211_RADIOTAP_DBM_ANTNOISE: + if (!got_noise) + { + ri->ri_noise = * ((int8_t*) iterator.this_arg); + got_noise = 1; + } + break; + case IEEE80211_RADIOTAP_DB_ANTNOISE: + if (!got_noise) + { + ri->ri_noise = * ((int8_t*) iterator.this_arg); + got_noise = 1; + } + break; + case IEEE80211_RADIOTAP_ANTENNA: + ri->ri_antenna = *iterator.this_arg; + break; + case IEEE80211_RADIOTAP_CHANNEL: + ri->ri_channel = *iterator.this_arg; + got_channel = 1; + break; + case IEEE80211_RADIOTAP_RATE: + ri->ri_rate = (*iterator.this_arg) * 500000; + break; + case IEEE80211_RADIOTAP_FLAGS: + { + uint8_t flags = *iterator.this_arg; + /* is the CRC visible at the end? if so, remove */ + if (0 != (flags & IEEE80211_RADIOTAP_F_FCS)) + { + fcs_removed = 1; + caplen -= sizeof (uint32_t); + } + break; + } + case IEEE80211_RADIOTAP_RX_FLAGS: + { + uint16_t flags = ntohs (* ((uint16_t *) iterator.this_arg)); + if (0 != (flags & IEEE80211_RADIOTAP_F_RX_BADFCS)) + return 0; + } + break; + } /* end of 'switch' */ + } /* end of the 'while' loop */ + } break; case ARPHRD_IEEE80211: - /* do nothing? */ + n = 0; /* no header */ break; default: - errno = ENOTSUP; + errno = ENOTSUP; /* unsupported format */ return -1; } - caplen -= n; + if (! got_channel) + ri->ri_channel = linux_get_channel (dev); - //detect fcs at the end, even if the flag wasn't set and remove it - if ((0 == fcs_removed) && (0 == check_crc_buf_osdep (tmpbuf + n, caplen - 4))) + /* detect CRC32 at the end, even if the flag wasn't set and remove it */ + if ( (0 == fcs_removed) && + (0 == check_crc_buf_osdep (tmpbuf + n, caplen - sizeof (uint32_t))) ) { - caplen -= 4; + /* NOTE: this heuristic can of course fail if there happens to + be a matching checksum at the end. Would be good to have + some data to see how often this heuristic actually works. */ + caplen -= sizeof (uint32_t); } + /* copy payload to target buffer */ memcpy (buf, tmpbuf + n, caplen); - if (!got_channel) - ri->ri_channel = linux_get_channel (dev); - return caplen; } +/* ************end of code for reading packets from kernel ************** */ + +/* ************other helper functions for main start here ************** */ + + /** * Open the wireless network interface for reading/writing. * @@ -1400,11 +1722,12 @@ open_device_raw (struct HardwareInfos *dev) setsockopt (dev->fd_raw, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof (mr))) { - fprintf (stderr, "Failed to enable promiscuous mode on interface `%.*s'\n", - IFNAMSIZ, dev->iface); + fprintf (stderr, + "Failed to enable promiscuous mode on interface `%.*s'\n", + IFNAMSIZ, + dev->iface); return 1; } - return 0; } @@ -1423,106 +1746,101 @@ test_wlan_interface (const char *iface) struct stat sbuf; int ret; - /* mac80211 stack detection */ - ret = - snprintf (strbuf, sizeof (strbuf), "/sys/class/net/%s/phy80211/subsystem", - iface); + ret = snprintf (strbuf, sizeof (strbuf), + "/sys/class/net/%s/phy80211/subsystem", + iface); if ((ret < 0) || (ret >= sizeof (strbuf)) || (0 != stat (strbuf, &sbuf))) { - fprintf (stderr, "Did not find 802.11 interface `%s'. Exiting.\n", iface); - return 1; + fprintf (stderr, + "Did not find 802.11 interface `%s'. Exiting.\n", + iface); + exit (1); } return 0; } /** - * Function to test incoming packets mac for being our own. + * Test incoming packets mac for being our own. * - * @param uint8_taIeeeHeader buffer of the packet + * @param taIeeeHeader buffer of the packet * @param dev the Hardware_Infos struct * @return 0 if mac belongs to us, 1 if mac is for another target */ static int -mac_test (const struct ieee80211_frame *uint8_taIeeeHeader, +mac_test (const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader, const struct HardwareInfos *dev) { - if (0 != memcmp (uint8_taIeeeHeader->i_addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE)) - return 1; - if (0 == memcmp (uint8_taIeeeHeader->i_addr1, &dev->pl_mac, MAC_ADDR_SIZE)) - return 0; - if (0 == memcmp (uint8_taIeeeHeader->i_addr1, &bc_all_mac, MAC_ADDR_SIZE)) - return 0; - return 1; + if (0 != memcmp (&taIeeeHeader->addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE)) + return 1; /* not a GNUnet ad-hoc package */ + if ( (0 == memcmp (&taIeeeHeader->addr1, &dev->pl_mac, MAC_ADDR_SIZE)) || + (0 == memcmp (&taIeeeHeader->addr1, &bc_all_mac, MAC_ADDR_SIZE)) ) + return 0; /* for us, or broadcast */ + return 1; /* not for us */ } /** - * function to set the wlan header to make attacks more difficult - * @param uint8_taIeeeHeader pointer to the header of the packet + * Set the wlan header to sane values to make attacks more difficult + * + * @param taIeeeHeader pointer to the header of the packet * @param dev pointer to the Hardware_Infos struct */ static void -mac_set (struct ieee80211_frame *uint8_taIeeeHeader, +mac_set (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader, const struct HardwareInfos *dev) { - uint8_taIeeeHeader->i_fc[0] = 0x08; - uint8_taIeeeHeader->i_fc[1] = 0x00; - memcpy (uint8_taIeeeHeader->i_addr2, &dev->pl_mac, MAC_ADDR_SIZE); - memcpy (uint8_taIeeeHeader->i_addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE); + taIeeeHeader->frame_control = htons (IEEE80211_FC0_TYPE_DATA); + taIeeeHeader->addr2 = dev->pl_mac; + taIeeeHeader->addr3 = mac_bssid_gnunet; } /** - * function to process the data from the stdin - * @param cls pointer to the device struct + * Process data from the stdin. Takes the message, prepends the + * radiotap transmission header, forces the sender MAC to be correct + * and puts it into our buffer for transmission to the kernel. + * + * @param cls pointer to the device struct ('struct HardwareInfos*') * @param hdr pointer to the start of the packet */ static void stdin_send_hw (void *cls, const struct GNUNET_MessageHeader *hdr) { struct HardwareInfos *dev = cls; - struct Radiotap_Send *header = (struct Radiotap_Send *) &hdr[1]; - struct ieee80211_frame *wlanheader; + const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header; + struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *wlanheader; size_t sendsize; - struct RadioTapheader rtheader; - - rtheader.header.it_version = 0; /* radiotap version */ - rtheader.header.it_len = GNUNET_htole16 (0x0c); /* radiotap header length */ - rtheader.header.it_present = GNUNET_le16toh (0x00008004); /* our bitmap */ - rtheader.rate = 0x00; - rtheader.pad1 = 0x00; - rtheader.txflags = - GNUNET_htole16 (IEEE80211_RADIOTAP_F_TX_NOACK | IEEE80211_RADIOTAP_F_TX_NOSEQ); + struct RadiotapTransmissionHeader rtheader; sendsize = ntohs (hdr->size); - if (sendsize < - sizeof (struct Radiotap_Send) + sizeof (struct GNUNET_MessageHeader)) + if ( (sendsize < + sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)) || + (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)) ) { - fprintf (stderr, "Function stdin_send_hw: malformed packet (too small)\n"); + fprintf (stderr, "Received malformed message\n"); exit (1); } - sendsize -= - sizeof (struct Radiotap_Send) + sizeof (struct GNUNET_MessageHeader); - + sendsize -= (sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) - sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame)); if (MAXLINE < sendsize) { - fprintf (stderr, "Function stdin_send_hw: Packet too big for buffer\n"); - exit (1); - } - if (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA != ntohs (hdr->type)) - { - fprintf (stderr, "Function stdin_send_hw: wrong packet type\n"); + fprintf (stderr, "Packet too big for buffer\n"); exit (1); } - + header = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr; + rtheader.header.it_version = 0; + rtheader.header.it_pad = 0; rtheader.header.it_len = GNUNET_htole16 (sizeof (rtheader)); - rtheader.rate = header->rate; + rtheader.header.it_present = GNUNET_htole16 (IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK); + rtheader.rate = header->rate; + rtheader.pad1 = 0; + rtheader.txflags = GNUNET_htole16 (IEEE80211_RADIOTAP_F_TX_NOACK | IEEE80211_RADIOTAP_F_TX_NOSEQ); memcpy (write_pout.buf, &rtheader, sizeof (rtheader)); - memcpy (write_pout.buf + sizeof (rtheader), &header[1], sendsize); + memcpy (&write_pout.buf[sizeof (rtheader)], &header->frame, sendsize); + wlanheader = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &write_pout.buf[sizeof (rtheader)]; + /* payload contains MAC address, but we don't trust it, so we'll - * overwrite it with OUR MAC address again to prevent mischief */ - wlanheader = (struct ieee80211_frame *) (write_pout.buf + sizeof (rtheader)); + * overwrite it with OUR MAC address to prevent mischief */ mac_set (wlanheader, dev); write_pout.size = sendsize + sizeof (rtheader); } @@ -1721,33 +2039,30 @@ main (int argc, char *argv[]) if (FD_ISSET (dev.fd_raw, &rfds)) { - struct GNUNET_MessageHeader *header; - struct Radiotap_rx *rxinfo; - struct ieee80211_frame *datastart; + struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm; ssize_t ret; - header = (struct GNUNET_MessageHeader *) write_std.buf; - rxinfo = (struct Radiotap_rx *) &header[1]; - datastart = (struct ieee80211_frame *) &rxinfo[1]; + rrm = (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf; ret = - linux_read (&dev, (unsigned char *) datastart, - sizeof (write_std.buf) - sizeof (struct Radiotap_rx) - - sizeof (struct GNUNET_MessageHeader), rxinfo); + linux_read (&dev, (unsigned char *) &rrm->frame, + sizeof (write_std.buf) + - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage) + + sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame), + rrm); if (0 > ret) { fprintf (stderr, "Read error from raw socket: %s\n", strerror (errno)); break; } - if ((0 < ret) && (0 == mac_test (datastart, &dev))) + if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev))) { - write_std.size = - ret + sizeof (struct GNUNET_MessageHeader) + - sizeof (struct Radiotap_rx); - header->size = htons (write_std.size); - header->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); + write_std.size = ret + + sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage) + - sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame); + rrm->header.size = htons (write_std.size); + rrm->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER); } } - } /* Error handling, try to clean up a bit at least */ mst_destroy (stdin_mst); diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index cd9bb5c..c200cb5 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -76,6 +76,11 @@ struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key; */ struct GNUNET_ATS_SchedulingHandle *GST_ats; +/** + * DEBUGGING connection counter + */ +static int connections; + /** * Transmit our HELLO message to the given (connected) neighbour. @@ -139,7 +144,7 @@ process_payload (const struct GNUNET_PeerIdentity *peer, size_t size = sizeof (struct InboundMessage) + msg_size + sizeof (struct GNUNET_ATS_Information) * (ats_count + 1); - char buf[size]; + char buf[size] GNUNET_ALIGN; struct GNUNET_ATS_Information *ap; ret = GNUNET_TIME_UNIT_ZERO; @@ -225,10 +230,12 @@ plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer, if (NULL == message) goto end; type = ntohs (message->type); -#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received Message with type %u from peer `%s'\n", type, GNUNET_i2s (peer)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received Message with type %u\n", type); -#endif + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# bytes total received"), + ntohs (message->size), GNUNET_NO); switch (type) { @@ -236,21 +243,17 @@ plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer, GST_validation_handle_hello (message); return ret; case GNUNET_MESSAGE_TYPE_TRANSPORT_PING: -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Processing `%s' from `%s'\n", "PING", (sender_address != NULL) ? GST_plugins_a2s (&address) : "<inbound>"); -#endif GST_validation_handle_ping (peer, message, &address, session); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG: -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Processing `%s' from `%s'\n", "PONG", (sender_address != NULL) ? GST_plugins_a2s (&address) : "<inbound>"); -#endif GST_validation_handle_pong (peer, message); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT: @@ -262,8 +265,8 @@ plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer, ats_count); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK: - GST_neighbours_handle_ack (message, peer, &address, session, ats, - ats_count); + GST_neighbours_handle_session_ack (message, peer, &address, session, ats, + ats_count); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT: GST_neighbours_handle_disconnect_message (peer, message); @@ -276,6 +279,10 @@ plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer, break; default: /* should be payload */ + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# bytes payload received"), + ntohs (message->size), GNUNET_NO); ret = process_payload (peer, &address, session, message, ats, ats_count); break; } @@ -285,11 +292,9 @@ end: * this connections seem to go extra-slow */ GNUNET_ATS_address_update (GST_ats, &address, session, ats, ats_count); #endif -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Allowing receive from peer %s to continue in %llu ms\n", GNUNET_i2s (peer), (unsigned long long) ret.rel_value); -#endif return ret; } @@ -341,12 +346,10 @@ plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, struct GNUNET_HELLO_Address address; GNUNET_assert (strlen (transport_name) > 0); -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %X to peer `%s' ended \n", session, GNUNET_i2s (peer)); -#endif if (NULL != session) - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "transport-ats", "Telling ATS to destroy session %p from peer %s\n", session, GNUNET_i2s (peer)); @@ -368,7 +371,7 @@ plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, * @param addrlen length of the address * @return ATS Information containing the network type */ -static const struct GNUNET_ATS_Information +static struct GNUNET_ATS_Information plugin_env_address_to_type (void *cls, const struct sockaddr *addr, size_t addrlen) @@ -425,15 +428,12 @@ ats_request_address_change (void *cls, /* ATS tells me to disconnect from peer */ if ((bw_in == 0) && (bw_out == 0)) { -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS tells me to disconnect from peer `%s'\n", GNUNET_i2s (&address->peer)); -#endif GST_neighbours_force_disconnect (&address->peer); return; } - /* will never return GNUNET_YES since connection is to be established */ GST_neighbours_switch_to_address (&address->peer, address, session, ats, ats_count, bandwidth_in, bandwidth_out); @@ -458,10 +458,15 @@ neighbours_connect_notification (void *cls, size_t len = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_ATS_Information); - char buf[len]; + char buf[len] GNUNET_ALIGN; struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf; struct GNUNET_ATS_Information *ap; + connections++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "We are now connected to peer `%s' and %u peers in total\n", + GNUNET_i2s (peer), connections); + connect_msg->header.size = htons (sizeof (buf)); connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT); connect_msg->ats_count = htonl (ats_count); @@ -485,6 +490,11 @@ neighbours_disconnect_notification (void *cls, { struct DisconnectInfoMessage disconnect_msg; + connections--; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Peer `%s' disconnected and we are connected to %u peers\n", + GNUNET_i2s (peer), connections); + disconnect_msg.header.size = htons (sizeof (struct DisconnectInfoMessage)); disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT); disconnect_msg.reserved = htonl (0); @@ -560,7 +570,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { char *keyfile; - + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded tmp; /* setup globals */ GST_cfg = c; if (GNUNET_OK != @@ -584,9 +594,15 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, } GST_stats = GNUNET_STATISTICS_create ("transport", c); GST_peerinfo = GNUNET_PEERINFO_connect (c); + memset (&GST_my_public_key, '\0', sizeof (GST_my_public_key)); + memset (&tmp, '\0', sizeof (tmp)); GNUNET_CRYPTO_rsa_key_get_public (GST_my_private_key, &GST_my_public_key); GNUNET_CRYPTO_hash (&GST_my_public_key, sizeof (GST_my_public_key), &GST_my_identity.hashPubKey); + + GNUNET_assert (NULL != GST_my_private_key); + GNUNET_assert (0 != memcmp (&GST_my_public_key, &tmp, sizeof (GST_my_public_key))); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); if (GST_peerinfo == NULL) @@ -599,6 +615,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, /* start subsystems */ GST_hello_start (&process_hello_update, NULL); + GNUNET_assert (NULL != GST_hello_get()); GST_blacklist_start (server); GST_ats = GNUNET_ATS_scheduling_init (GST_cfg, &ats_request_address_change, NULL); @@ -630,4 +647,4 @@ main (int argc, char *const *argv) GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; } -/* end of file gnunet-service-transport-new.c */ +/* end of file gnunet-service-transport.c */ diff --git a/src/transport/gnunet-service-transport_blacklist.c b/src/transport/gnunet-service-transport_blacklist.c index 2089949..8c36888 100644 --- a/src/transport/gnunet-service-transport_blacklist.c +++ b/src/transport/gnunet-service-transport_blacklist.c @@ -113,7 +113,7 @@ struct GST_BlacklistCheck * Current transmission request handle for this client, or NULL if no * request is pending. */ - struct GNUNET_CONNECTION_TransmitHandle *th; + struct GNUNET_SERVER_TransmitHandle *th; /** * Our current position in the blacklisters list. @@ -191,7 +191,7 @@ client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) bc->bl_pos = bl->next; if (bc->th != NULL) { - GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th); + GNUNET_SERVER_notify_transmit_ready_cancel (bc->th); bc->th = NULL; } if (bc->task == GNUNET_SCHEDULER_NO_TASK) @@ -221,7 +221,7 @@ read_blacklist_file () size_t colon_pos; int tsize; struct GNUNET_PeerIdentity pid; - struct stat frstat; + uint64_t fsize; struct GNUNET_CRYPTO_HashAsciiEncoded enc; unsigned int entries_found; char *transport_name; @@ -230,37 +230,34 @@ read_blacklist_file () GNUNET_CONFIGURATION_get_value_filename (GST_cfg, "TRANSPORT", "BLACKLIST_FILE", &fn)) { -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Option `%s' in section `%s' not specified!\n", "BLACKLIST_FILE", "TRANSPORT"); -#endif return; } if (GNUNET_OK != GNUNET_DISK_file_test (fn)) GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); - if (0 != STAT (fn, &frstat)) + if (GNUNET_OK != GNUNET_DISK_file_size (fn, + &fsize, GNUNET_NO, GNUNET_YES)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not read blacklist file `%s'\n"), fn); GNUNET_free (fn); return; } - if (frstat.st_size == 0) + if (fsize == 0) { -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Blacklist file `%s' is empty.\n"), fn); -#endif GNUNET_free (fn); return; } /* FIXME: use mmap */ - data = GNUNET_malloc_large (frstat.st_size); + data = GNUNET_malloc_large (fsize); GNUNET_assert (data != NULL); - if (frstat.st_size != GNUNET_DISK_fn_read (fn, data, frstat.st_size)) + if (fsize != GNUNET_DISK_fn_read (fn, data, fsize)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to read blacklist from `%s'\n"), fn); @@ -270,17 +267,17 @@ read_blacklist_file () } entries_found = 0; pos = 0; - while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos])) + while ((pos < fsize) && isspace ((unsigned char) data[pos])) pos++; - while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) && + while ((fsize >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) && (pos <= - frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))) + fsize - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))) { colon_pos = pos; - while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && + while ((colon_pos < fsize) && (data[colon_pos] != ':') && (!isspace ((unsigned char) data[colon_pos]))) colon_pos++; - if (colon_pos >= frstat.st_size) + if (colon_pos >= fsize) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ @@ -298,12 +295,12 @@ read_blacklist_file () ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"), (unsigned long long) colon_pos); pos = colon_pos; - while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos])) + while ((pos < fsize) && isspace ((unsigned char) data[pos])) pos++; continue; } tsize = colon_pos - pos; - if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || + if ((pos >= fsize) || (pos + tsize >= fsize) || (tsize == 0)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -321,11 +318,9 @@ read_blacklist_file () transport_name = GNUNET_malloc (tsize + 1); memcpy (transport_name, &data[pos], tsize); pos = colon_pos + 1; -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read transport name `%s' in blacklist file.\n", transport_name); -#endif memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); if (!isspace ((unsigned char) @@ -336,7 +331,7 @@ read_blacklist_file () ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"), (unsigned long long) pos); pos++; - while ((pos < frstat.st_size) && (!isspace ((unsigned char) data[pos]))) + while ((pos < fsize) && (!isspace ((unsigned char) data[pos]))) pos++; GNUNET_free_non_null (transport_name); continue; @@ -367,7 +362,7 @@ read_blacklist_file () } pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded); GNUNET_free_non_null (transport_name); - while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos])) + while ((pos < fsize) && isspace ((unsigned char) data[pos])) pos++; } GNUNET_STATISTICS_update (GST_stats, "# Transport entries blacklisted", @@ -450,11 +445,9 @@ transmit_blacklist_message (void *cls, size_t size, void *buf) GNUNET_i2s (&bc->peer)); return 0; } -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending blacklist test for peer `%s' to client\n", GNUNET_i2s (&bc->peer)); -#endif bl = bc->bl_pos; bm.header.size = htons (sizeof (struct BlacklistMessage)); bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY); @@ -483,11 +476,9 @@ do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) bl = bc->bl_pos; if (bl == NULL) { -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No other blacklist clients active, will allow neighbour `%s'\n", GNUNET_i2s (&bc->peer)); -#endif bc->cont (bc->cont_cls, &bc->peer, GNUNET_OK); GNUNET_CONTAINER_DLL_remove(bc_head, bc_tail, bc); GNUNET_free (bc); @@ -578,7 +569,6 @@ test_connection_ok (void *cls, const struct GNUNET_PeerIdentity *neighbour, } - /** * Initialize a blacklisting client. We got a blacklist-init * message from this client, add him to the list of clients @@ -606,6 +596,7 @@ GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client, } bl = bl->next; } + GNUNET_SERVER_client_mark_monitor (client); bl = GNUNET_malloc (sizeof (struct Blacklisters)); bl->client = client; GNUNET_SERVER_client_keep (client); @@ -639,9 +630,7 @@ GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client, bl = bl->next; if (bl == NULL) { -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n"); -#endif /* FIXME: other error handling here!? */ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; @@ -655,20 +644,16 @@ GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client, * cancelled in the meantime... */ if (ntohl (msg->is_allowed) == GNUNET_SYSERR) { -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist check failed, peer not allowed\n"); -#endif bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO); GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc); GNUNET_free (bc); } else { -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist check succeeded, continuing with checks\n"); -#endif bc->bl_pos = bc->bl_pos->next; bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); } @@ -694,11 +679,9 @@ void GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer, const char *transport_name) { -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding peer `%s' with plugin `%s' to blacklist\n", GNUNET_i2s (peer), transport_name); -#endif if (blacklist == NULL) blacklist = GNUNET_CONTAINER_multihashmap_create (TRANSPORT_BLACKLIST_HT_SIZE); @@ -812,7 +795,7 @@ GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc) } if (NULL != bc->th) { - GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th); + GNUNET_SERVER_notify_transmit_ready_cancel (bc->th); bc->th = NULL; } GNUNET_free (bc); diff --git a/src/transport/gnunet-service-transport_blacklist.h b/src/transport/gnunet-service-transport_blacklist.h index 68da7e4..b8335ab 100644 --- a/src/transport/gnunet-service-transport_blacklist.h +++ b/src/transport/gnunet-service-transport_blacklist.h @@ -58,6 +58,7 @@ void GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); + /** * A blacklisting client has sent us reply. Process it. * @@ -69,6 +70,7 @@ void GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); + /** * Add the given peer to the blacklist (for the given transport). * diff --git a/src/transport/gnunet-service-transport_clients.c b/src/transport/gnunet-service-transport_clients.c index d6ff554..b298195 100644 --- a/src/transport/gnunet-service-transport_clients.c +++ b/src/transport/gnunet-service-transport_clients.c @@ -102,7 +102,7 @@ struct TransportClient /** * Current transmit request handle. */ - struct GNUNET_CONNECTION_TransmitHandle *th; + struct GNUNET_SERVER_TransmitHandle *th; /** * Length of the list of messages pending for this client. @@ -208,10 +208,7 @@ setup_client (struct GNUNET_SERVER_Client *client) GNUNET_assert (lookup_client (client) == NULL); tc = GNUNET_malloc (sizeof (struct TransportClient)); tc->client = client; - -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc); -#endif return tc; } @@ -293,10 +290,8 @@ transmit_to_client_callback (void *cls, size_t size, void *buf) tc->th = NULL; if (buf == NULL) { -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission to client failed, closing connection.\n"); -#endif return 0; } cbuf = buf; @@ -307,11 +302,9 @@ transmit_to_client_callback (void *cls, size_t size, void *buf) msize = ntohs (msg->size); if (msize + tsize > size) break; -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting message of type %u to client %p.\n", ntohs (msg->type), tc); -#endif GNUNET_CONTAINER_DLL_remove (tc->message_queue_head, tc->message_queue_tail, q); tc->message_count--; @@ -346,6 +339,12 @@ unicast (struct TransportClient *tc, const struct GNUNET_MessageHeader *msg, struct ClientMessageQueueEntry *q; uint16_t msize; + if (msg == NULL) + { + GNUNET_break (0); + return; + } + if ((tc->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -403,10 +402,8 @@ client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) tc = lookup_client (client); if (tc == NULL) return; -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Client %p disconnected, cleaning up.\n", tc); -#endif while (NULL != (mqe = tc->message_queue_head)) { GNUNET_CONTAINER_DLL_remove (tc->message_queue_head, tc->message_queue_tail, @@ -417,7 +414,7 @@ client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc); if (tc->th != NULL) { - GNUNET_CONNECTION_notify_transmit_ready_cancel (tc->th); + GNUNET_SERVER_notify_transmit_ready_cancel (tc->th); tc->th = NULL; } GNUNET_break (0 == tc->message_count); @@ -448,7 +445,7 @@ notify_client_about_neighbour (void *cls, size_t size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_ATS_Information); - char buf[size]; + char buf[size] GNUNET_ALIGN; GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); cim = (struct ConnectInfoMessage *) buf; @@ -481,18 +478,14 @@ clients_handle_start (void *cls, struct GNUNET_SERVER_Client *client, tc = lookup_client (client); -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Client %p sent START\n", tc); -#endif if (tc != NULL) { /* got 'start' twice from the same client, not allowed */ -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "TransportClient %p ServerClient %p sent multiple START messages\n", tc, tc->client); -#endif GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; @@ -623,23 +616,16 @@ clients_handle_send (void *cls, struct GNUNET_SERVER_Client *client, GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# bytes payload received for other peers"), msize, - GNUNET_NO); -#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' request from client with target `%4s' and first message of type %u and total size %u\n", "SEND", GNUNET_i2s (&obm->peer), ntohs (obmm->type), msize); -#endif if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer)) { /* not connected, not allowed to send; can happen due to asynchronous operations */ -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not send message to peer `%s': not connected\n", GNUNET_i2s (&obm->peer)); -#endif GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# bytes payload dropped (other peer was not connected)"), @@ -695,11 +681,9 @@ clients_handle_request_connect (void *cls, struct GNUNET_SERVER_Client *client, gettext_noop ("# REQUEST CONNECT messages received"), 1, GNUNET_NO); -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer `%s'\n", GNUNET_i2s (&trcm->peer)); -#endif (void) GST_blacklist_test_allowed (&trcm->peer, NULL, &try_connect_if_allowed, NULL); GNUNET_SERVER_receive_done (client, GNUNET_OK); diff --git a/src/transport/gnunet-service-transport_hello.c b/src/transport/gnunet-service-transport_hello.c index 120f176..870c083 100644 --- a/src/transport/gnunet-service-transport_hello.c +++ b/src/transport/gnunet-service-transport_hello.c @@ -162,18 +162,18 @@ refresh_hello_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) gc.expiration = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION); + GNUNET_free (our_hello); our_hello = GNUNET_HELLO_create (&GST_my_public_key, &address_generator, &gc); -#if DEBUG_TRANSPORT + GNUNET_assert (NULL != our_hello); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size (our_hello)); -#endif GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# refreshed my HELLO"), 1, GNUNET_NO); if (NULL != hello_cb) hello_cb (hello_cb_cls, GST_hello_get ()); - GNUNET_PEERINFO_add_peer (GST_peerinfo, our_hello); + GNUNET_PEERINFO_add_peer (GST_peerinfo, our_hello, NULL, NULL); hello_task = GNUNET_SCHEDULER_add_delayed (HELLO_REFRESH_PERIOD, &refresh_hello_task, NULL); @@ -206,6 +206,7 @@ GST_hello_start (GST_HelloCallback cb, void *cb_cls) hello_cb = cb; hello_cb_cls = cb_cls; our_hello = GNUNET_HELLO_create (&GST_my_public_key, NULL, NULL); + GNUNET_assert (NULL != our_hello); refresh_hello (); } @@ -255,13 +256,11 @@ GST_hello_modify_addresses (int addremove, { struct OwnAddressList *al; -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - (add_remove == - GNUNET_YES) ? "Adding `%s':%s to the set of our addresses\n" : - "Removing `%s':%s from the set of our addresses\n", - GST_plugins_a2s (address), p->short_name); -#endif + (addremove == + GNUNET_YES) ? "Adding `%s' to the set of our addresses\n" : + "Removing `%s' from the set of our addresses\n", + GST_plugins_a2s (address)); GNUNET_assert (address != NULL); if (GNUNET_NO == addremove) { diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c index 3e8ef5a..c580168 100644 --- a/src/transport/gnunet-service-transport_neighbours.c +++ b/src/transport/gnunet-service-transport_neighbours.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2010,2011 Christian Grothoff (and other contributing authors) + (C) 2010,2011,2012 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 @@ -22,6 +22,10 @@ * @file transport/gnunet-service-transport_neighbours.c * @brief neighbour management * @author Christian Grothoff + * + * TODO: + * - "address_change_cb" is NEVER invoked; when should we call this one exactly? + * - TEST, TEST, TEST... */ #include "platform.h" #include "gnunet_ats_service.h" @@ -42,6 +46,12 @@ #define NEIGHBOUR_TABLE_SIZE 256 /** + * Time we give plugin to transmit DISCONNECT message before the + * neighbour entry self-destructs. + */ +#define DISCONNECT_SENT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100) + +/** * How often must a peer violate bandwidth quotas before we start * to simply drop its messages? */ @@ -50,38 +60,53 @@ /** * How often do we send KEEPALIVE messages to each of our neighbours and measure * the latency with this neighbour? - * (idle timeout is 5 minutes or 300 seconds, so with 30s interval we - * send 10 keepalives in each interval, so 10 messages would need to be + * (idle timeout is 5 minutes or 300 seconds, so with 100s interval we + * send 3 keepalives in each interval, so 3 messages would need to be * lost in a row for a disconnect). */ -#define KEEPALIVE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) +#define KEEPALIVE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100) +/** + * How long are we willing to wait for a response from ATS before timing out? + */ +#define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500) -#define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) - -#define FAST_RECONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) - +/** + * How long are we willing to wait for an ACK from the other peer before + * giving up on our connect operation? + */ #define SETUP_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) -#define TEST_NEW_CODE GNUNET_NO +/** + * How long are we willing to wait for a successful reconnect if + * an existing connection went down? Much shorter than the + * usual SETUP_CONNECTION_TIMEOUT as we do not inform the + * higher layers about the disconnect during this period. + */ +#define FAST_RECONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** - * Entry in neighbours. + * How long are we willing to wait for a response from the blacklist + * subsystem before timing out? */ -struct NeighbourMapEntry; +#define BLACKLIST_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500) + GNUNET_NETWORK_STRUCT_BEGIN /** - * Message a peer sends to another to indicate its - * preference for communicating via a particular - * session (and the desire to establish a real - * connection). + * Message a peer sends to another to indicate that it intends to + * setup a connection/session for data exchange. A 'SESSION_CONNECT' + * should be answered with a 'SESSION_CONNECT_ACK' with the same body + * to confirm. A 'SESSION_CONNECT_ACK' should then be followed with + * a 'SESSION_ACK'. Once the 'SESSION_ACK' is received, both peers + * should be connected. */ struct SessionConnectMessage { /** * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT' + * or 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK' */ struct GNUNET_MessageHeader header; @@ -99,6 +124,12 @@ struct SessionConnectMessage }; +/** + * Message we send to the other peer to notify him that we intentionally + * are disconnecting (to reduce timeouts). This is just a friendly + * notification, peers must not rely on always receiving disconnect + * messages. + */ struct SessionDisconnectMessage { /** @@ -136,8 +167,10 @@ struct SessionDisconnectMessage struct GNUNET_CRYPTO_RsaSignature signature; }; + GNUNET_NETWORK_STRUCT_END + /** * For each neighbour we keep a list of messages * that we still want to transmit to the neighbour. @@ -156,12 +189,6 @@ struct MessageQueue struct MessageQueue *prev; /** - * Once this message is actively being transmitted, which - * neighbour is it associated with? - */ - struct NeighbourMapEntry *n; - - /** * Function to call once we're done. */ GST_NeighbourSendContinuation cont; @@ -190,44 +217,196 @@ struct MessageQueue }; +/** + * Possible state of a neighbour. Initially, we are S_NOT_CONNECTED. + * + * Then, there are two main paths. If we receive a CONNECT message, we + * first run a check against the blacklist and ask ATS for a + * suggestion. (S_CONNECT_RECV_ATS). If the blacklist comes back + * positive, we give the address to ATS. If ATS makes a suggestion, + * we ALSO give that suggestion to the blacklist + * (S_CONNECT_RECV_BLACKLIST). Once the blacklist approves the + * address we got from ATS, we send our CONNECT_ACK and go to + * S_CONNECT_RECV_ACK. If we receive a SESSION_ACK, we go to + * S_CONNECTED (and notify everyone about the new connection). If the + * operation times out, we go to S_DISCONNECT. + * + * The other case is where we transmit a CONNECT message first. We + * start with S_INIT_ATS. If we get an address, we enter + * S_INIT_BLACKLIST and check the blacklist. If the blacklist is OK + * with the connection, we actually send the CONNECT message and go to + * state S_CONNECT_SENT. Once we receive a CONNECT_ACK, we go to + * S_CONNECTED (and notify everyone about the new connection and send + * back a SESSION_ACK). If the operation times out, we go to + * S_DISCONNECT. + * + * If the session is in trouble (i.e. transport-level disconnect or + * timeout), we go to S_RECONNECT_ATS where we ask ATS for a new + * address (we don't notify anyone about the disconnect yet). Once we + * have a new address, we go to S_RECONNECT_BLACKLIST to check the new + * address against the blacklist. If the blacklist approves, we enter + * S_RECONNECT_SENT and send a CONNECT message. If we receive a + * CONNECT_ACK, we go to S_CONNECTED and nobody noticed that we had + * trouble; we also send a SESSION_ACK at this time just in case. If + * the operation times out, we go to S_DISCONNECT (and notify everyone + * about the lost connection). + * + * If ATS decides to switch addresses while we have a normal + * connection, we go to S_CONNECTED_SWITCHING_BLACKLIST to check the + * new address against the blacklist. If the blacklist approves, we + * go to S_CONNECTED_SWITCHING_CONNECT_SENT and send a + * SESSION_CONNECT. If we get a SESSION_ACK back, we switch the + * primary connection to the suggested alternative from ATS, go back + * to S_CONNECTED and send a SESSION_ACK to the other peer just to be + * sure. If the operation times out (or the blacklist disapproves), + * we go to S_CONNECTED (and notify ATS that the given alternative + * address is "invalid"). + * + * Once a session is in S_DISCONNECT, it is cleaned up and then goes + * to (S_DISCONNECT_FINISHED). If we receive an explicit disconnect + * request, we can go from any state to S_DISCONNECT, possibly after + * generating disconnect notifications. + * + * Note that it is quite possible that while we are in any of these + * states, we could receive a 'CONNECT' request from the other peer. + * We then enter a 'weird' state where we pursue our own primary state + * machine (as described above), but with the 'send_connect_ack' flag + * set to 1. If our state machine allows us to send a 'CONNECT_ACK' + * (because we have an acceptable address), we send the 'CONNECT_ACK' + * and set the 'send_connect_ack' to 2. If we then receive a + * 'SESSION_ACK', we go to 'S_CONNECTED' (and reset 'send_connect_ack' + * to 0). + * + */ enum State { /** * fresh peer or completely disconnected */ - S_NOT_CONNECTED, + S_NOT_CONNECTED = 0, + + /** + * Asked to initiate connection, trying to get address from ATS + */ + S_INIT_ATS, + + /** + * Asked to initiate connection, trying to get address approved + * by blacklist. + */ + S_INIT_BLACKLIST, /** - * sent CONNECT message to other peer, waiting for CONNECT_ACK + * Sent CONNECT message to other peer, waiting for CONNECT_ACK */ S_CONNECT_SENT, /** - * received CONNECT message to other peer, sending CONNECT_ACK + * Received a CONNECT, asking ATS about address suggestions. + */ + S_CONNECT_RECV_ATS, + + /** + * Received CONNECT from other peer, got an address, checking with blacklist. + */ + S_CONNECT_RECV_BLACKLIST, + + /** + * CONNECT request from other peer was SESSION_ACK'ed, waiting for + * SESSION_ACK. */ - S_CONNECT_RECV, + S_CONNECT_RECV_ACK, /** - * received ACK or payload + * Got our CONNECT_ACK/SESSION_ACK, connection is up. */ S_CONNECTED, /** - * connection ended, fast reconnect + * Connection got into trouble, rest of the system still believes + * it to be up, but we're getting a new address from ATS. + */ + S_RECONNECT_ATS, + + /** + * Connection got into trouble, rest of the system still believes + * it to be up; we are checking the new address against the blacklist. + */ + S_RECONNECT_BLACKLIST, + + /** + * Sent CONNECT over new address (either by ATS telling us to switch + * addresses or from RECONNECT_ATS); if this fails, we need to tell + * the rest of the system about a disconnect. + */ + S_RECONNECT_SENT, + + /** + * We have some primary connection, but ATS suggested we switch + * to some alternative; we're now checking the alternative against + * the blacklist. + */ + S_CONNECTED_SWITCHING_BLACKLIST, + + /** + * We have some primary connection, but ATS suggested we switch + * to some alternative; we now sent a CONNECT message for the + * alternative session to the other peer and waiting for a + * CONNECT_ACK to make this our primary connection. + */ + S_CONNECTED_SWITCHING_CONNECT_SENT, + + /** + * Disconnect in progress (we're sending the DISCONNECT message to the + * other peer; after that is finished, the state will be cleaned up). */ - S_FAST_RECONNECT, + S_DISCONNECT, /** - * Disconnect in progress + * We're finished with the disconnect; clean up state now! */ - S_DISCONNECT + S_DISCONNECT_FINISHED }; -enum Address_State + +/** + * A possible address we could use to communicate with a neighbour. + */ +struct NeighbourAddress { - USED, - UNUSED, - FRESH, + + /** + * Active session for this address. + */ + struct Session *session; + + /** + * Network-level address information. + */ + struct GNUNET_HELLO_Address *address; + + /** + * Timestamp of the 'SESSION_CONNECT' message we sent to the other + * peer for this address. Use to check that the ACK is in response + * to our most recent 'CONNECT'. + */ + struct GNUNET_TIME_Absolute connect_timestamp; + + /** + * Inbound bandwidth from ATS for this address. + */ + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; + + /** + * Outbound bandwidth from ATS for this address. + */ + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; + + /** + * Did we tell ATS that this is our 'active' address? + */ + int ats_active; + }; @@ -255,14 +434,15 @@ struct NeighbourMapEntry struct MessageQueue *is_active; /** - * Active session for communicating with the peer. + * Primary address we currently use to communicate with the neighbour. */ - struct Session *session; + struct NeighbourAddress primary_address; /** - * Address we currently use. + * Alternative address currently under consideration for communicating + * with the neighbour. */ - struct GNUNET_HELLO_Address *address; + struct NeighbourAddress alternative_address; /** * Identity of this neighbour. @@ -270,93 +450,133 @@ struct NeighbourMapEntry struct GNUNET_PeerIdentity id; /** - * ID of task scheduled to run when this peer is about to - * time out (will free resources associated with the peer). + * Main task that drives this peer (timeouts, keepalives, etc.). + * Always runs the 'master_task'. */ - GNUNET_SCHEDULER_TaskIdentifier timeout_task; + GNUNET_SCHEDULER_TaskIdentifier task; /** - * ID of task scheduled to send keepalives. + * At what time should we sent the next keep-alive message? */ - GNUNET_SCHEDULER_TaskIdentifier keepalive_task; + struct GNUNET_TIME_Absolute keep_alive_time; /** - * ID of task scheduled to run when we should try transmitting - * the head of the message queue. + * At what time did we sent the last keep-alive message? Used + * to calculate round-trip time ("latency"). */ - GNUNET_SCHEDULER_TaskIdentifier transmission_task; + struct GNUNET_TIME_Absolute last_keep_alive_time; /** - * Tracker for inbound bandwidth. + * Timestamp we should include in our next CONNECT_ACK message. + * (only valid if 'send_connect_ack' is GNUNET_YES). Used to build + * our CONNECT_ACK message. */ - struct GNUNET_BANDWIDTH_Tracker in_tracker; + struct GNUNET_TIME_Absolute connect_ack_timestamp; /** - * Inbound bandwidth from ATS, activated when connection is up + * Time where we should cut the connection (timeout) if we don't + * make progress in the state machine (or get a KEEPALIVE_RESPONSE + * if we are in S_CONNECTED). */ - struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; + struct GNUNET_TIME_Absolute timeout; /** - * Inbound bandwidth from ATS, activated when connection is up + * Latest calculated latency value */ - struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; + struct GNUNET_TIME_Relative latency; /** - * Timestamp of the 'SESSION_CONNECT' message we got from the other peer + * Tracker for inbound bandwidth. */ - struct GNUNET_TIME_Absolute connect_ts; + struct GNUNET_BANDWIDTH_Tracker in_tracker; /** - * When did we sent the last keep-alive message? + * How often has the other peer (recently) violated the inbound + * traffic limit? Incremented by 10 per violation, decremented by 1 + * per non-violation (for each time interval). */ - struct GNUNET_TIME_Absolute keep_alive_sent; + unsigned int quota_violation_count; /** - * Latest calculated latency value + * The current state of the peer. */ - struct GNUNET_TIME_Relative latency; + enum State state; /** - * Timeout for ATS - * We asked ATS for a new address for this peer + * Did we sent an KEEP_ALIVE message and are we expecting a response? */ - GNUNET_SCHEDULER_TaskIdentifier ats_suggest; + int expect_latency_response; /** - * Task the resets the peer state after due to an pending - * unsuccessful connection setup + * Flag to set if we still need to send a CONNECT_ACK message to the other peer + * (once we have an address to use and the peer has been allowed by our + * blacklist). Set to 1 if we need to send a CONNECT_ACK. Set to 2 if we + * did send a CONNECT_ACK and should go to 'S_CONNECTED' upon receiving + * a 'SESSION_ACK' (regardless of what our own state machine might say). */ - GNUNET_SCHEDULER_TaskIdentifier state_reset; + int send_connect_ack; + +}; +/** + * Context for blacklist checks and the 'handle_test_blacklist_cont' + * function. Stores information about ongoing blacklist checks. + */ +struct BlackListCheckContext +{ + /** - * How often has the other peer (recently) violated the inbound - * traffic limit? Incremented by 10 per violation, decremented by 1 - * per non-violation (for each time interval). + * We keep blacklist checks in a DLL. */ - unsigned int quota_violation_count; + struct BlackListCheckContext *next; + /** + * We keep blacklist checks in a DLL. + */ + struct BlackListCheckContext *prev; /** - * The current state of the peer - * Element of enum State + * Address that is being checked. */ - int state; + struct NeighbourAddress na; + + /** + * ATS information about the address. + */ + struct GNUNET_ATS_Information *ats; /** - * Did we sent an KEEP_ALIVE message and are we expecting a response? + * Handle to the ongoing blacklist check. */ - int expect_latency_response; - int address_state; + struct GST_BlacklistCheck *bc; + + /** + * Size of the 'ats' array. + */ + uint32_t ats_count; + }; /** - * All known neighbours and their HELLOs. + * Hash map from peer identities to the respective 'struct NeighbourMapEntry'. */ static struct GNUNET_CONTAINER_MultiHashMap *neighbours; /** + * We keep blacklist checks in a DLL so that we can find + * the 'sessions' in their 'struct NeighbourAddress' if + * a session goes down. + */ +static struct BlackListCheckContext *bc_head; + +/** + * We keep blacklist checks in a DLL. + */ +static struct BlackListCheckContext *bc_tail; + +/** * Closure for connect_notify_cb, disconnect_notify_cb and address_change_cb */ static void *callback_cls; @@ -379,7 +599,13 @@ static GNUNET_TRANSPORT_PeerIterateCallback address_change_cb; /** * counter for connected neighbours */ -static int neighbours_connected; +static unsigned int neighbours_connected; + +/** + * Number of bytes we have currently queued for transmission. + */ +static unsigned long long bytes_in_send_queue; + /** * Lookup a neighbour entry in the neighbours hash map. @@ -390,468 +616,395 @@ static int neighbours_connected; static struct NeighbourMapEntry * lookup_neighbour (const struct GNUNET_PeerIdentity *pid) { + if (NULL == neighbours) + return NULL; return GNUNET_CONTAINER_multihashmap_get (neighbours, &pid->hashPubKey); } -/** - * Disconnect from the given neighbour, clean up the record. - * - * @param n neighbour to disconnect from - */ -static void -disconnect_neighbour (struct NeighbourMapEntry *n); - -#define change_state(n, state, ...) change (n, state, __LINE__) - -static int -is_connecting (struct NeighbourMapEntry *n) -{ - if ((n->state > S_NOT_CONNECTED) && (n->state < S_CONNECTED)) - return GNUNET_YES; - return GNUNET_NO; -} - -static int -is_connected (struct NeighbourMapEntry *n) -{ - if (n->state == S_CONNECTED) - return GNUNET_YES; - return GNUNET_NO; -} - -static int -is_disconnecting (struct NeighbourMapEntry *n) -{ - if (n->state == S_DISCONNECT) - return GNUNET_YES; - return GNUNET_NO; -} - static const char * print_state (int state) { + switch (state) { - case S_CONNECTED: - return "S_CONNECTED"; + case S_NOT_CONNECTED: + return "S_NOT_CONNECTED"; + break; + case S_INIT_ATS: + return "S_INIT_ATS"; break; - case S_CONNECT_RECV: - return "S_CONNECT_RECV"; + case S_INIT_BLACKLIST: + return "S_INIT_BLACKLIST"; break; case S_CONNECT_SENT: return "S_CONNECT_SENT"; break; - case S_DISCONNECT: - return "S_DISCONNECT"; + case S_CONNECT_RECV_ATS: + return "S_CONNECT_RECV_ATS"; break; - case S_NOT_CONNECTED: - return "S_NOT_CONNECTED"; + case S_CONNECT_RECV_BLACKLIST: + return "S_CONNECT_RECV_BLACKLIST"; break; - case S_FAST_RECONNECT: - return "S_FAST_RECONNECT"; + case S_CONNECT_RECV_ACK: + return "S_CONNECT_RECV_ACK"; break; - default: - GNUNET_break (0); + case S_CONNECTED: + return "S_CONNECTED"; break; - } - return NULL; -} - -static int -change (struct NeighbourMapEntry *n, int state, int line); - -static void -ats_suggest_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -static void -reset_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct NeighbourMapEntry *n = cls; - - if (n == NULL) - return; - - n->state_reset = GNUNET_SCHEDULER_NO_TASK; - if (n->state == S_CONNECTED) - return; - -#if DEBUG_TRANSPORT - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# failed connection attempts due to timeout"), 1, - GNUNET_NO); -#endif - - /* resetting state */ - - if (n->state == S_FAST_RECONNECT) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Fast reconnect time out, disconnecting peer `%s'\n", - GNUNET_i2s (&n->id)); - disconnect_neighbour(n); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n", - GNUNET_i2s (&n->id), n, print_state(n->state), "S_NOT_CONNECTED", __LINE__); - - n->state = S_NOT_CONNECTED; - - /* destroying address */ - if (n->address != NULL) - { - GNUNET_assert (strlen (n->address->transport_name) > 0); - GNUNET_ATS_address_destroyed (GST_ats, n->address, n->session); - } - - /* request new address */ - if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->ats_suggest); - n->ats_suggest = - GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, - n); - GNUNET_ATS_suggest_address (GST_ats, &n->id); -} - -static int -change (struct NeighbourMapEntry *n, int state, int line) -{ - int previous_state; - /* allowed transitions */ - int allowed = GNUNET_NO; - - previous_state = n->state; - - switch (n->state) - { - case S_NOT_CONNECTED: - if ((state == S_CONNECT_RECV) || (state == S_CONNECT_SENT) || - (state == S_DISCONNECT)) - allowed = GNUNET_YES; + case S_RECONNECT_ATS: + return "S_RECONNECT_ATS"; break; - case S_CONNECT_RECV: - allowed = GNUNET_YES; + case S_RECONNECT_BLACKLIST: + return "S_RECONNECT_BLACKLIST"; break; - case S_CONNECT_SENT: - allowed = GNUNET_YES; + case S_RECONNECT_SENT: + return "S_RECONNECT_SENT"; break; - case S_CONNECTED: - if ((state == S_DISCONNECT) || (state == S_FAST_RECONNECT)) - allowed = GNUNET_YES; + case S_CONNECTED_SWITCHING_BLACKLIST: + return "S_CONNECTED_SWITCHING_BLACKLIST"; + break; + case S_CONNECTED_SWITCHING_CONNECT_SENT: + return "S_CONNECTED_SWITCHING_CONNECT_SENT"; break; case S_DISCONNECT: + return "S_DISCONNECT"; break; - case S_FAST_RECONNECT: - if ((state == S_CONNECTED) || (state == S_DISCONNECT)) - allowed = GNUNET_YES; + case S_DISCONNECT_FINISHED: + return "S_DISCONNECT_FINISHED"; break; default: + return "UNDEFINED"; GNUNET_break (0); break; } - if (allowed == GNUNET_NO) - { - char *old = GNUNET_strdup (print_state (n->state)); - char *new = GNUNET_strdup (print_state (state)); - - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Illegal state transition from `%s' to `%s' in line %u \n", old, - new, line); - GNUNET_break (0); - GNUNET_free (old); - GNUNET_free (new); - return GNUNET_SYSERR; - } - { - char *old = GNUNET_strdup (print_state (n->state)); - char *new = GNUNET_strdup (print_state (state)); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n", - GNUNET_i2s (&n->id), n, old, new, line); - GNUNET_free (old); - GNUNET_free (new); - } - n->state = state; + GNUNET_break (0); + return "UNDEFINED"; +} +/** + * Test if we're connected to the given peer. + * + * @param n neighbour entry of peer to test + * @return GNUNET_YES if we are connected, GNUNET_NO if not + */ +static int +test_connected (struct NeighbourMapEntry *n) +{ + if (NULL == n) + return GNUNET_NO; switch (n->state) { - case S_FAST_RECONNECT: - case S_CONNECT_RECV: + case S_NOT_CONNECTED: + case S_INIT_ATS: + case S_INIT_BLACKLIST: case S_CONNECT_SENT: - if (n->state_reset != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->state_reset); - n->state_reset = - GNUNET_SCHEDULER_add_delayed (SETUP_CONNECTION_TIMEOUT, &reset_task, n); - break; + case S_CONNECT_RECV_ATS: + case S_CONNECT_RECV_BLACKLIST: + case S_CONNECT_RECV_ACK: + return GNUNET_NO; case S_CONNECTED: - case S_NOT_CONNECTED: + case S_RECONNECT_ATS: + case S_RECONNECT_BLACKLIST: + case S_RECONNECT_SENT: + case S_CONNECTED_SWITCHING_BLACKLIST: + case S_CONNECTED_SWITCHING_CONNECT_SENT: + return GNUNET_YES; case S_DISCONNECT: - if (GNUNET_SCHEDULER_NO_TASK != n->state_reset) - { -#if DEBUG_TRANSPORT - char *old = GNUNET_strdup (print_state (n->state)); - char *new = GNUNET_strdup (print_state (state)); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Removed reset task for peer `%s' %s failed in state transition `%s' -> `%s' \n", - GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), old, new); - GNUNET_free (old); - GNUNET_free (new); -#endif - GNUNET_assert (n->state_reset != GNUNET_SCHEDULER_NO_TASK); - GNUNET_SCHEDULER_cancel (n->state_reset); - n->state_reset = GNUNET_SCHEDULER_NO_TASK; - } - break; - + case S_DISCONNECT_FINISHED: + return GNUNET_NO; default: - GNUNET_assert (0); - } - - if (NULL != address_change_cb) - { - if (n->state == S_CONNECTED) - address_change_cb (callback_cls, &n->id, n->address); - else if (previous_state == S_CONNECTED) - address_change_cb (callback_cls, &n->id, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); + GNUNET_break (0); + break; } - - return GNUNET_OK; + return GNUNET_SYSERR; } -static ssize_t -send_with_session (struct NeighbourMapEntry *n, - const char *msgbuf, size_t msgbuf_size, - uint32_t priority, - struct GNUNET_TIME_Relative timeout, - GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +/** + * Send information about a new outbound quota to our clients. + * + * @param target affected peer + * @param quota new quota + */ +static void +send_outbound_quota (const struct GNUNET_PeerIdentity *target, + struct GNUNET_BANDWIDTH_Value32NBO quota) { - struct GNUNET_TRANSPORT_PluginFunctions *papi; - size_t ret = GNUNET_SYSERR; - - GNUNET_assert (n != NULL); - GNUNET_assert (n->session != NULL); - - papi = GST_plugins_find (n->address->transport_name); - if (papi == NULL) - { - if (cont != NULL) - cont (cont_cls, &n->id, GNUNET_SYSERR); - return GNUNET_SYSERR; - } - - ret = papi->send (papi->cls, - n->session, - msgbuf, msgbuf_size, - 0, - timeout, - cont, cont_cls); + struct QuotaSetMessage q_msg; - if ((ret == -1) && (cont != NULL)) - cont (cont_cls, &n->id, GNUNET_SYSERR); - return ret; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending outbound quota of %u Bps for peer `%s' to all clients\n", + ntohl (quota.value__), GNUNET_i2s (target)); + q_msg.header.size = htons (sizeof (struct QuotaSetMessage)); + q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA); + q_msg.quota = quota; + q_msg.peer = (*target); + GST_clients_broadcast (&q_msg.header, GNUNET_NO); } + /** - * Task invoked to start a transmission to another peer. + * We don't need a given neighbour address any more. + * Release its resources and give appropriate notifications + * to ATS and other subsystems. * - * @param cls the 'struct NeighbourMapEntry' - * @param tc scheduler context + * @param na address we are done with; 'na' itself must NOT be 'free'd, only the contents! */ static void -transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); +free_address (struct NeighbourAddress *na) +{ + if (GNUNET_YES == na->ats_active) + { + GST_validation_set_address_use (na->address, na->session, GNUNET_NO, __LINE__); + GNUNET_ATS_address_in_use (GST_ats, na->address, na->session, GNUNET_NO); + } + na->ats_active = GNUNET_NO; + if (NULL != na->address) + { + GNUNET_HELLO_address_free (na->address); + na->address = NULL; + } + na->session = NULL; +} /** - * We're done with our transmission attempt, continue processing. + * Initialize the 'struct NeighbourAddress'. * - * @param cls the 'struct MessageQueue' of the message - * @param receiver intended receiver - * @param success whether it worked or not + * @param na neighbour address to initialize + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL, in which case an + * address must be setup) + * @param bandwidth_in inbound quota to be used when connection is up + * @param bandwidth_out outbound quota to be used when connection is up + * @param is_active GNUNET_YES to mark this as the active address with ATS */ static void -transmit_send_continuation (void *cls, - const struct GNUNET_PeerIdentity *receiver, - int success) +set_address (struct NeighbourAddress *na, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, + int is_active) { - struct MessageQueue *mq = cls; - struct NeighbourMapEntry *n; - struct NeighbourMapEntry *tmp; + struct GNUNET_TRANSPORT_PluginFunctions *papi; - tmp = lookup_neighbour (receiver); - n = mq->n; - if ((NULL != n) && (tmp != NULL) && (tmp == n)) + if (NULL == (papi = GST_plugins_find (address->transport_name))) { - GNUNET_assert (n->is_active == mq); - n->is_active = NULL; - if (success == GNUNET_YES) + GNUNET_break (0); + return; + } + if (session == na->session) + { + na->bandwidth_in = bandwidth_in; + na->bandwidth_out = bandwidth_out; + if (is_active != na->ats_active) { - GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK); - n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n); + na->ats_active = is_active; + GNUNET_ATS_address_in_use (GST_ats, na->address, na->session, is_active); + GST_validation_set_address_use (na->address, na->session, is_active, __LINE__); } + if (GNUNET_YES == is_active) + { + /* FIXME: is this the right place to set quotas? */ + GST_neighbours_set_incoming_quota (&address->peer, bandwidth_in); + send_outbound_quota (&address->peer, bandwidth_out); + } + return; + } + free_address (na); + if (NULL == session) + session = papi->get_session (papi->cls, address); + if (NULL == session) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to obtain new session for peer `%s' and address '%s'\n", + GNUNET_i2s (&address->peer), GST_plugins_a2s (address)); + GNUNET_ATS_address_destroyed (GST_ats, address, NULL); + return; + } + na->address = GNUNET_HELLO_address_copy (address); + na->bandwidth_in = bandwidth_in; + na->bandwidth_out = bandwidth_out; + na->session = session; + na->ats_active = is_active; + if (GNUNET_YES == is_active) + { + /* Telling ATS about new session */ + GNUNET_ATS_address_update (GST_ats, na->address, na->session, NULL, 0); + GNUNET_ATS_address_in_use (GST_ats, na->address, na->session, GNUNET_YES); + GST_validation_set_address_use (na->address, na->session, GNUNET_YES, __LINE__); + + /* FIXME: is this the right place to set quotas? */ + GST_neighbours_set_incoming_quota (&address->peer, bandwidth_in); + send_outbound_quota (&address->peer, bandwidth_out); } -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message of type %u was %s\n", - ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type), - (success == GNUNET_OK) ? "successful" : "FAILED"); -#endif - if (NULL != mq->cont) - mq->cont (mq->cont_cls, success); - GNUNET_free (mq); } /** - * Check the ready list for the given neighbour and if a plugin is - * ready for transmission (and if we have a message), do so! + * Free a neighbour map entry. * - * @param n target peer for which to transmit + * @param n entry to free + * @param keep_sessions GNUNET_NO to tell plugin to terminate sessions, + * GNUNET_YES to keep all sessions */ static void -try_transmission_to_peer (struct NeighbourMapEntry *n) +free_neighbour (struct NeighbourMapEntry *n, int keep_sessions) { struct MessageQueue *mq; - struct GNUNET_TIME_Relative timeout; - ssize_t ret; + struct GNUNET_TRANSPORT_PluginFunctions *papi; - if (n->is_active != NULL) - { - GNUNET_break (0); - return; /* transmission already pending */ - } - if (n->transmission_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_break (0); - return; /* currently waiting for bandwidth */ - } + n->is_active = NULL; /* always free'd by its own continuation! */ + + /* fail messages currently in the queue */ while (NULL != (mq = n->messages_head)) { - timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout); - if (timeout.rel_value > 0) - break; GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); - n->is_active = mq; - mq->n = n; - transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); /* timeout */ + if (NULL != mq->cont) + mq->cont (mq->cont_cls, GNUNET_SYSERR); + GNUNET_free (mq); } - if (NULL == mq) - return; /* no more messages */ - - if (n->address == NULL) + /* It is too late to send other peer disconnect notifications, but at + least internally we need to get clean... */ + if (GNUNET_YES == test_connected (n)) { -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No address for peer `%s'\n", - GNUNET_i2s (&n->id)); -#endif - GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); - transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); - GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK); - n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n); - return; + GNUNET_STATISTICS_set (GST_stats, + gettext_noop ("# peers connected"), + --neighbours_connected, + GNUNET_NO); + disconnect_notify_cb (callback_cls, &n->id); } - if (GST_plugins_find (n->address->transport_name) == NULL) - { - GNUNET_break (0); - return; - } - GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); - n->is_active = mq; - mq->n = n; + /* FIXME-PLUGIN-API: This does not seem to guarantee that all + transport sessions eventually get killed due to inactivity; they + MUST have their own timeout logic (but at least TCP doesn't have + one yet). Are we sure that EVERY 'session' of a plugin is + actually cleaned up this way!? Note that if we are switching + between two TCP sessions to the same peer, the existing plugin + API gives us not even the means to selectively kill only one of + them! Killing all sessions like this seems to be very, very + wrong. */ + if ((GNUNET_NO == keep_sessions) && + (NULL != n->primary_address.address) && + (NULL != (papi = GST_plugins_find (n->primary_address.address->transport_name)))) + papi->disconnect (papi->cls, &n->id); - if ((n->address->address_length == 0) && (n->session == NULL)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No address for peer `%s'\n", - GNUNET_i2s (&n->id)); - transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); - GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK); - n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n); - return; - } + n->state = S_DISCONNECT_FINISHED; - ret = send_with_session(n, - mq->message_buf, mq->message_buf_size, - 0, timeout, - &transmit_send_continuation, mq); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (neighbours, + &n->id.hashPubKey, n)); + + /* cut transport-level connection */ + free_address (&n->primary_address); + free_address (&n->alternative_address); - if (ret == -1) + // FIXME-ATS-API: we might want to be more specific about + // which states we do this from in the future (ATS should + // have given us a 'suggest_address' handle, and if we have + // such a handle, we should cancel the operation here! + GNUNET_ATS_suggest_address_cancel (GST_ats, &n->id); + + if (GNUNET_SCHEDULER_NO_TASK != n->task) { - /* failure, but 'send' would not call continuation in this case, - * so we need to do it here! */ - transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); + GNUNET_SCHEDULER_cancel (n->task); + n->task = GNUNET_SCHEDULER_NO_TASK; } - + /* free rest of memory */ + GNUNET_free (n); } /** - * Task invoked to start a transmission to another peer. + * Transmit a message using the current session of the given + * neighbour. * - * @param cls the 'struct NeighbourMapEntry' - * @param tc scheduler context + * @param n entry for the recipient + * @param msgbuf buffer to transmit + * @param msgbuf_size number of bytes in buffer + * @param priority transmission priority + * @param timeout transmission timeout + * @param cont continuation to call when finished (can be NULL) + * @param cont_cls closure for cont */ static void -transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +send_with_session (struct NeighbourMapEntry *n, + const char *msgbuf, size_t msgbuf_size, + uint32_t priority, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_TransmitContinuation cont, + void *cont_cls) { - struct NeighbourMapEntry *n = cls; + struct GNUNET_TRANSPORT_PluginFunctions *papi; - GNUNET_assert (NULL != lookup_neighbour (&n->id)); - n->transmission_task = GNUNET_SCHEDULER_NO_TASK; - try_transmission_to_peer (n); + GNUNET_assert (n->primary_address.session != NULL); + if ( ( (NULL == (papi = GST_plugins_find (n->primary_address.address->transport_name))) || + (-1 == papi->send (papi->cls, + n->primary_address.session, + msgbuf, msgbuf_size, + priority, + timeout, + cont, cont_cls))) && + (NULL != cont) ) + cont (cont_cls, &n->id, GNUNET_SYSERR); + GNUNET_break (NULL != papi); } /** - * Initialize the neighbours subsystem. + * Master task run for every neighbour. Performs all of the time-related + * activities (keep alive, send next message, disconnect if idle, finish + * clean up after disconnect). * - * @param cls closure for callbacks - * @param connect_cb function to call if we connect to a peer - * @param disconnect_cb function to call if we disconnect from a peer - * @param peer_address_cb function to call if we change an active address - * of a neighbour + * @param cls the 'struct NeighbourMapEntry' for which we are running + * @param tc scheduler context (unused) */ -void -GST_neighbours_start (void *cls, - GNUNET_TRANSPORT_NotifyConnect connect_cb, - GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb, - GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb) -{ - callback_cls = cls; - connect_notify_cb = connect_cb; - disconnect_notify_cb = disconnect_cb; - address_change_cb = peer_address_cb; - neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE); -} +static void +master_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); +/** + * Function called when the 'DISCONNECT' message has been sent by the + * plugin. Frees the neighbour --- if the entry still exists. + * + * @param cls NULL + * @param target identity of the neighbour that was disconnected + * @param result GNUNET_OK if the disconnect got out successfully + */ static void send_disconnect_cont (void *cls, const struct GNUNET_PeerIdentity *target, int result) { -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending DISCONNECT message to peer `%4s': %i\n", - GNUNET_i2s (target), result); -#endif + struct NeighbourMapEntry *n; + + n = lookup_neighbour (target); + if (NULL == n) + return; /* already gone */ + if (S_DISCONNECT != n->state) + return; /* have created a fresh entry since */ + n->state = S_DISCONNECT; + if (GNUNET_SCHEDULER_NO_TASK != n->task) + GNUNET_SCHEDULER_cancel (n->task); + n->task = GNUNET_SCHEDULER_add_now (&master_task, n); } -static int -send_disconnect (struct NeighbourMapEntry * n) +/** + * Transmit a DISCONNECT message to the other peer. + * + * @param n neighbour to send DISCONNECT message. + */ +static void +send_disconnect (struct NeighbourMapEntry *n) { - size_t ret; struct SessionDisconnectMessage disconnect_msg; -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending DISCONNECT message to peer `%4s'\n", GNUNET_i2s (&n->id)); -#endif - disconnect_msg.header.size = htons (sizeof (struct SessionDisconnectMessage)); disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT); @@ -870,19 +1023,14 @@ send_disconnect (struct NeighbourMapEntry * n) &disconnect_msg.purpose, &disconnect_msg.signature)); - ret = send_with_session (n, - (const char *) &disconnect_msg, sizeof (disconnect_msg), - UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, - &send_disconnect_cont, NULL); - - if (ret == GNUNET_SYSERR) - return GNUNET_SYSERR; - + send_with_session (n, + (const char *) &disconnect_msg, sizeof (disconnect_msg), + UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, + &send_disconnect_cont, NULL); GNUNET_STATISTICS_update (GST_stats, gettext_noop - ("# peers disconnected due to external request"), 1, + ("# DISCONNECT messages sent"), 1, GNUNET_NO); - return GNUNET_OK; } @@ -894,780 +1042,541 @@ send_disconnect (struct NeighbourMapEntry * n) static void disconnect_neighbour (struct NeighbourMapEntry *n) { - struct MessageQueue *mq; - int previous_state; - - previous_state = n->state; - - if (is_disconnecting (n)) - return; - - /* send DISCONNECT MESSAGE */ - if (previous_state == S_CONNECTED) - { - if (GNUNET_OK == send_disconnect (n)) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent DISCONNECT_MSG to `%s'\n", - GNUNET_i2s (&n->id)); - else - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Could not send DISCONNECT_MSG to `%s'\n", - GNUNET_i2s (&n->id)); - } - - change_state (n, S_DISCONNECT); - - if (previous_state == S_CONNECTED) - { - GNUNET_assert (NULL != n->address); - if (n->address_state == USED) - { - GST_validation_set_address_use (n->address, n->session, GNUNET_NO); - GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO); - n->address_state = UNUSED; - } - } - - if (n->address != NULL) - { - struct GNUNET_TRANSPORT_PluginFunctions *papi; - - papi = GST_plugins_find (n->address->transport_name); - if (papi != NULL) - papi->disconnect (papi->cls, &n->id); - } - while (NULL != (mq = n->messages_head)) - { - GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); - if (NULL != mq->cont) - mq->cont (mq->cont_cls, GNUNET_SYSERR); - GNUNET_free (mq); - } - if (NULL != n->is_active) - { - n->is_active->n = NULL; - n->is_active = NULL; - } - - switch (previous_state) + /* depending on state, notify neighbour and/or upper layers of this peer + about disconnect */ + switch (n->state) { + case S_NOT_CONNECTED: + case S_INIT_ATS: + case S_INIT_BLACKLIST: + /* other peer is completely unaware of us, no need to send DISCONNECT */ + n->state = S_DISCONNECT_FINISHED; + free_neighbour (n, GNUNET_NO); + return; + case S_CONNECT_SENT: + send_disconnect (n); + n->state = S_DISCONNECT; + break; + case S_CONNECT_RECV_ATS: + case S_CONNECT_RECV_BLACKLIST: + /* we never ACK'ed the other peer's request, no need to send DISCONNECT */ + n->state = S_DISCONNECT_FINISHED; + free_neighbour (n, GNUNET_NO); + return; + case S_CONNECT_RECV_ACK: + /* we DID ACK the other peer's request, must send DISCONNECT */ + send_disconnect (n); + n->state = S_DISCONNECT; + break; case S_CONNECTED: - GNUNET_assert (neighbours_connected > 0); - neighbours_connected--; - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->keepalive_task); - GNUNET_SCHEDULER_cancel (n->keepalive_task); - n->keepalive_task = GNUNET_SCHEDULER_NO_TASK; - n->expect_latency_response = GNUNET_NO; - GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1, - GNUNET_NO); + case S_RECONNECT_BLACKLIST: + case S_RECONNECT_SENT: + case S_CONNECTED_SWITCHING_BLACKLIST: + case S_CONNECTED_SWITCHING_CONNECT_SENT: + /* we are currently connected, need to send disconnect and do + internal notifications and update statistics */ + send_disconnect (n); + GNUNET_STATISTICS_set (GST_stats, + gettext_noop ("# peers connected"), + --neighbours_connected, + GNUNET_NO); disconnect_notify_cb (callback_cls, &n->id); + n->state = S_DISCONNECT; break; - case S_FAST_RECONNECT: - GNUNET_STATISTICS_update (GST_stats, - gettext_noop ("# fast reconnects failed"), 1, - GNUNET_NO); + case S_RECONNECT_ATS: + /* ATS address request timeout, disconnect without sending disconnect message */ + GNUNET_STATISTICS_set (GST_stats, + gettext_noop ("# peers connected"), + --neighbours_connected, + GNUNET_NO); disconnect_notify_cb (callback_cls, &n->id); + n->state = S_DISCONNECT; + break; + case S_DISCONNECT: + /* already disconnected, ignore */ + break; + case S_DISCONNECT_FINISHED: + /* already cleaned up, how did we get here!? */ + GNUNET_assert (0); break; default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); + GNUNET_break (0); break; } + /* schedule timeout to clean up */ + if (GNUNET_SCHEDULER_NO_TASK != n->task) + GNUNET_SCHEDULER_cancel (n->task); + n->task = GNUNET_SCHEDULER_add_delayed (DISCONNECT_SENT_TIMEOUT, + &master_task, n); +} - GNUNET_ATS_suggest_address_cancel (GST_ats, &n->id); - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (neighbours, - &n->id.hashPubKey, n)); - if (GNUNET_SCHEDULER_NO_TASK != n->ats_suggest) - { - GNUNET_SCHEDULER_cancel (n->ats_suggest); - n->ats_suggest = GNUNET_SCHEDULER_NO_TASK; - } - if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task) - { - GNUNET_SCHEDULER_cancel (n->timeout_task); - n->timeout_task = GNUNET_SCHEDULER_NO_TASK; - } - if (GNUNET_SCHEDULER_NO_TASK != n->transmission_task) +/** + * We're done with our transmission attempt, continue processing. + * + * @param cls the 'struct MessageQueue' of the message + * @param receiver intended receiver + * @param success whether it worked or not + */ +static void +transmit_send_continuation (void *cls, + const struct GNUNET_PeerIdentity *receiver, + int success) +{ + struct MessageQueue *mq = cls; + struct NeighbourMapEntry *n; + + if (NULL == (n = lookup_neighbour (receiver))) { - GNUNET_SCHEDULER_cancel (n->transmission_task); - n->transmission_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_free (mq); + return; /* disconnect or other error while transmitting, can happen */ } - if (NULL != n->address) + if (n->is_active == mq) { - GNUNET_HELLO_address_free (n->address); - n->address = NULL; - } - n->session = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting peer `%4s', %X\n", - GNUNET_i2s (&n->id), n); - GNUNET_free (n); + /* this is still "our" neighbour, remove us from its queue + and allow it to send the next message now */ + n->is_active = NULL; + if (GNUNET_SCHEDULER_NO_TASK != n->task) + GNUNET_SCHEDULER_cancel (n->task); + n->task = GNUNET_SCHEDULER_add_now (&master_task, n); + } + GNUNET_assert (bytes_in_send_queue >= mq->message_buf_size); + bytes_in_send_queue -= mq->message_buf_size; + GNUNET_STATISTICS_set (GST_stats, + gettext_noop + ("# bytes in message queue for other peers"), + bytes_in_send_queue, GNUNET_NO); + if (GNUNET_OK == success) + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# messages transmitted to other peers"), + 1, GNUNET_NO); + else + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# transmission failures for messages to other peers"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message to `%s' of type %u was a %s\n", + GNUNET_i2s (receiver), + ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type), + (success == GNUNET_OK) ? "success" : "FAILURE"); + if (NULL != mq->cont) + mq->cont (mq->cont_cls, success); + GNUNET_free (mq); } /** - * Peer has been idle for too long. Disconnect. + * Check the message list for the given neighbour and if we can + * send a message, do so. This function should only be called + * if the connection is at least generally ready for transmission. + * While we will only send one message at a time, no bandwidth + * quota management is performed here. If a message was given to + * the plugin, the continuation will automatically re-schedule + * the 'master' task once the next message might be transmitted. * - * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle - * @param tc scheduler context + * @param n target peer for which to transmit */ static void -neighbour_timeout_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +try_transmission_to_peer (struct NeighbourMapEntry *n) { - struct NeighbourMapEntry *n = cls; + struct MessageQueue *mq; + struct GNUNET_TIME_Relative timeout; - n->timeout_task = GNUNET_SCHEDULER_NO_TASK; + if (NULL == n->primary_address.address) + { + /* no address, why are we here? */ + GNUNET_break (0); + return; + } + if ((0 == n->primary_address.address->address_length) && + (NULL == n->primary_address.session)) + { + /* no address, why are we here? */ + GNUNET_break (0); + return; + } + if (NULL != n->is_active) + { + /* transmission already pending */ + return; + } - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# peers disconnected due to timeout"), 1, - GNUNET_NO); - disconnect_neighbour (n); + /* timeout messages from the queue that are past their due date */ + while (NULL != (mq = n->messages_head)) + { + timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout); + if (timeout.rel_value > 0) + break; + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# messages timed out while in transport queue"), + 1, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); + n->is_active = mq; + transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); /* timeout */ + } + if (NULL == mq) + return; /* no more messages */ + GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); + n->is_active = mq; + send_with_session (n, + mq->message_buf, mq->message_buf_size, + 0 /* priority */, timeout, + &transmit_send_continuation, mq); } /** - * Send another keepalive message. + * Send keepalive message to the neighbour. Must only be called + * if we are on 'connected' state. Will internally determine + * if a keepalive is truly needed (so can always be called). * - * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle - * @param tc scheduler context + * @param n neighbour that went idle and needs a keepalive */ static void -neighbour_keepalive_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +send_keepalive (struct NeighbourMapEntry *n) { - struct NeighbourMapEntry *n = cls; struct GNUNET_MessageHeader m; - int ret; GNUNET_assert (S_CONNECTED == n->state); - n->keepalive_task = - GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY, - &neighbour_keepalive_task, n); - - GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# keepalives sent"), 1, - GNUNET_NO); + if (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time).rel_value > 0) + return; /* no keepalive needed at this time */ m.size = htons (sizeof (struct GNUNET_MessageHeader)); m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE); - - ret = send_with_session (n, - (const void *) &m, sizeof (m), - UINT32_MAX /* priority */ , - GNUNET_TIME_UNIT_FOREVER_REL, - NULL, NULL); - - n->expect_latency_response = GNUNET_NO; - n->keep_alive_sent = GNUNET_TIME_absolute_get_zero (); - if (ret != GNUNET_SYSERR) - { - n->expect_latency_response = GNUNET_YES; - n->keep_alive_sent = GNUNET_TIME_absolute_get (); - } - + send_with_session (n, + (const void *) &m, sizeof (m), + UINT32_MAX /* priority */, + KEEPALIVE_FREQUENCY, + NULL, NULL); + GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# keepalives sent"), 1, + GNUNET_NO); + n->expect_latency_response = GNUNET_YES; + n->last_keep_alive_time = GNUNET_TIME_absolute_get (); + n->keep_alive_time = GNUNET_TIME_relative_to_absolute (KEEPALIVE_FREQUENCY); } /** - * Disconnect from the given neighbour. + * Keep the connection to the given neighbour alive longer, + * we received a KEEPALIVE (or equivalent); send a response. * - * @param cls unused - * @param key hash of neighbour's public key (not used) - * @param value the 'struct NeighbourMapEntry' of the neighbour + * @param neighbour neighbour to keep alive (by sending keep alive response) */ -static int -disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value) +void +GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour) { - struct NeighbourMapEntry *n = value; + struct NeighbourMapEntry *n; + struct GNUNET_MessageHeader m; -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n", - GNUNET_i2s (&n->id), "SHUTDOWN_TASK"); -#endif - if (S_CONNECTED == n->state) + if (NULL == (n = lookup_neighbour (neighbour))) + { GNUNET_STATISTICS_update (GST_stats, gettext_noop - ("# peers disconnected due to global disconnect"), + ("# KEEPALIVE messages discarded (peer unknown)"), 1, GNUNET_NO); - disconnect_neighbour (n); - return GNUNET_OK; -} - - -static void -ats_suggest_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct NeighbourMapEntry *n = cls; - - n->ats_suggest = GNUNET_SCHEDULER_NO_TASK; - - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "ATS did not suggested address to connect to peer `%s'\n", - GNUNET_i2s (&n->id)); - - disconnect_neighbour (n); -} - -/** - * Cleanup the neighbours subsystem. - */ -void -GST_neighbours_stop () -{ - // This can happen during shutdown - if (neighbours == NULL) + return; + } + if (NULL == n->primary_address.session) { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# KEEPALIVE messages discarded (no session)"), + 1, GNUNET_NO); return; } - - GNUNET_CONTAINER_multihashmap_iterate (neighbours, &disconnect_all_neighbours, - NULL); - GNUNET_CONTAINER_multihashmap_destroy (neighbours); -// GNUNET_assert (neighbours_connected == 0); - neighbours = NULL; - callback_cls = NULL; - connect_notify_cb = NULL; - disconnect_notify_cb = NULL; - address_change_cb = NULL; + /* send reply to allow neighbour to measure latency */ + m.size = htons (sizeof (struct GNUNET_MessageHeader)); + m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE); + send_with_session(n, + (const void *) &m, sizeof (m), + UINT32_MAX /* priority */, + KEEPALIVE_FREQUENCY, + NULL, NULL); } -struct ContinutionContext -{ - struct GNUNET_HELLO_Address *address; - - struct Session *session; -}; - -static void -send_outbound_quota (const struct GNUNET_PeerIdentity *target, - struct GNUNET_BANDWIDTH_Value32NBO quota) -{ - struct QuotaSetMessage q_msg; - -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending outbound quota of %u Bps for peer `%s' to all clients\n", - ntohl (quota.value__), GNUNET_i2s (target)); -#endif - q_msg.header.size = htons (sizeof (struct QuotaSetMessage)); - q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA); - q_msg.quota = quota; - q_msg.peer = (*target); - GST_clients_broadcast (&q_msg.header, GNUNET_NO); -} /** - * We tried to send a SESSION_CONNECT message to another peer. If this - * succeeded, we change the state. If it failed, we should tell - * ATS to not use this address anymore (until it is re-validated). + * We received a KEEP_ALIVE_RESPONSE message and use this to calculate + * latency to this peer. Pass the updated information (existing ats + * plus calculated latency) to ATS. * - * @param cls the 'struct GNUNET_HELLO_Address' of the address that was tried - * @param target peer to send the message to - * @param success GNUNET_OK on success + * @param neighbour neighbour to keep alive + * @param ats performance data + * @param ats_count number of entries in ats */ -static void -send_connect_continuation (void *cls, const struct GNUNET_PeerIdentity *target, - int success) +void +GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) { - struct ContinutionContext *cc = cls; - struct NeighbourMapEntry *n = lookup_neighbour (&cc->address->peer); + struct NeighbourMapEntry *n; + uint32_t latency; + struct GNUNET_ATS_Information ats_new[ats_count + 1]; - if (GNUNET_YES != success) - { - GNUNET_assert (strlen (cc->address->transport_name) > 0); - GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session); - } - if ((NULL == neighbours) || (NULL == n) || (n->state == S_DISCONNECT)) + if (NULL == (n = lookup_neighbour (neighbour))) { - GNUNET_HELLO_address_free (cc->address); - GNUNET_free (cc); + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# KEEPALIVE_RESPONSE messages discarded (not connected)"), + 1, GNUNET_NO); return; } - - if ((GNUNET_YES == success) && - ((n->state == S_NOT_CONNECTED) || (n->state == S_CONNECT_SENT))) + if ( (S_CONNECTED != n->state) || + (GNUNET_YES != n->expect_latency_response) ) { - change_state (n, S_CONNECT_SENT); - GNUNET_HELLO_address_free (cc->address); - GNUNET_free (cc); + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# KEEPALIVE_RESPONSE messages discarded (not expected)"), + 1, GNUNET_NO); return; } - - if ((GNUNET_NO == success) && - ((n->state == S_NOT_CONNECTED) || (n->state == S_CONNECT_SENT))) - { -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to send CONNECT_MSG to peer `%4s' with address '%s' session %p, asking ATS for new address \n", - GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session); -#endif - change_state (n, S_NOT_CONNECTED); - if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->ats_suggest); - n->ats_suggest = - GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, &ats_suggest_cancel, - n); - GNUNET_ATS_suggest_address (GST_ats, &n->id); - } - GNUNET_HELLO_address_free (cc->address); - GNUNET_free (cc); + n->expect_latency_response = GNUNET_NO; + n->latency = GNUNET_TIME_absolute_get_duration (n->last_keep_alive_time); + n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Latency for peer `%s' is %llu ms\n", + GNUNET_i2s (&n->id), n->latency.rel_value); + memcpy (ats_new, ats, sizeof (struct GNUNET_ATS_Information) * ats_count); + /* append latency */ + ats_new[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); + if (n->latency.rel_value > UINT32_MAX) + latency = UINT32_MAX; + else + latency = n->latency.rel_value; + ats_new[ats_count].value = htonl (latency); + GNUNET_ATS_address_update (GST_ats, + n->primary_address.address, + n->primary_address.session, ats_new, + ats_count + 1); } /** - * We tried to switch addresses with an peer already connected. If it failed, - * we should tell ATS to not use this address anymore (until it is re-validated). + * We have received a message from the given sender. How long should + * we delay before receiving more? (Also used to keep the peer marked + * as live). * - * @param cls the 'struct NeighbourMapEntry' - * @param target peer to send the message to - * @param success GNUNET_OK on success + * @param sender sender of the message + * @param size size of the message + * @param do_forward set to GNUNET_YES if the message should be forwarded to clients + * GNUNET_NO if the neighbour is not connected or violates the quota, + * GNUNET_SYSERR if the connection is not fully up yet + * @return how long to wait before reading more from this sender */ -static void -send_switch_address_continuation (void *cls, - const struct GNUNET_PeerIdentity *target, - int success) +struct GNUNET_TIME_Relative +GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity + *sender, ssize_t size, int *do_forward) { - struct ContinutionContext *cc = cls; struct NeighbourMapEntry *n; - - if (neighbours == NULL) + struct GNUNET_TIME_Relative ret; + + if (NULL == neighbours) { - GNUNET_HELLO_address_free (cc->address); - GNUNET_free (cc); - return; /* neighbour is going away */ + *do_forward = GNUNET_NO; + return GNUNET_TIME_UNIT_FOREVER_REL; /* This can happen during shutdown */ } - - n = lookup_neighbour (&cc->address->peer); - if ((n == NULL) || (is_disconnecting (n))) + if (NULL == (n = lookup_neighbour (sender))) + { + GST_neighbours_try_connect (sender); + if (NULL == (n = lookup_neighbour (sender))) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# messages discarded due to lack of neighbour record"), + 1, GNUNET_NO); + *do_forward = GNUNET_NO; + return GNUNET_TIME_UNIT_ZERO; + } + } + if (! test_connected (n)) { - GNUNET_HELLO_address_free (cc->address); - GNUNET_free (cc); - return; /* neighbour is going away */ + *do_forward = GNUNET_SYSERR; + return GNUNET_TIME_UNIT_ZERO; } - - GNUNET_assert ((n->state == S_CONNECTED) || (n->state == S_FAST_RECONNECT)); - if (GNUNET_YES != success) + if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size)) { -#if DEBUG_TRANSPORT + n->quota_violation_count++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to switch connected peer `%s' to address '%s' session %X, asking ATS for new address \n", - GNUNET_i2s (&n->id), GST_plugins_a2s (cc->address), cc->session); -#endif - GNUNET_assert (strlen (cc->address->transport_name) > 0); - GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session); - - if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->ats_suggest); - n->ats_suggest = - GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, - n); - GNUNET_ATS_suggest_address (GST_ats, &n->id); - GNUNET_HELLO_address_free (cc->address); - GNUNET_free (cc); - return; + "Bandwidth quota (%u b/s) violation detected (total of %u).\n", + n->in_tracker.available_bytes_per_s__, + n->quota_violation_count); + /* Discount 32k per violation */ + GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024); } - /* Tell ATS that switching addresses was successful */ - switch (n->state) + else { - case S_CONNECTED: - if (n->address_state == FRESH) + if (n->quota_violation_count > 0) { - GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES); - GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0); - if (cc->session != n->session) - GNUNET_break (0); - GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES); - n->address_state = USED; + /* try to add 32k back */ + GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024); + n->quota_violation_count--; } - break; - case S_FAST_RECONNECT: -#if DEBUG_TRANSPORT + } + if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# bandwidth quota violations by other peers"), + 1, GNUNET_NO); + *do_forward = GNUNET_NO; + return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT; + } + *do_forward = GNUNET_YES; + ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024); + if (ret.rel_value > 0) + { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Successful fast reconnect to peer `%s'\n", - GNUNET_i2s (&n->id)); -#endif - change_state (n, S_CONNECTED); - neighbours_connected++; - GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1, - GNUNET_NO); - - if (n->address_state == FRESH) - { - GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES); - GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0); - GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES); - n->address_state = USED; - } - - if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK) - n->keepalive_task = - GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n); - - /* Updating quotas */ - GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in); - send_outbound_quota (target, n->bandwidth_out); - - default: - break; + "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n", + (unsigned long long) n->in_tracker. + consumption_since_last_update__, + (unsigned int) n->in_tracker.available_bytes_per_s__, + (unsigned long long) ret.rel_value); + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# ms throttling suggested"), + (int64_t) ret.rel_value, GNUNET_NO); } - GNUNET_HELLO_address_free (cc->address); - GNUNET_free (cc); + return ret; } /** - * We tried to send a SESSION_CONNECT message to another peer. If this - * succeeded, we change the state. If it failed, we should tell - * ATS to not use this address anymore (until it is re-validated). + * Transmit a message to the given target using the active connection. * - * @param cls the 'struct NeighbourMapEntry' - * @param target peer to send the message to - * @param success GNUNET_OK on success + * @param target destination + * @param msg message to send + * @param msg_size number of bytes in msg + * @param timeout when to fail with timeout + * @param cont function to call when done + * @param cont_cls closure for 'cont' */ -static void -send_connect_ack_continuation (void *cls, - const struct GNUNET_PeerIdentity *target, - int success) +void +GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg, + size_t msg_size, struct GNUNET_TIME_Relative timeout, + GST_NeighbourSendContinuation cont, void *cont_cls) { - struct ContinutionContext *cc = cls; struct NeighbourMapEntry *n; + struct MessageQueue *mq; - if (neighbours == NULL) - { - GNUNET_HELLO_address_free (cc->address); - GNUNET_free (cc); - return; /* neighbour is going away */ - } - - n = lookup_neighbour (&cc->address->peer); - if ((n == NULL) || (is_disconnecting (n))) + /* All ove these cases should never happen; they are all API violations. + But we check anyway, just to be sure. */ + if (NULL == (n = lookup_neighbour (target))) { - GNUNET_HELLO_address_free (cc->address); - GNUNET_free (cc); - return; /* neighbour is going away */ + GNUNET_break (0); + if (NULL != cont) + cont (cont_cls, GNUNET_SYSERR); + return; } - - if (GNUNET_YES == success) + if (GNUNET_YES != test_connected (n)) { - GNUNET_HELLO_address_free (cc->address); - GNUNET_free (cc); - return; /* sending successful */ + GNUNET_break (0); + if (NULL != cont) + cont (cont_cls, GNUNET_SYSERR); + return; } - - /* sending failed, ask for next address */ -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to send CONNECT_MSG to peer `%4s' with address '%s' session %X, asking ATS for new address \n", - GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session); -#endif - change_state (n, S_NOT_CONNECTED); - GNUNET_assert (strlen (cc->address->transport_name) > 0); - GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session); - - if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->ats_suggest); - n->ats_suggest = - GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, - n); - GNUNET_ATS_suggest_address (GST_ats, &n->id); - GNUNET_HELLO_address_free (cc->address); - GNUNET_free (cc); + bytes_in_send_queue += msg_size; + GNUNET_STATISTICS_set (GST_stats, + gettext_noop + ("# bytes in message queue for other peers"), + bytes_in_send_queue, GNUNET_NO); + mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size); + mq->cont = cont; + mq->cont_cls = cont_cls; + memcpy (&mq[1], msg, msg_size); + mq->message_buf = (const char *) &mq[1]; + mq->message_buf_size = msg_size; + mq->timeout = GNUNET_TIME_relative_to_absolute (timeout); + GNUNET_CONTAINER_DLL_insert_tail (n->messages_head, n->messages_tail, mq); + if ( (NULL != n->is_active) || + ( (NULL == n->primary_address.session) && (NULL == n->primary_address.address)) ) + return; + if (GNUNET_SCHEDULER_NO_TASK != n->task) + GNUNET_SCHEDULER_cancel (n->task); + n->task = GNUNET_SCHEDULER_add_now (&master_task, n); } /** - * For an existing neighbour record, set the active connection to - * use the given address. + * Send a SESSION_CONNECT message via the given address. * - * @param peer identity of the peer to switch the address for - * @param address address of the other peer, NULL if other peer - * connected to us - * @param session session to use (or NULL) - * @param ats performance data - * @param ats_count number of entries in ats - * @param bandwidth_in inbound quota to be used when connection is up - * @param bandwidth_out outbound quota to be used when connection is up - * @return GNUNET_YES if we are currently connected, GNUNET_NO if the - * connection is not up (yet) + * @param na address to use */ -int -GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Address - *address, - struct Session *session, - const struct GNUNET_ATS_Information *ats, - uint32_t ats_count, - struct GNUNET_BANDWIDTH_Value32NBO - bandwidth_in, - struct GNUNET_BANDWIDTH_Value32NBO - bandwidth_out) +static void +send_session_connect (struct NeighbourAddress *na) { - struct NeighbourMapEntry *n; - struct SessionConnectMessage connect_msg; - struct ContinutionContext *cc; - size_t msg_len; - size_t ret; - - if (neighbours == NULL) - { - /* This can happen during shutdown */ - return GNUNET_NO; - } - n = lookup_neighbour (peer); - if (NULL == n) - return GNUNET_NO; - if (n->state == S_DISCONNECT) - { - /* We are disconnecting, nothing to do here */ - return GNUNET_NO; - } - GNUNET_assert (address->transport_name != NULL); - if ((session == NULL) && (0 == address->address_length)) - { - GNUNET_break_op (0); - /* FIXME: is this actually possible? When does this happen? */ - if (strlen (address->transport_name) > 0) - GNUNET_ATS_address_destroyed (GST_ats, address, session); - GNUNET_ATS_suggest_address (GST_ats, peer); - return GNUNET_NO; - } - - /* checks successful and neighbour != NULL */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "ATS tells us to switch to address '%s' session %p for peer `%s' in state `%s'\n", - (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>", - session, - GNUNET_i2s (peer), - print_state (n->state)); - - if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (n->ats_suggest); - n->ats_suggest = GNUNET_SCHEDULER_NO_TASK; - } - /* do not switch addresses just update quotas */ -/* - if (n->state == S_FAST_RECONNECT) - { - if (0 == GNUNET_HELLO_address_cmp(address, n->address)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "FAST RECONNECT to peer `%s' and address '%s' with identical ADDRESS\n", - GNUNET_i2s (&n->id), GST_plugins_a2s (n->address)); - } - } -*/ - if ((n->state == S_CONNECTED) && (NULL != n->address) && - (0 == GNUNET_HELLO_address_cmp (address, n->address)) && - (n->session == session)) - { - n->bandwidth_in = bandwidth_in; - n->bandwidth_out = bandwidth_out; - GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in); - send_outbound_quota (peer, n->bandwidth_out); - return GNUNET_NO; - } - if (n->state == S_CONNECTED) - { - /* mark old address as no longer used */ - GNUNET_assert (NULL != n->address); - if (n->address_state == USED) - { - GST_validation_set_address_use (n->address, n->session, GNUNET_NO); - GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO); - n->address_state = UNUSED; - } - } - - /* set new address */ - if (NULL != n->address) - GNUNET_HELLO_address_free (n->address); - n->address = GNUNET_HELLO_address_copy (address); - n->address_state = FRESH; - n->bandwidth_in = bandwidth_in; - n->bandwidth_out = bandwidth_out; - GNUNET_SCHEDULER_cancel (n->timeout_task); - n->timeout_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, - &neighbour_timeout_task, n); - - if (NULL != address_change_cb && n->state == S_CONNECTED) - address_change_cb (callback_cls, &n->id, n->address); - - /* Obtain an session for this address from plugin */ struct GNUNET_TRANSPORT_PluginFunctions *papi; - papi = GST_plugins_find (address->transport_name); - - if (papi == NULL) - { - /* we don't have the plugin for this address */ - GNUNET_ATS_address_destroyed (GST_ats, n->address, NULL); - - if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->ats_suggest); - n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, - ats_suggest_cancel, - n); - GNUNET_ATS_suggest_address (GST_ats, &n->id); - GNUNET_HELLO_address_free (n->address); - n->address = NULL; - n->session = NULL; - return GNUNET_NO; - } - - if (session == NULL) - { - n->session = papi->get_session (papi->cls, address); - /* Session could not be initiated */ - if (n->session == NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to obtain new session %p for peer `%s' and address '%s'\n", - n->session, GNUNET_i2s (&n->id), GST_plugins_a2s (n->address)); - - GNUNET_ATS_address_destroyed (GST_ats, n->address, NULL); - - if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->ats_suggest); - n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, - ats_suggest_cancel, - n); - GNUNET_ATS_suggest_address (GST_ats, &n->id); - GNUNET_HELLO_address_free (n->address); - n->address = NULL; - n->session = NULL; - return GNUNET_NO; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Obtained new session %p for peer `%s' and address '%s'\n", - n->session, GNUNET_i2s (&n->id), GST_plugins_a2s (n->address)); - /* Telling ATS about new session */ - GNUNET_ATS_address_update (GST_ats, n->address, n->session, NULL, 0); - } - else + struct SessionConnectMessage connect_msg; + + if (NULL == (papi = GST_plugins_find (na->address->transport_name))) { - n->session = session; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Using existing session %p for peer `%s' and address '%s'\n", - n->session, - GNUNET_i2s (&n->id), - (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>"); + GNUNET_break (0); + return; } - - switch (n->state) + if (NULL == na->session) + na->session = papi->get_session (papi->cls, na->address); + if (NULL == na->session) { - case S_NOT_CONNECTED: - case S_CONNECT_SENT: - msg_len = sizeof (struct SessionConnectMessage); - connect_msg.header.size = htons (msg_len); - connect_msg.header.type = - htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT); - connect_msg.reserved = htonl (0); - connect_msg.timestamp = - GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); - - cc = GNUNET_malloc (sizeof (struct ContinutionContext)); - cc->session = n->session; - cc->address = GNUNET_HELLO_address_copy (address); - - ret = send_with_session (n, - (const char *) &connect_msg, msg_len, - UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, - &send_connect_continuation, cc); - - return GNUNET_NO; - case S_CONNECT_RECV: - /* We received a CONNECT message and asked ATS for an address */ - msg_len = sizeof (struct SessionConnectMessage); - connect_msg.header.size = htons (msg_len); - connect_msg.header.type = - htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK); - connect_msg.reserved = htonl (0); - connect_msg.timestamp = - GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); - cc = GNUNET_malloc (sizeof (struct ContinutionContext)); - cc->session = n->session; - cc->address = GNUNET_HELLO_address_copy (address); - - ret = send_with_session(n, - (const void *) &connect_msg, msg_len, - UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, - &send_connect_ack_continuation, - cc); - return GNUNET_NO; - case S_CONNECTED: - case S_FAST_RECONNECT: - /* connected peer is switching addresses or tries fast reconnect */ - msg_len = sizeof (struct SessionConnectMessage); - connect_msg.header.size = htons (msg_len); - connect_msg.header.type = - htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT); - connect_msg.reserved = htonl (0); - connect_msg.timestamp = - GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); - cc = GNUNET_malloc (sizeof (struct ContinutionContext)); - cc->session = n->session; - cc->address = GNUNET_HELLO_address_copy (address); - ret = send_with_session(n, - (const void *) &connect_msg, msg_len, - UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, - &send_switch_address_continuation, cc); - if (ret == GNUNET_SYSERR) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to send CONNECT_MESSAGE to `%4s' using address '%s' session %X\n", - GNUNET_i2s (peer), GST_plugins_a2s (address), session); - } - return GNUNET_NO; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid connection state to switch addresses %u \n", n->state); - GNUNET_break_op (0); - return GNUNET_NO; + GNUNET_break (0); + return; } + na->connect_timestamp = GNUNET_TIME_absolute_get (); + connect_msg.header.size = htons (sizeof (struct SessionConnectMessage)); + connect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT); + connect_msg.reserved = htonl (0); + connect_msg.timestamp = GNUNET_TIME_absolute_hton (na->connect_timestamp); + (void) papi->send (papi->cls, + na->session, + (const char *) &connect_msg, sizeof (struct SessionConnectMessage), + UINT_MAX, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, NULL); } /** - * Obtain current latency information for the given neighbour. + * Send a SESSION_CONNECT_ACK message via the given address. * - * @param peer - * @return observed latency of the address, FOREVER if the address was - * never successfully validated + * @param address address to use + * @param session session to use + * @param timestamp timestamp to use for the ACK message */ -struct GNUNET_TIME_Relative -GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer) -{ - struct NeighbourMapEntry *n; - - n = lookup_neighbour (peer); - if ((NULL == n) || ((n->address == NULL) && (n->session == NULL))) - return GNUNET_TIME_UNIT_FOREVER_REL; - - return n->latency; -} - -/** - * Obtain current address information for the given neighbour. - * - * @param peer - * @return address currently used - */ -struct GNUNET_HELLO_Address * -GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer) +static void +send_session_connect_ack_message (const struct GNUNET_HELLO_Address *address, + struct Session *session, + struct GNUNET_TIME_Absolute timestamp) { - struct NeighbourMapEntry *n; - - n = lookup_neighbour (peer); - if ((NULL == n) || ((n->address == NULL) && (n->session == NULL))) - return NULL; - - return n->address; + struct GNUNET_TRANSPORT_PluginFunctions *papi; + struct SessionConnectMessage connect_msg; + + if (NULL == (papi = GST_plugins_find (address->transport_name))) + { + GNUNET_break (0); + return; + } + if (NULL == session) + session = papi->get_session (papi->cls, address); + if (NULL == session) + { + GNUNET_break (0); + return; + } + connect_msg.header.size = htons (sizeof (struct SessionConnectMessage)); + connect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK); + connect_msg.reserved = htonl (0); + connect_msg.timestamp = GNUNET_TIME_absolute_hton (timestamp); + (void) papi->send (papi->cls, + session, + (const char *) &connect_msg, sizeof (struct SessionConnectMessage), + UINT_MAX, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, NULL); } - /** - * Create an entry in the neighbour map for the given peer + * Create a fresh entry in the neighbour map for the given peer * * @param peer peer to create an entry for * @return new neighbour map entry @@ -1677,20 +1586,17 @@ setup_neighbour (const struct GNUNET_PeerIdentity *peer) { struct NeighbourMapEntry *n; -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Unknown peer `%s', creating new neighbour\n", GNUNET_i2s (peer)); -#endif + "Creating new neighbour entry for `%s'\n", + GNUNET_i2s (peer)); n = GNUNET_malloc (sizeof (struct NeighbourMapEntry)); n->id = *peer; n->state = S_NOT_CONNECTED; - n->latency = GNUNET_TIME_relative_get_forever (); + n->latency = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_BANDWIDTH_tracker_init (&n->in_tracker, GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT, MAX_BANDWIDTH_CARRY_S); - n->timeout_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, - &neighbour_timeout_task, n); + n->task = GNUNET_SCHEDULER_add_now (&master_task, n); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (neighbours, &n->id.hashPubKey, n, @@ -1700,6 +1606,32 @@ setup_neighbour (const struct GNUNET_PeerIdentity *peer) /** + * Check if the two given addresses are the same. + * Actually only checks if the sessions are non-NULL + * (which they should be) and then if they are identical; + * the actual addresses don't matter if the session + * pointers match anyway, and we must have session pointers + * at this time. + * + * @param a1 first address to compare + * @param a2 other address to compare + * @return GNUNET_NO if the addresses do not match, GNUNET_YES if they do match + */ +static int +address_matches (const struct NeighbourAddress *a1, + const struct NeighbourAddress *a2) +{ + if ( (NULL == a1->session) || + (NULL == a2->session) ) + { + GNUNET_break (0); + return 0; + } + return (a1->session == a2->session) ? GNUNET_YES : GNUNET_NO; +} + + +/** * Try to create a connection to the given target (eventually). * * @param target peer to try to connect to @@ -1709,585 +1641,1234 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target) { struct NeighbourMapEntry *n; - // This can happen during shutdown - if (neighbours == NULL) - { - return; - } -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to peer `%s'\n", + if (NULL == neighbours) + return; /* during shutdown, do nothing */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asked to connect to peer `%s'\n", GNUNET_i2s (target)); -#endif if (0 == memcmp (target, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity))) { - /* my own hello */ + /* refuse to connect to myself */ + /* FIXME: can this happen? Is this not an API violation? */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Refusing to try to connect to myself.\n"); return; } n = lookup_neighbour (target); - if (NULL != n) { - if ((S_CONNECTED == n->state) || (is_connecting (n))) - return; /* already connecting or connected */ - if (is_disconnecting (n)) - change_state (n, S_NOT_CONNECTED); + switch (n->state) + { + case S_NOT_CONNECTED: + /* this should not be possible */ + GNUNET_break (0); + free_neighbour (n, GNUNET_NO); + break; + case S_INIT_ATS: + case S_INIT_BLACKLIST: + case S_CONNECT_SENT: + case S_CONNECT_RECV_ATS: + case S_CONNECT_RECV_BLACKLIST: + case S_CONNECT_RECV_ACK: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Ignoring request to try to connect to `%s', already trying!\n", + GNUNET_i2s (target)); + return; /* already trying */ + case S_CONNECTED: + case S_RECONNECT_ATS: + case S_RECONNECT_BLACKLIST: + case S_RECONNECT_SENT: + case S_CONNECTED_SWITCHING_BLACKLIST: + case S_CONNECTED_SWITCHING_CONNECT_SENT: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Ignoring request to try to connect, already connected to `%s'!\n", + GNUNET_i2s (target)); + return; /* already connected */ + case S_DISCONNECT: + /* get rid of remains, ready to re-try immediately */ + free_neighbour (n, GNUNET_NO); + break; + case S_DISCONNECT_FINISHED: + /* should not be possible */ + GNUNET_assert (0); + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); + GNUNET_break (0); + free_neighbour (n, GNUNET_NO); + break; + } } + n = setup_neighbour (target); + n->state = S_INIT_ATS; + n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); - - if (n == NULL) - n = setup_neighbour (target); -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Asking ATS for suggested address to connect to peer `%s'\n", - GNUNET_i2s (&n->id)); -#endif - - GNUNET_ATS_suggest_address (GST_ats, &n->id); + GNUNET_ATS_reset_backoff (GST_ats, target); + GNUNET_ATS_suggest_address (GST_ats, target); } + /** - * Test if we're connected to the given peer. + * Function called with the result of a blacklist check. * - * @param target peer to test - * @return GNUNET_YES if we are connected, GNUNET_NO if not + * @param cls closure with the 'struct BlackListCheckContext' + * @param peer peer this check affects + * @param result GNUNET_OK if the address is allowed */ -int -GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target) +static void +handle_test_blacklist_cont (void *cls, + const struct GNUNET_PeerIdentity *peer, + int result) { + struct BlackListCheckContext *bcc = cls; struct NeighbourMapEntry *n; - // This can happen during shutdown - if (neighbours == NULL) + bcc->bc = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to new address of peer `%s' based on blacklist is `%s'\n", + GNUNET_i2s (peer), + (GNUNET_OK == result) ? "allowed" : "FORBIDDEN"); + if (GNUNET_OK == result) { - return GNUNET_NO; + /* valid new address, let ATS know! */ + GNUNET_ATS_address_update (GST_ats, + bcc->na.address, + bcc->na.session, + bcc->ats, bcc->ats_count); + } + if (NULL == (n = lookup_neighbour (peer))) + goto cleanup; /* nobody left to care about new address */ + switch (n->state) + { + case S_NOT_CONNECTED: + /* this should not be possible */ + GNUNET_break (0); + free_neighbour (n, GNUNET_NO); + break; + case S_INIT_ATS: + /* still waiting on ATS suggestion */ + break; + case S_INIT_BLACKLIST: + /* check if the address the blacklist was fine with matches + ATS suggestion, if so, we can move on! */ + if ( (GNUNET_OK == result) && + (1 == n->send_connect_ack) ) + { + n->send_connect_ack = 2; + send_session_connect_ack_message (bcc->na.address, + bcc->na.session, + n->connect_ack_timestamp); + } + if (GNUNET_YES != address_matches (&bcc->na, &n->primary_address)) + break; /* result for an address we currently don't care about */ + if (GNUNET_OK == result) + { + n->timeout = GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT); + n->state = S_CONNECT_SENT; + send_session_connect (&n->primary_address); + } + else + { + // FIXME: should also possibly destroy session with plugin!? + GNUNET_ATS_address_destroyed (GST_ats, + bcc->na.address, + NULL); + free_address (&n->primary_address); + n->state = S_INIT_ATS; + n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); + // FIXME: do we need to ask ATS again for suggestions? + GNUNET_ATS_suggest_address (GST_ats, &n->id); + } + break; + case S_CONNECT_SENT: + /* waiting on CONNECT_ACK, send ACK if one is pending */ + if ( (GNUNET_OK == result) && + (1 == n->send_connect_ack) ) + { + n->send_connect_ack = 2; + send_session_connect_ack_message (n->primary_address.address, + n->primary_address.session, + n->connect_ack_timestamp); + } + break; + case S_CONNECT_RECV_ATS: + /* still waiting on ATS suggestion, don't care about blacklist */ + break; + case S_CONNECT_RECV_BLACKLIST: + if (GNUNET_YES != address_matches (&bcc->na, &n->primary_address)) + break; /* result for an address we currently don't care about */ + if (GNUNET_OK == result) + { + n->timeout = GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT); + n->state = S_CONNECT_RECV_ACK; + send_session_connect_ack_message (bcc->na.address, + bcc->na.session, + n->connect_ack_timestamp); + if (1 == n->send_connect_ack) + n->send_connect_ack = 2; + } + else + { + // FIXME: should also possibly destroy session with plugin!? + GNUNET_ATS_address_destroyed (GST_ats, + bcc->na.address, + NULL); + free_address (&n->primary_address); + n->state = S_INIT_ATS; + n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); + // FIXME: do we need to ask ATS again for suggestions? + GNUNET_ATS_reset_backoff (GST_ats, peer); + GNUNET_ATS_suggest_address (GST_ats, &n->id); + } + break; + case S_CONNECT_RECV_ACK: + /* waiting on SESSION_ACK, send ACK if one is pending */ + if ( (GNUNET_OK == result) && + (1 == n->send_connect_ack) ) + { + n->send_connect_ack = 2; + send_session_connect_ack_message (n->primary_address.address, + n->primary_address.session, + n->connect_ack_timestamp); + } + break; + case S_CONNECTED: + /* already connected, don't care about blacklist */ + break; + case S_RECONNECT_ATS: + /* still waiting on ATS suggestion, don't care about blacklist */ + break; + case S_RECONNECT_BLACKLIST: + if ( (GNUNET_OK == result) && + (1 == n->send_connect_ack) ) + { + n->send_connect_ack = 2; + send_session_connect_ack_message (bcc->na.address, + bcc->na.session, + n->connect_ack_timestamp); + } + if (GNUNET_YES != address_matches (&bcc->na, &n->primary_address)) + break; /* result for an address we currently don't care about */ + if (GNUNET_OK == result) + { + send_session_connect (&n->primary_address); + n->timeout = GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT); + n->state = S_RECONNECT_SENT; + } + else + { + GNUNET_ATS_address_destroyed (GST_ats, + bcc->na.address, + NULL); + n->state = S_RECONNECT_ATS; + n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); + // FIXME: do we need to ask ATS again for suggestions? + GNUNET_ATS_suggest_address (GST_ats, &n->id); + } + break; + case S_RECONNECT_SENT: + /* waiting on CONNECT_ACK, don't care about blacklist */ + if ( (GNUNET_OK == result) && + (1 == n->send_connect_ack) ) + { + n->send_connect_ack = 2; + send_session_connect_ack_message (n->primary_address.address, + n->primary_address.session, + n->connect_ack_timestamp); + } + break; + case S_CONNECTED_SWITCHING_BLACKLIST: + if (GNUNET_YES != address_matches (&bcc->na, &n->alternative_address)) + break; /* result for an address we currently don't care about */ + if (GNUNET_OK == result) + { + send_session_connect (&n->alternative_address); + n->state = S_CONNECTED_SWITCHING_CONNECT_SENT; + } + else + { + GNUNET_ATS_address_destroyed (GST_ats, + bcc->na.address, + NULL); + free_address (&n->alternative_address); + n->state = S_CONNECTED; + } + break; + case S_CONNECTED_SWITCHING_CONNECT_SENT: + /* waiting on CONNECT_ACK, don't care about blacklist */ + if ( (GNUNET_OK == result) && + (1 == n->send_connect_ack) ) + { + n->send_connect_ack = 2; + send_session_connect_ack_message (n->primary_address.address, + n->primary_address.session, + n->connect_ack_timestamp); + } + break; + case S_DISCONNECT: + /* Nothing to do here, ATS will already do what can be done */ + break; + case S_DISCONNECT_FINISHED: + /* should not be possible */ + GNUNET_assert (0); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); + GNUNET_break (0); + free_neighbour (n, GNUNET_NO); + break; } + cleanup: + GNUNET_HELLO_address_free (bcc->na.address); + GNUNET_CONTAINER_DLL_remove (bc_head, + bc_tail, + bcc); + GNUNET_free (bcc); +} - n = lookup_neighbour (target); - if ((NULL == n) || (S_CONNECTED != n->state)) - return GNUNET_NO; /* not connected */ - return GNUNET_YES; +/** + * We want to know if connecting to a particular peer via + * a particular address is allowed. Check it! + * + * @param peer identity of the peer to switch the address for + * @param ts time at which the check was initiated + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) + * @param ats performance data + * @param ats_count number of entries in ats (excluding 0-termination) + */ +static void +check_blacklist (const struct GNUNET_PeerIdentity *peer, + struct GNUNET_TIME_Absolute ts, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) +{ + struct BlackListCheckContext *bcc; + struct GST_BlacklistCheck *bc; + + bcc = + GNUNET_malloc (sizeof (struct BlackListCheckContext) + + sizeof (struct GNUNET_ATS_Information) * ats_count); + bcc->ats_count = ats_count; + bcc->na.address = GNUNET_HELLO_address_copy (address); + bcc->na.session = session; + bcc->na.connect_timestamp = ts; + bcc->ats = (struct GNUNET_ATS_Information *) &bcc[1]; + memcpy (bcc->ats, ats, sizeof (struct GNUNET_ATS_Information) * ats_count); + GNUNET_CONTAINER_DLL_insert (bc_head, + bc_tail, + bcc); + if (NULL != (bc = GST_blacklist_test_allowed (peer, + address->transport_name, + &handle_test_blacklist_cont, bcc))) + bcc->bc = bc; + /* if NULL == bc, 'cont' was already called and 'bcc' already free'd, so + we must only store 'bc' if 'bc' is non-NULL... */ } + /** - * A session was terminated. Take note. + * We received a 'SESSION_CONNECT' message from the other peer. + * Consider switching to it. * - * @param peer identity of the peer where the session died - * @param session session that is gone + * @param message possibly a 'struct SessionConnectMessage' (check format) + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) + * @param ats performance data + * @param ats_count number of entries in ats (excluding 0-termination) */ void -GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer, - struct Session *session) +GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) { + const struct SessionConnectMessage *scm; struct NeighbourMapEntry *n; + struct GNUNET_TIME_Absolute ts; - if (neighbours == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received CONNECT message from peer `%s'\n", + GNUNET_i2s (peer)); + if (ntohs (message->size) != sizeof (struct SessionConnectMessage)) { - /* This can happen during shutdown */ + GNUNET_break_op (0); return; } - -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %X to peer `%s' ended \n", - session, GNUNET_i2s (peer)); -#endif - + if (NULL == neighbours) + return; /* we're shutting down */ + scm = (const struct SessionConnectMessage *) message; + GNUNET_break_op (0 == ntohl (scm->reserved)); + ts = GNUNET_TIME_absolute_ntoh (scm->timestamp); n = lookup_neighbour (peer); if (NULL == n) - return; - if (session != n->session) - return; /* doesn't affect us */ - if (n->state == S_CONNECTED) - { - if (n->address_state == USED) - { - GST_validation_set_address_use (n->address, n->session, GNUNET_NO); - GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO); - n->address_state = UNUSED; - } - } - - if (NULL != n->address) - { - GNUNET_HELLO_address_free (n->address); - n->address = NULL; - } - n->session = NULL; - - /* not connected anymore anyway, shouldn't matter */ - if (S_CONNECTED != n->state) - return; - - if (n->keepalive_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (n->keepalive_task); - n->keepalive_task = GNUNET_SCHEDULER_NO_TASK; - n->expect_latency_response = GNUNET_NO; + n = setup_neighbour (peer); + n->send_connect_ack = 1; + n->connect_ack_timestamp = ts; + switch (n->state) + { + case S_NOT_CONNECTED: + n->state = S_CONNECT_RECV_ATS; + n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); + GNUNET_ATS_reset_backoff (GST_ats, peer); + GNUNET_ATS_suggest_address (GST_ats, peer); + check_blacklist (peer, ts, address, session, ats, ats_count); + break; + case S_INIT_ATS: + case S_INIT_BLACKLIST: + case S_CONNECT_SENT: + case S_CONNECT_RECV_ATS: + case S_CONNECT_RECV_BLACKLIST: + case S_CONNECT_RECV_ACK: + /* It can never hurt to have an alternative address in the above cases, + see if it is allowed */ + check_blacklist (peer, ts, address, session, ats, ats_count); + break; + case S_CONNECTED: + /* we are already connected and can thus send the ACK immediately; + still, it can never hurt to have an alternative address, so also + tell ATS about it */ + GNUNET_assert (NULL != n->primary_address.address); + GNUNET_assert (NULL != n->primary_address.session); + n->send_connect_ack = 0; + send_session_connect_ack_message (n->primary_address.address, + n->primary_address.session, ts); + check_blacklist (peer, ts, address, session, ats, ats_count); + break; + case S_RECONNECT_ATS: + case S_RECONNECT_BLACKLIST: + case S_RECONNECT_SENT: + /* It can never hurt to have an alternative address in the above cases, + see if it is allowed */ + check_blacklist (peer, ts, address, session, ats, ats_count); + break; + case S_CONNECTED_SWITCHING_BLACKLIST: + case S_CONNECTED_SWITCHING_CONNECT_SENT: + /* we are already connected and can thus send the ACK immediately; + still, it can never hurt to have an alternative address, so also + tell ATS about it */ + GNUNET_assert (NULL != n->primary_address.address); + GNUNET_assert (NULL != n->primary_address.session); + n->send_connect_ack = 0; + send_session_connect_ack_message (n->primary_address.address, + n->primary_address.session, ts); + check_blacklist (peer, ts, address, session, ats, ats_count); + break; + case S_DISCONNECT: + /* get rid of remains without terminating sessions, ready to re-try */ + free_neighbour (n, GNUNET_YES); + n = setup_neighbour (peer); + n->state = S_CONNECT_RECV_ATS; + GNUNET_ATS_reset_backoff (GST_ats, peer); + GNUNET_ATS_suggest_address (GST_ats, peer); + break; + case S_DISCONNECT_FINISHED: + /* should not be possible */ + GNUNET_assert (0); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); + GNUNET_break (0); + free_neighbour (n, GNUNET_NO); + break; } - - /* connected, try fast reconnect */ - /* statistics "transport" : "# peers connected" -= 1 - * neighbours_connected -= 1 - * BUT: no disconnect_cb to notify clients about disconnect - */ - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying fast reconnect to peer `%s'\n", - GNUNET_i2s (peer)); - - GNUNET_assert (neighbours_connected > 0); - change_state (n, S_FAST_RECONNECT); - neighbours_connected--; - GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1, - GNUNET_NO); - - - /* We are connected, so ask ATS to switch addresses */ - GNUNET_SCHEDULER_cancel (n->timeout_task); - n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT, - &neighbour_timeout_task, n); - /* try QUICKLY to re-establish a connection, reduce timeout! */ - if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->ats_suggest); - n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, - &ats_suggest_cancel, - n); - GNUNET_ATS_suggest_address (GST_ats, peer); } /** - * Transmit a message to the given target using the active connection. + * For an existing neighbour record, set the active connection to + * use the given address. * - * @param target destination - * @param msg message to send - * @param msg_size number of bytes in msg - * @param timeout when to fail with timeout - * @param cont function to call when done - * @param cont_cls closure for 'cont' + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) + * @param ats performance data + * @param ats_count number of entries in ats + * @param bandwidth_in inbound quota to be used when connection is up + * @param bandwidth_out outbound quota to be used when connection is up */ void -GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg, - size_t msg_size, struct GNUNET_TIME_Relative timeout, - GST_NeighbourSendContinuation cont, void *cont_cls) +GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_in, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_out) { struct NeighbourMapEntry *n; - struct MessageQueue *mq; + struct GNUNET_TRANSPORT_PluginFunctions *papi; + + GNUNET_assert (address->transport_name != NULL); + if (NULL == (n = lookup_neighbour (peer))) + return; - // This can happen during shutdown - if (neighbours == NULL) + /* Obtain an session for this address from plugin */ + if (NULL == (papi = GST_plugins_find (address->transport_name))) { + /* we don't have the plugin for this address */ + GNUNET_ATS_address_destroyed (GST_ats, address, NULL); return; } - - n = lookup_neighbour (target); - if ((n == NULL) || (!is_connected (n))) + if ((NULL == session) && (0 == address->address_length)) { - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# messages not sent (no such peer or not connected)"), - 1, GNUNET_NO); -#if DEBUG_TRANSPORT - if (n == NULL) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Could not send message to peer `%s': unknown neighbour", - GNUNET_i2s (target)); - else if (!is_connected (n)) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Could not send message to peer `%s': not connected\n", - GNUNET_i2s (target)); -#endif - if (NULL != cont) - cont (cont_cls, GNUNET_SYSERR); + GNUNET_break (0); + if (strlen (address->transport_name) > 0) + GNUNET_ATS_address_destroyed (GST_ats, address, session); return; } - - if ((n->session == NULL) && (n->address == NULL)) + if (NULL == session) + session = papi->get_session (papi->cls, address); + if (NULL == session) { - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# messages not sent (no such peer or not connected)"), - 1, GNUNET_NO); -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Could not send message to peer `%s': no address available\n", - GNUNET_i2s (target)); -#endif - - if (NULL != cont) - cont (cont_cls, GNUNET_SYSERR); + "Failed to obtain new session for peer `%s' and address '%s'\n", + GNUNET_i2s (&address->peer), GST_plugins_a2s (address)); + GNUNET_ATS_address_destroyed (GST_ats, address, NULL); return; } - - GNUNET_assert (msg_size >= sizeof (struct GNUNET_MessageHeader)); - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# bytes in message queue for other peers"), - msg_size, GNUNET_NO); - mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size); - mq->cont = cont; - mq->cont_cls = cont_cls; - /* FIXME: this memcpy can be up to 7% of our total runtime! */ - memcpy (&mq[1], msg, msg_size); - mq->message_buf = (const char *) &mq[1]; - mq->message_buf_size = msg_size; - mq->timeout = GNUNET_TIME_relative_to_absolute (timeout); - GNUNET_CONTAINER_DLL_insert_tail (n->messages_head, n->messages_tail, mq); - - if ((GNUNET_SCHEDULER_NO_TASK == n->transmission_task) && - (NULL == n->is_active)) - n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "ATS tells us to switch to address '%s' for peer `%s'\n", + (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>", + GNUNET_i2s (peer)); + switch (n->state) + { + case S_NOT_CONNECTED: + GNUNET_break (0); + free_neighbour (n, GNUNET_NO); + return; + case S_INIT_ATS: + set_address (&n->primary_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + n->state = S_INIT_BLACKLIST; + n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); + check_blacklist (&n->id, + n->connect_ack_timestamp, + address, session, ats, ats_count); + break; + case S_INIT_BLACKLIST: + /* ATS suggests a different address, switch again */ + set_address (&n->primary_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); + check_blacklist (&n->id, + n->connect_ack_timestamp, + address, session, ats, ats_count); + break; + case S_CONNECT_SENT: + /* ATS suggests a different address, switch again */ + set_address (&n->primary_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + n->state = S_INIT_BLACKLIST; + n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); + check_blacklist (&n->id, + n->connect_ack_timestamp, + address, session, ats, ats_count); + break; + case S_CONNECT_RECV_ATS: + set_address (&n->primary_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + n->state = S_CONNECT_RECV_BLACKLIST; + n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); + check_blacklist (&n->id, + n->connect_ack_timestamp, + address, session, ats, ats_count); + break; + case S_CONNECT_RECV_BLACKLIST: + case S_CONNECT_RECV_ACK: + /* ATS asks us to switch while we were trying to connect; switch to new + address and check blacklist again */ + set_address (&n->primary_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); + check_blacklist (&n->id, + n->connect_ack_timestamp, + address, session, ats, ats_count); + break; + case S_CONNECTED: + GNUNET_assert (NULL != n->primary_address.address); + GNUNET_assert (NULL != n->primary_address.session); + if (n->primary_address.session == session) + { + /* not an address change, just a quota change */ + set_address (&n->primary_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_YES); + break; + } + /* ATS asks us to switch a life connection; see if we can get + a CONNECT_ACK on it before we actually do this! */ + set_address (&n->alternative_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + n->state = S_CONNECTED_SWITCHING_BLACKLIST; + check_blacklist (&n->id, + GNUNET_TIME_absolute_get (), + address, session, ats, ats_count); + break; + case S_RECONNECT_ATS: + set_address (&n->primary_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + n->state = S_RECONNECT_BLACKLIST; + n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); + check_blacklist (&n->id, + n->connect_ack_timestamp, + address, session, ats, ats_count); + break; + case S_RECONNECT_BLACKLIST: + /* ATS asks us to switch while we were trying to reconnect; switch to new + address and check blacklist again */ + set_address (&n->primary_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); + check_blacklist (&n->id, + n->connect_ack_timestamp, + address, session, ats, ats_count); + break; + case S_RECONNECT_SENT: + /* ATS asks us to switch while we were trying to reconnect; switch to new + address and check blacklist again */ + set_address (&n->primary_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + n->state = S_RECONNECT_BLACKLIST; + n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); + check_blacklist (&n->id, + n->connect_ack_timestamp, + address, session, ats, ats_count); + break; + case S_CONNECTED_SWITCHING_BLACKLIST: + if (n->primary_address.session == session) + { + /* ATS switches back to still-active session */ + free_address (&n->alternative_address); + n->state = S_CONNECTED; + break; + } + /* ATS asks us to switch a life connection, update blacklist check */ + set_address (&n->alternative_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + check_blacklist (&n->id, + GNUNET_TIME_absolute_get (), + address, session, ats, ats_count); + break; + case S_CONNECTED_SWITCHING_CONNECT_SENT: + if (n->primary_address.session == session) + { + /* ATS switches back to still-active session */ + free_address (&n->alternative_address); + n->state = S_CONNECTED; + break; + } + /* ATS asks us to switch a life connection, update blacklist check */ + set_address (&n->alternative_address, + address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + n->state = S_CONNECTED_SWITCHING_BLACKLIST; + check_blacklist (&n->id, + GNUNET_TIME_absolute_get (), + address, session, ats, ats_count); + break; + case S_DISCONNECT: + /* not going to switch addresses while disconnecting */ + return; + case S_DISCONNECT_FINISHED: + GNUNET_assert (0); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); + GNUNET_break (0); + break; + } } /** - * We have received a message from the given sender. How long should - * we delay before receiving more? (Also used to keep the peer marked - * as live). + * Master task run for every neighbour. Performs all of the time-related + * activities (keep alive, send next message, disconnect if idle, finish + * clean up after disconnect). * - * @param sender sender of the message - * @param size size of the message - * @param do_forward set to GNUNET_YES if the message should be forwarded to clients - * GNUNET_NO if the neighbour is not connected or violates the quota, - * GNUNET_SYSERR if the connection is not fully up yet - * @return how long to wait before reading more from this sender + * @param cls the 'struct NeighbourMapEntry' for which we are running + * @param tc scheduler context (unused) */ -struct GNUNET_TIME_Relative -GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity - *sender, ssize_t size, int *do_forward) +static void +master_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct NeighbourMapEntry *n; - struct GNUNET_TIME_Relative ret; - - // This can happen during shutdown - if (neighbours == NULL) - { - return GNUNET_TIME_UNIT_FOREVER_REL; - } + struct NeighbourMapEntry *n = cls; + struct GNUNET_TIME_Relative delay; - n = lookup_neighbour (sender); - if (n == NULL) + n->task = GNUNET_SCHEDULER_NO_TASK; + delay = GNUNET_TIME_absolute_get_remaining (n->timeout); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "master task runs for neighbour `%s' in state %d with timeout in %llu ms\n", + GNUNET_i2s (&n->id), + n->state, + (unsigned long long) delay.rel_value); + switch (n->state) { - GST_neighbours_try_connect (sender); - n = lookup_neighbour (sender); - if (NULL == n) + case S_NOT_CONNECTED: + /* invalid state for master task, clean up */ + GNUNET_break (0); + n->state = S_DISCONNECT_FINISHED; + free_neighbour (n, GNUNET_NO); + return; + case S_INIT_ATS: + if (0 == delay.rel_value) { - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# messages discarded due to lack of neighbour record"), - 1, GNUNET_NO); - *do_forward = GNUNET_NO; - return GNUNET_TIME_UNIT_ZERO; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out waiting for ATS to provide address\n", + GNUNET_i2s (&n->id)); + n->state = S_DISCONNECT_FINISHED; + free_neighbour (n, GNUNET_NO); + return; } - } - if (!is_connected (n)) - { - *do_forward = GNUNET_SYSERR; - return GNUNET_TIME_UNIT_ZERO; - } - if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size)) - { - n->quota_violation_count++; -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Bandwidth quota (%u b/s) violation detected (total of %u).\n", - n->in_tracker.available_bytes_per_s__, - n->quota_violation_count); -#endif - /* Discount 32k per violation */ - GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024); - } - else - { - if (n->quota_violation_count > 0) + break; + case S_INIT_BLACKLIST: + if (0 == delay.rel_value) { - /* try to add 32k back */ - GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024); - n->quota_violation_count--; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out waiting for BLACKLIST to approve address\n", + GNUNET_i2s (&n->id)); + n->state = S_DISCONNECT_FINISHED; + free_neighbour (n, GNUNET_NO); + return; } - } - if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD) - { - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# bandwidth quota violations by other peers"), - 1, GNUNET_NO); - *do_forward = GNUNET_NO; - return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT; - } - *do_forward = GNUNET_YES; - ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024); - if (ret.rel_value > 0) - { -#if DEBUG_TRANSPORT + break; + case S_CONNECT_SENT: + if (0 == delay.rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out waiting for other peer to send CONNECT_ACK\n", + GNUNET_i2s (&n->id)); + disconnect_neighbour (n); + return; + } + break; + case S_CONNECT_RECV_ATS: + if (0 == delay.rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out waiting ATS to provide address to use for CONNECT_ACK\n", + GNUNET_i2s (&n->id)); + n->state = S_DISCONNECT_FINISHED; + free_neighbour (n, GNUNET_NO); + return; + } + break; + case S_CONNECT_RECV_BLACKLIST: + if (0 == delay.rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out waiting BLACKLIST to approve address to use for CONNECT_ACK\n", + GNUNET_i2s (&n->id)); + n->state = S_DISCONNECT_FINISHED; + free_neighbour (n, GNUNET_NO); + return; + } + break; + case S_CONNECT_RECV_ACK: + if (0 == delay.rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out waiting for other peer to send SESSION_ACK\n", + GNUNET_i2s (&n->id)); + disconnect_neighbour (n); + return; + } + break; + case S_CONNECTED: + if (0 == delay.rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out, missing KEEPALIVE_RESPONSEs\n", + GNUNET_i2s (&n->id)); + disconnect_neighbour (n); + return; + } + try_transmission_to_peer (n); + send_keepalive (n); + break; + case S_RECONNECT_ATS: + if (0 == delay.rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out, waiting for ATS replacement address\n", + GNUNET_i2s (&n->id)); + disconnect_neighbour (n); + return; + } + break; + case S_RECONNECT_BLACKLIST: + if (0 == delay.rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out, waiting for BLACKLIST to approve replacement address\n", + GNUNET_i2s (&n->id)); + disconnect_neighbour (n); + return; + } + break; + case S_RECONNECT_SENT: + if (0 == delay.rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out, waiting for other peer to CONNECT_ACK replacement address\n", + GNUNET_i2s (&n->id)); + disconnect_neighbour (n); + return; + } + break; + case S_CONNECTED_SWITCHING_BLACKLIST: + if (0 == delay.rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out, missing KEEPALIVE_RESPONSEs\n", + GNUNET_i2s (&n->id)); + disconnect_neighbour (n); + return; + } + try_transmission_to_peer (n); + send_keepalive (n); + break; + case S_CONNECTED_SWITCHING_CONNECT_SENT: + if (0 == delay.rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' timed out, missing KEEPALIVE_RESPONSEs (after trying to CONNECT on alternative address)\n", + GNUNET_i2s (&n->id)); + disconnect_neighbour (n); + return; + } + try_transmission_to_peer (n); + send_keepalive (n); + break; + case S_DISCONNECT: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n", - (unsigned long long) n->in_tracker. - consumption_since_last_update__, - (unsigned int) n->in_tracker.available_bytes_per_s__, - (unsigned long long) ret.rel_value); -#endif - GNUNET_STATISTICS_update (GST_stats, - gettext_noop ("# ms throttling suggested"), - (int64_t) ret.rel_value, GNUNET_NO); - } - return ret; + "Cleaning up connection to `%s' after sending DISCONNECT\n", + GNUNET_i2s (&n->id)); + n->state = S_DISCONNECT_FINISHED; + free_neighbour (n, GNUNET_NO); + return; + case S_DISCONNECT_FINISHED: + /* how did we get here!? */ + GNUNET_assert (0); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); + GNUNET_break (0); + break; + } + if ( (S_CONNECTED_SWITCHING_CONNECT_SENT == n->state) || + (S_CONNECTED_SWITCHING_BLACKLIST == n->state) || + (S_CONNECTED == n->state) ) + { + /* if we are *now* in one of these three states, we're sending + keep alive messages, so we need to consider the keepalive + delay, not just the connection timeout */ + delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time), + delay); + } + if (GNUNET_SCHEDULER_NO_TASK == n->task) + n->task = GNUNET_SCHEDULER_add_delayed (delay, + &master_task, + n); } /** - * Keep the connection to the given neighbour alive longer, - * we received a KEEPALIVE (or equivalent). + * Send a SESSION_ACK message to the neighbour to confirm that we + * got his CONNECT_ACK. * - * @param neighbour neighbour to keep alive + * @param n neighbour to send the SESSION_ACK to */ -void -GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour) +static void +send_session_ack_message (struct NeighbourMapEntry *n) { - struct NeighbourMapEntry *n; - - // This can happen during shutdown - if (neighbours == NULL) - { - return; - } - - n = lookup_neighbour (neighbour); - if (NULL == n) - { - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# KEEPALIVE messages discarded (not connected)"), - 1, GNUNET_NO); - return; - } - GNUNET_SCHEDULER_cancel (n->timeout_task); - n->timeout_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, - &neighbour_timeout_task, n); - - /* send reply to measure latency */ - if (S_CONNECTED != n->state) - return; - - struct GNUNET_MessageHeader m; - - m.size = htons (sizeof (struct GNUNET_MessageHeader)); - m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE); + struct GNUNET_MessageHeader msg; - send_with_session(n, - (const void *) &m, sizeof (m), - UINT32_MAX, - GNUNET_TIME_UNIT_FOREVER_REL, - NULL, NULL); + msg.size = htons (sizeof (struct GNUNET_MessageHeader)); + msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK); + (void) send_with_session(n, + (const char *) &msg, sizeof (struct GNUNET_MessageHeader), + UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, + NULL, NULL); } + /** - * We received a KEEP_ALIVE_RESPONSE message and use this to calculate latency - * to this peer + * We received a 'SESSION_CONNECT_ACK' message from the other peer. + * Consider switching to it. * - * @param neighbour neighbour to keep alive + * @param message possibly a 'struct SessionConnectMessage' (check format) + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) * @param ats performance data * @param ats_count number of entries in ats */ void -GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour, +GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { + const struct SessionConnectMessage *scm; + struct GNUNET_TIME_Absolute ts; struct NeighbourMapEntry *n; - struct GNUNET_ATS_Information *ats_new; - uint32_t latency; - if (neighbours == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received CONNECT_ACK message from peer `%s'\n", + GNUNET_i2s (peer)); + if (ntohs (message->size) != sizeof (struct SessionConnectMessage)) { - // This can happen during shutdown + GNUNET_break_op (0); return; } - - n = lookup_neighbour (neighbour); - if ((NULL == n) || (n->state != S_CONNECTED)) + scm = (const struct SessionConnectMessage *) message; + GNUNET_break_op (ntohl (scm->reserved) == 0); + if (NULL == (n = lookup_neighbour (peer))) { GNUNET_STATISTICS_update (GST_stats, gettext_noop - ("# KEEPALIVE_RESPONSE messages discarded (not connected)"), + ("# unexpected CONNECT_ACK messages (no peer)"), 1, GNUNET_NO); return; } - if (n->expect_latency_response != GNUNET_YES) + ts = GNUNET_TIME_absolute_ntoh (scm->timestamp); + switch (n->state) { + case S_NOT_CONNECTED: + GNUNET_break (0); + free_neighbour (n, GNUNET_NO); + return; + case S_INIT_ATS: + case S_INIT_BLACKLIST: GNUNET_STATISTICS_update (GST_stats, gettext_noop - ("# KEEPALIVE_RESPONSE messages discarded (not expected)"), + ("# unexpected CONNECT_ACK messages (not ready)"), 1, GNUNET_NO); - return; + break; + case S_CONNECT_SENT: + if (ts.abs_value != n->primary_address.connect_timestamp.abs_value) + break; /* ACK does not match our original CONNECT message */ + n->state = S_CONNECTED; + n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + GNUNET_STATISTICS_set (GST_stats, + gettext_noop ("# peers connected"), + ++neighbours_connected, + GNUNET_NO); + connect_notify_cb (callback_cls, &n->id, ats, ats_count); + set_address (&n->primary_address, + n->primary_address.address, + n->primary_address.session, + n->primary_address.bandwidth_in, + n->primary_address.bandwidth_out, + GNUNET_YES); + send_session_ack_message (n); + break; + case S_CONNECT_RECV_ATS: + case S_CONNECT_RECV_BLACKLIST: + case S_CONNECT_RECV_ACK: + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# unexpected CONNECT_ACK messages (not ready)"), + 1, GNUNET_NO); + break; + case S_CONNECTED: + /* duplicate CONNECT_ACK, let's answer by duplciate SESSION_ACK just in case */ + send_session_ack_message (n); + break; + case S_RECONNECT_ATS: + case S_RECONNECT_BLACKLIST: + /* we didn't expect any CONNECT_ACK, as we are waiting for ATS + to give us a new address... */ + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# unexpected CONNECT_ACK messages (waiting on ATS)"), + 1, GNUNET_NO); + break; + case S_RECONNECT_SENT: + /* new address worked; go back to connected! */ + n->state = S_CONNECTED; + send_session_ack_message (n); + break; + case S_CONNECTED_SWITCHING_BLACKLIST: + /* duplicate CONNECT_ACK, let's answer by duplciate SESSION_ACK just in case */ + send_session_ack_message (n); + break; + case S_CONNECTED_SWITCHING_CONNECT_SENT: + /* new address worked; adopt it and go back to connected! */ + n->state = S_CONNECTED; + n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + GNUNET_break (GNUNET_NO == n->alternative_address.ats_active); + set_address (&n->primary_address, + n->alternative_address.address, + n->alternative_address.session, + n->alternative_address.bandwidth_in, + n->alternative_address.bandwidth_out, + GNUNET_YES); + free_address (&n->alternative_address); + send_session_ack_message (n); + break; + case S_DISCONNECT: + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# unexpected CONNECT_ACK messages (disconnecting)"), + 1, GNUNET_NO); + break; + case S_DISCONNECT_FINISHED: + GNUNET_assert (0); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); + GNUNET_break (0); + break; } - n->expect_latency_response = GNUNET_NO; +} - GNUNET_assert (n->keep_alive_sent.abs_value != - GNUNET_TIME_absolute_get_zero ().abs_value); - n->latency = - GNUNET_TIME_absolute_get_difference (n->keep_alive_sent, - GNUNET_TIME_absolute_get ()); -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Latency for peer `%s' is %llu ms\n", - GNUNET_i2s (&n->id), n->latency.rel_value); -#endif +/** + * A session was terminated. Take note; if needed, try to get + * an alternative address from ATS. + * + * @param peer identity of the peer where the session died + * @param session session that is gone + */ +void +GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer, + struct Session *session) +{ + struct NeighbourMapEntry *n; + struct BlackListCheckContext *bcc; + struct BlackListCheckContext *bcc_next; - if (n->latency.rel_value == GNUNET_TIME_relative_get_forever ().rel_value) + /* make sure to cancel all ongoing blacklist checks involving 'session' */ + bcc_next = bc_head; + while (NULL != (bcc = bcc_next)) { - GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats, ats_count); + bcc_next = bcc->next; + if (bcc->na.session == session) + { + GST_blacklist_test_cancel (bcc->bc); + GNUNET_HELLO_address_free (bcc->na.address); + GNUNET_CONTAINER_DLL_remove (bc_head, + bc_tail, + bcc); + GNUNET_free (bcc); + } } - else + if (NULL == (n = lookup_neighbour (peer))) + return; /* can't affect us */ + if (session != n->primary_address.session) { - ats_new = - GNUNET_malloc (sizeof (struct GNUNET_ATS_Information) * - (ats_count + 1)); - memcpy (ats_new, ats, sizeof (struct GNUNET_ATS_Information) * ats_count); - - /* add latency */ - ats_new[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); - if (n->latency.rel_value > UINT32_MAX) - latency = UINT32_MAX; - else - latency = n->latency.rel_value; - ats_new[ats_count].value = htonl (latency); + if (session == n->alternative_address.session) + { + free_address (&n->alternative_address); + if ( (S_CONNECTED_SWITCHING_BLACKLIST == n->state) || + (S_CONNECTED_SWITCHING_CONNECT_SENT == n->state) ) + n->state = S_CONNECTED; + else + GNUNET_break (0); + } + return; /* doesn't affect us further */ + } - GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats_new, - ats_count + 1); - GNUNET_free (ats_new); + n->expect_latency_response = GNUNET_NO; + + switch (n->state) + { + case S_NOT_CONNECTED: + GNUNET_break (0); + free_neighbour (n, GNUNET_NO); + return; + case S_INIT_ATS: + GNUNET_break (0); + free_neighbour (n, GNUNET_NO); + return; + case S_INIT_BLACKLIST: + case S_CONNECT_SENT: + free_address (&n->primary_address); + n->state = S_INIT_ATS; + n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); + // FIXME: need to ask ATS for suggestions again? + GNUNET_ATS_suggest_address (GST_ats, &n->id); + break; + case S_CONNECT_RECV_ATS: + case S_CONNECT_RECV_BLACKLIST: + case S_CONNECT_RECV_ACK: + /* error on inbound session; free neighbour entirely */ + free_address (&n->primary_address); + free_neighbour (n, GNUNET_NO); + return; + case S_CONNECTED: + free_address (&n->primary_address); + n->state = S_RECONNECT_ATS; + n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); + /* FIXME: is this ATS call needed? */ + GNUNET_ATS_suggest_address (GST_ats, &n->id); + break; + case S_RECONNECT_ATS: + /* we don't have an address, how can it go down? */ + GNUNET_break (0); + break; + case S_RECONNECT_BLACKLIST: + case S_RECONNECT_SENT: + n->state = S_RECONNECT_ATS; + n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); + // FIXME: need to ask ATS for suggestions again? + GNUNET_ATS_suggest_address (GST_ats, &n->id); + break; + case S_CONNECTED_SWITCHING_BLACKLIST: + /* primary went down while we were checking secondary against + blacklist, adopt secondary as primary */ + free_address (&n->primary_address); + n->primary_address = n->alternative_address; + memset (&n->alternative_address, 0, sizeof (struct NeighbourAddress)); + n->timeout = GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT); + n->state = S_RECONNECT_BLACKLIST; + break; + case S_CONNECTED_SWITCHING_CONNECT_SENT: + /* primary went down while we were waiting for CONNECT_ACK on secondary; + secondary as primary */ + free_address (&n->primary_address); + n->primary_address = n->alternative_address; + memset (&n->alternative_address, 0, sizeof (struct NeighbourAddress)); + n->timeout = GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT); + n->state = S_RECONNECT_SENT; + break; + case S_DISCONNECT: + free_address (&n->primary_address); + break; + case S_DISCONNECT_FINISHED: + /* neighbour was freed and plugins told to terminate session */ + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); + GNUNET_break (0); + break; } + if (GNUNET_SCHEDULER_NO_TASK != n->task) + GNUNET_SCHEDULER_cancel (n->task); + n->task = GNUNET_SCHEDULER_add_now (&master_task, n); } /** - * Change the incoming quota for the given peer. + * We received a 'SESSION_ACK' message from the other peer. + * If we sent a 'CONNECT_ACK' last, this means we are now + * connected. Otherwise, do nothing. * - * @param neighbour identity of peer to change qutoa for - * @param quota new quota + * @param message possibly a 'struct SessionConnectMessage' (check format) + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) + * @param ats performance data + * @param ats_count number of entries in ats */ void -GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour, - struct GNUNET_BANDWIDTH_Value32NBO quota) +GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) { struct NeighbourMapEntry *n; - // This can happen during shutdown - if (neighbours == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received SESSION_ACK message from peer `%s'\n", + GNUNET_i2s (peer)); + if (ntohs (message->size) != sizeof (struct GNUNET_MessageHeader)) { + GNUNET_break_op (0); return; } - - n = lookup_neighbour (neighbour); - if (n == NULL) + if (NULL == (n = lookup_neighbour (peer))) + return; + /* check if we are in a plausible state for having sent + a CONNECT_ACK. If not, return, otherwise break */ + if ( ( (S_CONNECT_RECV_ACK != n->state) && + (S_CONNECT_SENT != n->state) ) || + (2 != n->send_connect_ack) ) { GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# SET QUOTA messages ignored (no such peer)"), - 1, GNUNET_NO); + gettext_noop ("# unexpected SESSION ACK messages"), 1, + GNUNET_NO); return; } -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Setting inbound quota of %u Bps for peer `%s' to all clients\n", - ntohl (quota.value__), GNUNET_i2s (&n->id)); -#endif - GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, quota); - if (0 != ntohl (quota.value__)) - return; -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s' due to `%s'\n", - GNUNET_i2s (&n->id), "SET_QUOTA"); -#endif - if (is_connected (n)) - GNUNET_STATISTICS_update (GST_stats, - gettext_noop ("# disconnects due to quota of 0"), - 1, GNUNET_NO); - disconnect_neighbour (n); + n->state = S_CONNECTED; + n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + GNUNET_STATISTICS_set (GST_stats, + gettext_noop ("# peers connected"), + ++neighbours_connected, + GNUNET_NO); + connect_notify_cb (callback_cls, &n->id, ats, ats_count); + set_address (&n->primary_address, + n->primary_address.address, + n->primary_address.session, + n->primary_address.bandwidth_in, + n->primary_address.bandwidth_out, + GNUNET_YES); } /** - * Closure for the neighbours_iterate function. - */ -struct IteratorContext -{ - /** - * Function to call on each connected neighbour. - */ - GST_NeighbourIterator cb; - - /** - * Closure for 'cb'. - */ - void *cb_cls; -}; - - -/** - * Call the callback from the closure for each connected neighbour. + * Test if we're connected to the given peer. * - * @param cls the 'struct IteratorContext' - * @param key the hash of the public key of the neighbour - * @param value the 'struct NeighbourMapEntry' - * @return GNUNET_OK (continue to iterate) + * @param target peer to test + * @return GNUNET_YES if we are connected, GNUNET_NO if not */ -static int -neighbours_iterate (void *cls, const GNUNET_HashCode * key, void *value) +int +GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target) { - struct IteratorContext *ic = cls; - struct NeighbourMapEntry *n = value; - - if (!is_connected (n)) - return GNUNET_OK; - - ic->cb (ic->cb_cls, &n->id, NULL, 0, n->address); - return GNUNET_OK; + return test_connected (lookup_neighbour (target)); } /** - * Iterate over all connected neighbours. - * - * @param cb function to call - * @param cb_cls closure for cb - */ -void -GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls) -{ - struct IteratorContext ic; - - // This can happen during shutdown - if (neighbours == NULL) - { - return; - } - - ic.cb = cb; - ic.cb_cls = cb_cls; - GNUNET_CONTAINER_multihashmap_iterate (neighbours, &neighbours_iterate, &ic); -} - -/** - * If we have an active connection to the given target, it must be shutdown. + * Change the incoming quota for the given peer. * - * @param target peer to disconnect from + * @param neighbour identity of peer to change qutoa for + * @param quota new quota */ void -GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target) +GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour, + struct GNUNET_BANDWIDTH_Value32NBO quota) { struct NeighbourMapEntry *n; - // This can happen during shutdown - if (neighbours == NULL) + if (NULL == (n = lookup_neighbour (neighbour))) { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# SET QUOTA messages ignored (no such peer)"), + 1, GNUNET_NO); return; } - - n = lookup_neighbour (target); - if (NULL == n) - return; /* not active */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Setting inbound quota of %u Bps for peer `%s' to all clients\n", + ntohl (quota.value__), GNUNET_i2s (&n->id)); + GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, quota); + if (0 != ntohl (quota.value__)) + return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s' due to `%s'\n", + GNUNET_i2s (&n->id), "SET_QUOTA"); + if (GNUNET_YES == test_connected (n)) + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# disconnects due to quota of 0"), + 1, GNUNET_NO); disconnect_neighbour (n); } @@ -2309,12 +2890,9 @@ GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity const struct SessionDisconnectMessage *sdm; GNUNET_HashCode hc; -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received DISCONNECT message from peer `%s'\n", GNUNET_i2s (peer)); -#endif - if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage)) { // GNUNET_break_op (0); @@ -2325,11 +2903,9 @@ GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity return; } sdm = (const struct SessionDisconnectMessage *) msg; - n = lookup_neighbour (peer); - if (NULL == n) + if (NULL == (n = lookup_neighbour (peer))) return; /* gone already */ - if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value <= - n->connect_ts.abs_value) + if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value <= n->connect_ack_timestamp.abs_value) { GNUNET_STATISTICS_update (GST_stats, gettext_noop @@ -2361,360 +2937,210 @@ GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity GNUNET_break_op (0); return; } - GST_neighbours_force_disconnect (peer); + if (GNUNET_YES == test_connected (n)) + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# other peer asked to disconnect from us"), 1, + GNUNET_NO); + disconnect_neighbour (n); } /** - * We received a 'SESSION_CONNECT_ACK' message from the other peer. - * Consider switching to it. - * - * @param message possibly a 'struct SessionConnectMessage' (check format) - * @param peer identity of the peer to switch the address for - * @param address address of the other peer, NULL if other peer - * connected to us - * @param session session to use (or NULL) - * @param ats performance data - * @param ats_count number of entries in ats + * Closure for the neighbours_iterate function. */ -void -GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Address *address, - struct Session *session, - const struct GNUNET_ATS_Information *ats, - uint32_t ats_count) +struct IteratorContext { - const struct SessionConnectMessage *scm; - struct GNUNET_MessageHeader msg; - struct NeighbourMapEntry *n; - size_t msg_len; - size_t ret; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received CONNECT_ACK message from peer `%s'\n", - GNUNET_i2s (peer)); - - if (ntohs (message->size) != sizeof (struct SessionConnectMessage)) - { - GNUNET_break_op (0); - return; - } - scm = (const struct SessionConnectMessage *) message; - GNUNET_break_op (ntohl (scm->reserved) == 0); - n = lookup_neighbour (peer); - if (NULL == n) - { - /* we did not send 'CONNECT' -- at least not recently */ - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# unexpected CONNECT_ACK messages (no peer)"), - 1, GNUNET_NO); - return; - } - - /* Additional check - * - * ((n->state != S_CONNECT_RECV) && (n->address != NULL)): - * - * We also received an CONNECT message, switched from SENDT to RECV and - * ATS already suggested us an address after a successful blacklist check + /** + * Function to call on each connected neighbour. */ + GST_NeighbourIterator cb; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received CONNECT_ACK message from peer `%s' in state `%s'\n", - GNUNET_i2s (peer), - print_state(n->state)); - - if ((n->address != NULL) && (n->state == S_CONNECTED)) - { - /* After fast reconnect: send ACK (ACK) even when we are connected */ - msg_len = sizeof (msg); - msg.size = htons (msg_len); - msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK); - - ret = send_with_session(n, - (const char *) &msg, msg_len, - UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, - NULL, NULL); - - if (ret == GNUNET_SYSERR) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to send SESSION_ACK to `%4s' using address '%s' session %X\n", - GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session); - return; - } - - if ((n->state != S_CONNECT_SENT) && - ((n->state != S_CONNECT_RECV) && (n->address != NULL))) - { - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# unexpected CONNECT_ACK messages"), 1, - GNUNET_NO); - return; - } - if (n->state != S_CONNECTED) - change_state (n, S_CONNECTED); - - if (NULL != session) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, - "transport-ats", - "Giving ATS session %p of plugin %s for peer %s\n", - session, address->transport_name, GNUNET_i2s (peer)); - } - GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count); - GNUNET_assert (NULL != n->address); + /** + * Closure for 'cb'. + */ + void *cb_cls; +}; - if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address))) - { - GST_validation_set_address_use (n->address, n->session, GNUNET_YES); - GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES); - n->address_state = USED; - } - GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in); +/** + * Call the callback from the closure for each connected neighbour. + * + * @param cls the 'struct IteratorContext' + * @param key the hash of the public key of the neighbour + * @param value the 'struct NeighbourMapEntry' + * @return GNUNET_OK (continue to iterate) + */ +static int +neighbours_iterate (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct IteratorContext *ic = cls; + struct NeighbourMapEntry *n = value; - /* send ACK (ACK) */ - msg_len = sizeof (msg); - msg.size = htons (msg_len); - msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK); + if (GNUNET_YES == test_connected (n)) + ic->cb (ic->cb_cls, &n->id, NULL, 0, n->primary_address.address); + return GNUNET_OK; +} - ret = send_with_session(n, - (const char *) &msg, msg_len, - UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, - NULL, NULL); - if (ret == GNUNET_SYSERR) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to send SESSION_ACK to `%4s' using address '%s' session %X\n", - GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session); +/** + * Iterate over all connected neighbours. + * + * @param cb function to call + * @param cb_cls closure for cb + */ +void +GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls) +{ + struct IteratorContext ic; + if (NULL == neighbours) + return; /* can happen during shutdown */ + ic.cb = cb; + ic.cb_cls = cb_cls; + GNUNET_CONTAINER_multihashmap_iterate (neighbours, &neighbours_iterate, &ic); +} - if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK) - n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n); - neighbours_connected++; - GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1, - GNUNET_NO); -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Notify about connect of `%4s' using address '%s' session %X LINE %u\n", - GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session, - __LINE__); -#endif - connect_notify_cb (callback_cls, &n->id, ats, ats_count); - send_outbound_quota (peer, n->bandwidth_out); +/** + * If we have an active connection to the given target, it must be shutdown. + * + * @param target peer to disconnect from + */ +void +GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target) +{ + struct NeighbourMapEntry *n; + if (NULL == (n = lookup_neighbour (target))) + return; /* not active */ + if (GNUNET_YES == test_connected (n)) + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# disconnected from peer upon explicit request"), 1, + GNUNET_NO); + disconnect_neighbour (n); } -void -GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Address *address, - struct Session *session, - const struct GNUNET_ATS_Information *ats, - uint32_t ats_count) +/** + * Obtain current latency information for the given neighbour. + * + * @param peer to get the latency for + * @return observed latency of the address, FOREVER if the + * the connection is not up + */ +struct GNUNET_TIME_Relative +GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer) { struct NeighbourMapEntry *n; -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ACK message from peer `%s'\n", - GNUNET_i2s (peer)); -#endif - - if (ntohs (message->size) != sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break_op (0); - return; - } n = lookup_neighbour (peer); - if (NULL == n) + if (NULL == n) + return GNUNET_TIME_UNIT_FOREVER_REL; + switch (n->state) { + case S_CONNECTED: + case S_RECONNECT_SENT: + case S_RECONNECT_ATS: + return n->latency; + case S_NOT_CONNECTED: + case S_INIT_BLACKLIST: + case S_INIT_ATS: + case S_CONNECT_SENT: + case S_CONNECT_RECV_BLACKLIST: + case S_DISCONNECT: + case S_DISCONNECT_FINISHED: + return GNUNET_TIME_UNIT_FOREVER_REL; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); GNUNET_break (0); - return; - } - if (S_CONNECTED == n->state) - return; - if (!is_connecting (n)) - { - GNUNET_STATISTICS_update (GST_stats, - gettext_noop ("# unexpected ACK messages"), 1, - GNUNET_NO); - return; - } - change_state (n, S_CONNECTED); - if (NULL != session) - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, - "transport-ats", - "Giving ATS session %p of plugin %s for peer %s\n", - session, address->transport_name, GNUNET_i2s (peer)); - GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count); - GNUNET_assert (n->address != NULL); - - if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address))) - { - GST_validation_set_address_use (n->address, n->session, GNUNET_YES); - GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES); - n->address_state = USED; + break; } - - - neighbours_connected++; - GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1, - GNUNET_NO); - - GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in); - if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK) - n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n); -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Notify about connect of `%4s' using address '%s' session %X LINE %u\n", - GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session, - __LINE__); -#endif - connect_notify_cb (callback_cls, &n->id, ats, ats_count); - send_outbound_quota (peer, n->bandwidth_out); + return GNUNET_TIME_UNIT_FOREVER_REL; } -struct BlackListCheckContext -{ - struct GNUNET_ATS_Information *ats; - - uint32_t ats_count; - - struct Session *session; - - struct GNUNET_HELLO_Address *address; - - struct GNUNET_TIME_Absolute ts; -}; - -static void -handle_connect_blacklist_cont (void *cls, - const struct GNUNET_PeerIdentity *peer, - int result) +/** + * Obtain current address information for the given neighbour. + * + * @param peer + * @return address currently used + */ +struct GNUNET_HELLO_Address * +GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer) { struct NeighbourMapEntry *n; - struct BlackListCheckContext *bcc = cls; - -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Blacklist check due to CONNECT message: `%s'\n", - GNUNET_i2s (peer), - (result == GNUNET_OK) ? "ALLOWED" : "FORBIDDEN"); -#endif - - /* not allowed */ - if (GNUNET_OK != result) - { - GNUNET_HELLO_address_free (bcc->address); - GNUNET_free (bcc); - return; - } n = lookup_neighbour (peer); if (NULL == n) - n = setup_neighbour (peer); - - if (bcc->ts.abs_value > n->connect_ts.abs_value) - { - if (NULL != bcc->session) - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, - "transport-ats", - "Giving ATS session %p of address `%s' for peer %s\n", - bcc->session, GST_plugins_a2s (bcc->address), - GNUNET_i2s (peer)); - /* Tell ATS about the session, so ATS can suggest it if it likes it. */ - - GNUNET_ATS_address_update (GST_ats, bcc->address, bcc->session, bcc->ats, - bcc->ats_count); - n->connect_ts = bcc->ts; - } - - GNUNET_HELLO_address_free (bcc->address); - GNUNET_free (bcc); - - if (n->state != S_CONNECT_RECV) - change_state (n, S_CONNECT_RECV); - - - /* Ask ATS for an address to connect via that address */ - if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->ats_suggest); - n->ats_suggest = - GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, - n); - GNUNET_ATS_suggest_address (GST_ats, peer); + return NULL; + return n->primary_address.address; } + /** - * We received a 'SESSION_CONNECT' message from the other peer. - * Consider switching to it. + * Initialize the neighbours subsystem. * - * @param message possibly a 'struct SessionConnectMessage' (check format) - * @param peer identity of the peer to switch the address for - * @param address address of the other peer, NULL if other peer - * connected to us - * @param session session to use (or NULL) - * @param ats performance data - * @param ats_count number of entries in ats (excluding 0-termination) + * @param cls closure for callbacks + * @param connect_cb function to call if we connect to a peer + * @param disconnect_cb function to call if we disconnect from a peer + * @param peer_address_cb function to call if we change an active address + * of a neighbour */ void -GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Address *address, - struct Session *session, - const struct GNUNET_ATS_Information *ats, - uint32_t ats_count) +GST_neighbours_start (void *cls, + GNUNET_TRANSPORT_NotifyConnect connect_cb, + GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb, + GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb) { - const struct SessionConnectMessage *scm; - struct BlackListCheckContext *bcc = NULL; - struct NeighbourMapEntry *n; + callback_cls = cls; + connect_notify_cb = connect_cb; + disconnect_notify_cb = disconnect_cb; + address_change_cb = peer_address_cb; + neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE); +} -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received CONNECT message from peer `%s'\n", GNUNET_i2s (peer)); -#endif - if (ntohs (message->size) != sizeof (struct SessionConnectMessage)) - { - GNUNET_break_op (0); - return; - } +/** + * Disconnect from the given neighbour. + * + * @param cls unused + * @param key hash of neighbour's public key (not used) + * @param value the 'struct NeighbourMapEntry' of the neighbour + * @return GNUNET_OK (continue to iterate) + */ +static int +disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct NeighbourMapEntry *n = value; - scm = (const struct SessionConnectMessage *) message; - GNUNET_break_op (ntohl (scm->reserved) == 0); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Disconnecting peer `%4s', %s\n", + GNUNET_i2s (&n->id), "SHUTDOWN_TASK"); + n->state = S_DISCONNECT_FINISHED; + free_neighbour (n, GNUNET_NO); + return GNUNET_OK; +} - GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count); - n = lookup_neighbour (peer); - if ((n != NULL) && ((S_CONNECTED == n->state) || (S_FAST_RECONNECT == n->state))) - { - /* connected peer switches addresses or is trying to do a fast reconnect*/ +/** + * Cleanup the neighbours subsystem. + */ +void +GST_neighbours_stop () +{ + if (NULL == neighbours) return; - } - - - /* we are not connected to this peer */ - /* do blacklist check */ - bcc = - GNUNET_malloc (sizeof (struct BlackListCheckContext) + - sizeof (struct GNUNET_ATS_Information) * (ats_count + 1)); - bcc->ts = GNUNET_TIME_absolute_ntoh (scm->timestamp); - bcc->ats_count = ats_count + 1; - bcc->address = GNUNET_HELLO_address_copy (address); - bcc->session = session; - bcc->ats = (struct GNUNET_ATS_Information *) &bcc[1]; - memcpy (bcc->ats, ats, sizeof (struct GNUNET_ATS_Information) * ats_count); - bcc->ats[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); - bcc->ats[ats_count].value = - htonl ((uint32_t) GST_neighbour_get_latency (peer).rel_value); - GST_blacklist_test_allowed (peer, address->transport_name, - &handle_connect_blacklist_cont, bcc); + GNUNET_CONTAINER_multihashmap_iterate (neighbours, + &disconnect_all_neighbours, + NULL); + GNUNET_CONTAINER_multihashmap_destroy (neighbours); + neighbours = NULL; + callback_cls = NULL; + connect_notify_cb = NULL; + disconnect_notify_cb = NULL; + address_change_cb = NULL; } diff --git a/src/transport/gnunet-service-transport_neighbours.h b/src/transport/gnunet-service-transport_neighbours.h index 33fa1da..23091b7 100644 --- a/src/transport/gnunet-service-transport_neighbours.h +++ b/src/transport/gnunet-service-transport_neighbours.h @@ -127,6 +127,7 @@ GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity void GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour); + /** * We received a KEEP_ALIVE_RESPONSE message and use this to calculate latency * to this peer @@ -212,10 +213,8 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer, * @param ats_count number of entries in ats * @param bandwidth_in inbound quota to be used when connection is up * @param bandwidth_out outbound quota to be used when connection is up - * @return GNUNET_YES if we are currently connected, GNUNET_NO if the - * connection is not up (yet) */ -int +void GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct Session *session, @@ -266,13 +265,26 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count); + +/** + * We received a 'SESSION_ACK' message from the other peer. + * FIXME: describe what this means! + * + * @param message possibly a 'struct SessionConnectMessage' (check format) + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) + * @param ats performance data + * @param ats_count number of entries in ats + */ void -GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Address *address, - struct Session *session, - const struct GNUNET_ATS_Information *ats, - uint32_t ats_count); +GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count); /** diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c index a6d9424..8421969 100644 --- a/src/transport/gnunet-service-transport_validation.c +++ b/src/transport/gnunet-service-transport_validation.c @@ -251,6 +251,10 @@ struct ValidationEntry * Are we expecting a PONG message for this validation entry? */ int expecting_pong; + + /* FIXME: DEBUGGING */ + int last_line_set_to_no; + int last_line_set_to_yes; }; @@ -600,6 +604,9 @@ find_validation_entry (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded if (public_key == NULL) return NULL; ve = GNUNET_malloc (sizeof (struct ValidationEntry)); + ve->in_use = GNUNET_SYSERR; /* not defined */ + ve->last_line_set_to_no = 0; + ve->last_line_set_to_yes = 0; ve->address = GNUNET_HELLO_address_copy (address); ve->public_key = *public_key; ve->pid = address->peer; @@ -863,10 +870,8 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, PONG_SIGNATURE_LIFETIME.rel_value / 4) { /* create / update cached sig */ -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating PONG signature to indicate ownership.\n"); -#endif *sig_cache_exp = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME); pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp); GNUNET_assert (GNUNET_OK == @@ -1076,13 +1081,10 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, GNUNET_NO); return; } -#if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Address validated for peer `%s' with plugin `%s': `%s'\n", - GNUNET_i2s (sender), tname, GST_plugins_a2s (tname, addr, - addrlen)); -#endif + GNUNET_i2s (sender), tname, GST_plugins_a2s (ve->address)); /* validity achieved, remember it! */ ve->expecting_pong = GNUNET_NO; ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); @@ -1097,7 +1099,7 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, /* build HELLO to store in PEERINFO */ ve->copied = GNUNET_NO; hello = GNUNET_HELLO_create (&ve->public_key, &add_valid_peer_address, ve); - GNUNET_PEERINFO_add_peer (GST_peerinfo, hello); + GNUNET_PEERINFO_add_peer (GST_peerinfo, hello, NULL, NULL); GNUNET_free (hello); } @@ -1128,7 +1130,7 @@ GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello) return; /* Add peer identity without addresses to peerinfo service */ h = GNUNET_HELLO_create (&vac.public_key, NULL, NULL); - GNUNET_PEERINFO_add_peer (GST_peerinfo, h); + GNUNET_PEERINFO_add_peer (GST_peerinfo, h, NULL, NULL); #if VERBOSE_VALIDATION GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Adding `%s' without addresses for peer `%s'\n"), "HELLO", @@ -1211,11 +1213,13 @@ GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target, * @param session the session * @param in_use GNUNET_YES if we are now using the address for a connection, * GNUNET_NO if we are no longer using the address for a connection + * @param line line of caller just for DEBUGGING! */ void GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address, struct Session *session, - int in_use) + int in_use, + int line) { struct ValidationEntry *ve; @@ -1229,10 +1233,33 @@ GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address, return; } if (ve->in_use == in_use) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "GST_validation_set_address_use: %s %s: ve->in_use %i <-> in_use %i\n", - GNUNET_i2s (&address->peer), GST_plugins_a2s (address), ve->in_use, - in_use); + { + + if (GNUNET_YES == in_use) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error setting address in use for peer `%s' `%s' to USED: set last time by %i, called now by %i\n", + GNUNET_i2s (&address->peer), GST_plugins_a2s (address), + ve->last_line_set_to_yes, line); + } + if (GNUNET_NO == in_use) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error setting address in use for peer `%s' `%s' to NOT_USED: set last time by %i, called now by %i\n", + GNUNET_i2s (&address->peer), GST_plugins_a2s (address), + ve->last_line_set_to_no, line); + } + } + + if (GNUNET_YES == in_use) + { + ve->last_line_set_to_yes = line; + } + if (GNUNET_NO == in_use) + { + ve->last_line_set_to_no = line; + } + GNUNET_break (ve->in_use != in_use); /* should be different... */ ve->in_use = in_use; if (in_use == GNUNET_YES) diff --git a/src/transport/gnunet-service-transport_validation.h b/src/transport/gnunet-service-transport_validation.h index 9b1063b..dd5bcd6 100644 --- a/src/transport/gnunet-service-transport_validation.h +++ b/src/transport/gnunet-service-transport_validation.h @@ -52,13 +52,16 @@ GST_validation_stop (void); * address more or less often. * * @param address the address - * @param session session + * @param session the session * @param in_use GNUNET_YES if we are now using the address for a connection, * GNUNET_NO if we are no longer using the address for a connection + * @param line line of caller just for DEBUGGING! */ void GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address, - struct Session *session, int in_use); + struct Session *session, + int in_use, + int line); /** diff --git a/src/transport/gnunet-transport-certificate-creation b/src/transport/gnunet-transport-certificate-creation index a38a7b7..b5cffb2 100755 --- a/src/transport/gnunet-transport-certificate-creation +++ b/src/transport/gnunet-transport-certificate-creation @@ -32,7 +32,7 @@ DUALCASE=1; export DUALCASE # for MKS sh # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH -relink_command="(cd /home/grothoff/svn/gnunet/src/transport; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; LD_LIBRARY_PATH=/usr/lib/debug:/home/grothoff/lib; export LD_LIBRARY_PATH; PATH=/opt/jdk1.6.0_22/bin:/usr/lib/jvm/java-6-sun//bin:.:/home/grothoff/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games; export PATH; gcc -fno-strict-aliasing -Wall -g -Wall -Werror -O0 -I/home/grothoff//include -o \$progdir/\$file gnunet-transport-certificate-creation.o -L/home/grothoff//lib ../../src/util/.libs/libgnunetutil.so -ldl -Wl,-rpath -Wl,/home/grothoff/svn/gnunet/src/util/.libs -Wl,-rpath -Wl,/home/grothoff/lib)" +relink_command="(cd /home/grothoff/gnunet-0.9.3/src/transport; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; LD_LIBRARY_PATH=/usr/lib/debug:/home/grothoff/lib; export LD_LIBRARY_PATH; PATH=/opt/jdk1.6.0_22/bin:/usr/lib/jvm/java-6-sun//bin:.:/home/grothoff/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games; export PATH; gcc -fno-strict-aliasing -Wall -g -Wall -Werror -O0 -I/home/grothoff//include -o \$progdir/\$file gnunet-transport-certificate-creation.o -L/home/grothoff//lib ../../src/util/.libs/libgnunetutil.so -ldl -Wl,-rpath -Wl,/home/grothoff/gnunet-0.9.3/src/util/.libs)" # This environment variable determines our operation mode. if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then diff --git a/src/transport/gnunet-transport-certificate-creation.c b/src/transport/gnunet-transport-certificate-creation.c index 2ec8d36..c4c13dc 100644 --- a/src/transport/gnunet-transport-certificate-creation.c +++ b/src/transport/gnunet-transport-certificate-creation.c @@ -62,7 +62,7 @@ main (int argc, char **argv) if (openssl == NULL) return 2; GNUNET_assert (GNUNET_OS_process_wait (openssl) == GNUNET_OK); - GNUNET_OS_process_close (openssl); + GNUNET_OS_process_destroy (openssl); /* Create a self-signed certificate in batch mode using rsa key */ /* openssl req -batch -days 365 -out $2 -new -x509 -key $1 2> /dev/null */ @@ -73,7 +73,7 @@ main (int argc, char **argv) if (openssl == NULL) return 3; GNUNET_assert (GNUNET_OS_process_wait (openssl) == GNUNET_OK); - GNUNET_OS_process_close (openssl); + GNUNET_OS_process_destroy (openssl); CHMOD (argv[1], S_IRUSR); CHMOD (argv[2], S_IRUSR); return 0; diff --git a/src/transport/gnunet-transport-wlan-sender.c b/src/transport/gnunet-transport-wlan-sender.c index 9f06b63..daa8f02 100644 --- a/src/transport/gnunet-transport-wlan-sender.c +++ b/src/transport/gnunet-transport-wlan-sender.c @@ -46,35 +46,22 @@ #define IEEE80211_FC0_TYPE_CTL 0x04 #define IEEE80211_FC0_TYPE_DATA 0x08 -GNUNET_NETWORK_STRUCT_BEGIN - -/* - * generic definitions for IEEE 802.11 frames - */ -struct ieee80211_frame -{ - u_int8_t i_fc[2]; - u_int8_t i_dur[2]; - u_int8_t i_addr1[IEEE80211_ADDR_LEN]; - u_int8_t i_addr2[IEEE80211_ADDR_LEN]; - u_int8_t i_addr3[IEEE80211_ADDR_LEN]; - u_int8_t i_seq[2]; - u_int8_t llc[4]; -} GNUNET_PACKED; -GNUNET_NETWORK_STRUCT_END /** * function to fill the radiotap header * @param header pointer to the radiotap header + * @param size total message size * @return GNUNET_YES at success */ static int -getRadiotapHeader (struct Radiotap_Send *header) +getRadiotapHeader (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header, + uint16_t size) { + header->header.size = htons (size); + header->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER); header->rate = 255; header->tx_power = 0; header->antenna = 0; - return GNUNET_YES; } @@ -87,23 +74,21 @@ getRadiotapHeader (struct Radiotap_Send *header) * @return GNUNET_YES if there was no error */ static int -getWlanHeader (struct ieee80211_frame *Header, const char *to_mac_addr, - const char *mac, unsigned int size) +getWlanHeader (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *Header, + const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr, + const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac, unsigned int size) { - uint16_t *tmp16; const int rate = 11000000; - Header->i_fc[0] = IEEE80211_FC0_TYPE_DATA; - Header->i_fc[1] = 0x00; - memcpy (&Header->i_addr3, &mac_bssid_gnunet, sizeof (mac_bssid_gnunet)); - memcpy (&Header->i_addr2, mac, sizeof (mac_bssid_gnunet)); - memcpy (&Header->i_addr1, to_mac_addr, sizeof (mac_bssid_gnunet)); - - tmp16 = (uint16_t *) Header->i_dur; - *tmp16 = (uint16_t) GNUNET_htole16 ((size * 1000000) / rate + 290); + Header->frame_control = htons (IEEE80211_FC0_TYPE_DATA); + Header->addr3 = mac_bssid_gnunet; + Header->addr2 = *mac; + Header->addr1 = *to_mac_addr; + Header->duration = GNUNET_htole16 ((size * 1000000) / rate + 290); Header->llc[0] = WLAN_LLC_DSAP_FIELD; Header->llc[1] = WLAN_LLC_SSAP_FIELD; - + Header->llc[2] = 0; // FIXME + Header->llc[3] = 0; // FIXME return GNUNET_YES; } @@ -112,13 +97,10 @@ int main (int argc, char *argv[]) { char msg_buf[WLAN_MTU]; - struct GNUNET_MessageHeader *msg; - struct ieee80211_frame *wlan_header; - struct Radiotap_Send *radiotap; - + struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radiotap; unsigned int temp[6]; - char inmac[6]; - char outmac[6]; + struct GNUNET_TRANSPORT_WLAN_MacAddress inmac; + struct GNUNET_TRANSPORT_WLAN_MacAddress outmac; int pos; long long count; double bytes_per_s; @@ -136,7 +118,7 @@ main (int argc, char *argv[]) return 1; } if (6 != - sscanf (argv[3], "%x-%x-%x-%x-%x-%x", &temp[0], &temp[1], &temp[2], + SSCANF (argv[3], "%x-%x-%x-%x-%x-%x", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5])) { fprintf (stderr, @@ -144,8 +126,10 @@ main (int argc, char *argv[]) "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n"); return 1; } + for (i = 0; i < 6; i++) + outmac.mac[i] = temp[i]; if (6 != - sscanf (argv[2], "%x-%x-%x-%x-%x-%x", &temp[0], &temp[1], &temp[2], + SSCANF (argv[2], "%x-%x-%x-%x-%x-%x", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5])) { fprintf (stderr, @@ -154,9 +138,7 @@ main (int argc, char *argv[]) return 1; } for (i = 0; i < 6; i++) - inmac[i] = temp[i]; - for (i = 0; i < 6; i++) - outmac[i] = temp[i]; + inmac.mac[i] = temp[i]; pid_t pid; int commpipe[2]; /* This holds the fd for the input & output of the pipe */ @@ -185,22 +167,16 @@ main (int argc, char *argv[]) setvbuf (stdout, (char *) NULL, _IONBF, 0); /* Set non-buffered output on stdout */ - msg = (struct GNUNET_MessageHeader *) msg_buf; - msg->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); - msg->size = htons (WLAN_MTU); - radiotap = (struct Radiotap_Send *) &msg[1]; - wlan_header = (struct ieee80211_frame *) &radiotap[1]; + radiotap = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) msg_buf; + getRadiotapHeader (radiotap, WLAN_MTU); pos = 0; - - getRadiotapHeader (radiotap); - getWlanHeader (wlan_header, outmac, inmac, - WLAN_MTU - sizeof (struct GNUNET_MessageHeader)); - + getWlanHeader (&radiotap->frame, &outmac, &inmac, + WLAN_MTU); start = time (NULL); count = 0; while (1) { - pos += write (commpipe[1], msg, WLAN_MTU - pos); + pos += write (commpipe[1], msg_buf, WLAN_MTU - pos); if (pos % WLAN_MTU == 0) { pos = 0; diff --git a/src/transport/gnunet-transport.c b/src/transport/gnunet-transport.c index ee977f5..3b6b7e4 100644 --- a/src/transport/gnunet-transport.c +++ b/src/transport/gnunet-transport.c @@ -37,8 +37,10 @@ /** * How long do we wait for the NAT test to report success? + * Should match NAT_SERVER_TIMEOUT in 'nat_test.c'. */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) +#define RESOLUTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) /** * Which peer should we connect to? @@ -121,6 +123,8 @@ static struct GNUNET_PeerIdentity pid; */ static GNUNET_SCHEDULER_TaskIdentifier end; +static struct GNUNET_CONTAINER_MultiHashMap *peers; + /** * Selected level of verbosity. */ @@ -193,7 +197,7 @@ display_test_result (struct TestContext *tc, int result) if ((0 == resolver_users) && (NULL != resolver)) { GNUNET_break (0 == GNUNET_OS_process_kill (resolver, SIGTERM)); - GNUNET_OS_process_close (resolver); + GNUNET_OS_process_destroy (resolver); resolver = NULL; } } @@ -443,19 +447,32 @@ notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, traffic_received += ntohs (message->size); } -void +struct ResolutionContext +{ + struct GNUNET_HELLO_Address *addrcp; + + int printed; +}; + + +static void process_string (void *cls, const char *address) { - struct GNUNET_HELLO_Address *addrcp = cls; + struct ResolutionContext *rc = cls; + struct GNUNET_HELLO_Address *addrcp = rc->addrcp; - if ((address != NULL)) + if (address != NULL) { FPRINTF (stdout, _("Peer `%s': %s %s\n"), GNUNET_i2s (&addrcp->peer), addrcp->transport_name, address); + rc->printed = GNUNET_YES; } else { /* done */ - GNUNET_free (addrcp); + if (GNUNET_NO == rc->printed) + FPRINTF (stdout, _("Peer `%s': %s <unable to resolve address>\n"), GNUNET_i2s (&addrcp->peer), addrcp->transport_name); + GNUNET_free (rc->addrcp); + GNUNET_free (rc); } } @@ -471,6 +488,7 @@ process_address (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address) { const struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct ResolutionContext *rc; if (peer == NULL) { @@ -484,10 +502,16 @@ process_address (void *cls, const struct GNUNET_PeerIdentity *peer, return; } + rc = GNUNET_malloc(sizeof (struct ResolutionContext)); + rc->addrcp = GNUNET_HELLO_address_copy(address); + rc->printed = GNUNET_NO; + + GNUNET_assert (NULL != rc); + /* Resolve address to string */ GNUNET_TRANSPORT_address_to_string (cfg, address, numeric, - GNUNET_TIME_UNIT_MINUTES, &process_string, - GNUNET_HELLO_address_copy(address)); + RESOLUTION_TIMEOUT, &process_string, + rc); } @@ -504,7 +528,13 @@ shutdown_task (void *cls, { struct GNUNET_TRANSPORT_PeerIterateContext *pic = cls; - GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pic); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pic); + + if (NULL != peers) + { + GNUNET_CONTAINER_multihashmap_destroy (peers); + peers = NULL; + } } @@ -561,8 +591,9 @@ run (void *cls, char *const *args, const char *cfgfile, } if (iterate_connections) { + peers = GNUNET_CONTAINER_multihashmap_create (20); GNUNET_TRANSPORT_peer_get_active_addresses (cfg, NULL, GNUNET_YES, - GNUNET_TIME_UNIT_MINUTES, + TIMEOUT, &process_address, (void *) cfg); } if (monitor_connections) diff --git a/src/transport/plugin_transport_http.c b/src/transport/plugin_transport_http.c index f88ff33..d99f531 100644 --- a/src/transport/plugin_transport_http.c +++ b/src/transport/plugin_transport_http.c @@ -106,7 +106,23 @@ struct PrettyPrinterContext */ struct Plugin; +/** + * Start session timeout + */ +static void +start_session_timeout (struct Session *s); +/** + * Increment session timeout due to activity + */ +static void +reschedule_session_timeout (struct Session *s); + +/** + * Cancel timeout + */ +static void +stop_session_timeout (struct Session *s); /** * Append our port and forward the result. @@ -151,6 +167,9 @@ append_port (void *cls, const char *hostname) } + + + /** * Convert the transports address to a nice, human-readable * format. @@ -209,6 +228,12 @@ http_plugin_address_pretty_printer (void *cls, const char *type, sbs = sizeof (struct sockaddr_in); port = ntohs (a4->u4_port); } + else if (0 == addrlen) + { + asc (asc_cls, "<inbound connection>"); + asc (asc_cls, NULL); + return; + } else { /* invalid address */ @@ -243,13 +268,10 @@ http_plugin_address_pretty_printer (void *cls, const char *type, static int http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) { - struct Plugin *plugin = cls; struct IPv4HttpAddressWrapper *w_tv4 = plugin->ipv4_addr_head; struct IPv6HttpAddressWrapper *w_tv6 = plugin->ipv6_addr_head; - - GNUNET_assert (cls != NULL); if ((addrlen != sizeof (struct sockaddr_in)) || (addrlen != sizeof (struct sockaddr_in6))) @@ -311,6 +333,8 @@ http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity *peer, atsi[1].value = session->ats_address_network_type; GNUNET_break (session->ats_address_network_type != ntohl (GNUNET_ATS_NET_UNSPECIFIED)); + reschedule_session_timeout (session); + delay = plugin->env->receive (plugin->env->cls, &s->target, message, (const struct GNUNET_ATS_Information *) &atsi, @@ -318,6 +342,104 @@ http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity *peer, return delay; } + +/** + * Function called to convert a string address to + * a binary address. + * + * @param cls closure ('struct Plugin*') + * @param addr string address + * @param addrlen length of the address + * @param buf location to store the buffer + * If the function returns GNUNET_SYSERR, its contents are undefined. + * @param added length of created address + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +http_string_to_address (void *cls, + const char *addr, + uint16_t addrlen, + void **buf, + size_t *added) +{ +#if !BUILD_HTTPS + char *protocol = "http"; +#else + char *protocol = "https"; +#endif + char *addr_str = NULL; + struct sockaddr_in addr_4; + struct sockaddr_in6 addr_6; + struct IPv4HttpAddress * http_4addr; + struct IPv6HttpAddress * http_6addr; + + if ((NULL == addr) || (addrlen == 0)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if ('\0' != addr[addrlen - 1]) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (strlen (addr) != addrlen - 1) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + /* protocoll + "://" + ":" */ + if (addrlen <= (strlen (protocol) + 4)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Invalid address string `%s' to convert to address\n", + addr); + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (NULL == (addr_str = strstr(addr, "://"))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Invalid address string `%s' to convert to address\n", + addr); + GNUNET_break (0); + return GNUNET_SYSERR; + } + addr_str = &addr_str[3]; + + if (addr_str[strlen(addr_str)-1] == '/') + addr_str[strlen(addr_str)-1] = '\0'; + + if (GNUNET_OK == GNUNET_STRINGS_to_address_ipv4(addr_str, strlen(addr_str), &addr_4)) + { + http_4addr = GNUNET_malloc (sizeof (struct IPv4HttpAddress)); + http_4addr->u4_port = addr_4.sin_port; + http_4addr->ipv4_addr = (uint32_t) addr_4.sin_addr.s_addr; + (*buf) = http_4addr; + (*added) = sizeof (struct IPv4HttpAddress); + return GNUNET_OK; + } + if (GNUNET_OK == GNUNET_STRINGS_to_address_ipv6(addr_str, strlen(addr_str), &addr_6)) + { + http_6addr = GNUNET_malloc (sizeof (struct IPv6HttpAddress)); + http_6addr->u6_port = addr_6.sin6_port; + http_6addr->ipv6_addr = addr_6.sin6_addr; + (*buf) = http_6addr; + (*added) = sizeof (struct IPv6HttpAddress); + return GNUNET_OK; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Invalid address string `%s' to convert to address\n", + addr_str); + GNUNET_break (0); + return GNUNET_SYSERR; +} + + /** * Function called for a quick conversion of the binary address to * a numeric address. Note that the caller must not free the @@ -385,6 +507,7 @@ http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) return rbuf; } + struct Session * lookup_session_old (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, struct Session *session, const void *addr, size_t addrlen, @@ -398,11 +521,11 @@ lookup_session_old (struct Plugin *plugin, const struct GNUNET_PeerIdentity *tar { #if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, - "Comparing peer `%s' address `%s' len %i session %X to \n", + "Comparing peer `%s' address `%s' len %i session %p to \n", GNUNET_i2s (target), GNUNET_a2s (addr, addrlen), addrlen, session); GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, - "peer `%s' address `%s' len %i session %X \n\n", + "peer `%s' address `%s' len %i session %p \n\n", GNUNET_i2s (&t->target), GNUNET_a2s (t->addr, t->addrlen), t->addrlen, t); GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "memcmp %i \n", @@ -430,6 +553,7 @@ lookup_session_old (struct Plugin *plugin, const struct GNUNET_PeerIdentity *tar return NULL; } + struct Session * lookup_session (struct Plugin *plugin, const struct GNUNET_HELLO_Address *address) @@ -445,9 +569,28 @@ lookup_session (struct Plugin *plugin, } +int +exist_session (struct Plugin *plugin, struct Session *s) +{ + struct Session * head; + + GNUNET_assert (NULL != plugin); + GNUNET_assert (NULL != s); + + for (head = plugin->head; head != NULL; head = head->next) + { + if (head == s) + return GNUNET_YES; + } + return GNUNET_NO; +} + + void delete_session (struct Session *s) { + stop_session_timeout(s); + if (s->msg_tk != NULL) { GNUNET_SERVER_mst_destroy (s->msg_tk); @@ -459,10 +602,10 @@ delete_session (struct Session *s) GNUNET_free (s); } + struct Session * create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, - const void *addr, size_t addrlen, - GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) + const void *addr, size_t addrlen) { struct Session *s = NULL; @@ -474,12 +617,12 @@ create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, s->addr = GNUNET_malloc (addrlen); memcpy (s->addr, addr, addrlen); s->addrlen = addrlen; - s->next = NULL; - s->next_receive = GNUNET_TIME_absolute_get_zero (); s->ats_address_network_type = htonl (GNUNET_ATS_NET_UNSPECIFIED); + start_session_timeout(s); return s; } + void notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, struct Session *s) @@ -491,6 +634,7 @@ notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, delete_session (s); } + /** * Creates a new outbound session the transport service will use to send data to the * peer @@ -499,7 +643,6 @@ notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, * @param address the address * @return the session or NULL of max connections exceeded */ - static struct Session * http_get_session (void *cls, const struct GNUNET_HELLO_Address *address) @@ -535,16 +678,7 @@ http_get_session (void *cls, GNUNET_assert ((addrlen == sizeof (struct IPv6HttpAddress)) || (addrlen == sizeof (struct IPv4HttpAddress))); - s = GNUNET_malloc (sizeof (struct Session)); - memcpy (&s->target, &address->peer, sizeof (struct GNUNET_PeerIdentity)); - s->plugin = plugin; - s->addr = GNUNET_malloc (address->address_length); - memcpy (s->addr, address->address, address->address_length); - s->addrlen = addrlen; - s->next = NULL; - s->next_receive = GNUNET_TIME_absolute_get_zero (); - s->inbound = GNUNET_NO; - s->ats_address_network_type = htonl (GNUNET_ATS_NET_UNSPECIFIED); + s = create_session (plugin, &address->peer, address->address, address->address_length); /* Get ATS type */ if (addrlen == sizeof (struct IPv4HttpAddress)) @@ -592,6 +726,7 @@ http_get_session (void *cls, return s; } + /** * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a @@ -653,7 +788,6 @@ http_plugin_send (void *cls, } /* create new message and schedule */ - msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size); msg->next = NULL; msg->size = msgbuf_size; @@ -663,25 +797,21 @@ http_plugin_send (void *cls, msg->transmit_cont_cls = cont_cls; memcpy (msg->buf, msgbuf, msgbuf_size); + reschedule_session_timeout (session); + if (session->inbound == GNUNET_NO) { -#if DEBUG_HTTP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Using outbound client session %p to send to `%session'\n", session, + "Using outbound client session %p to send to `%s'\n", session, GNUNET_i2s (&session->target)); -#endif - client_send (session, msg); res = msgbuf_size; } if (session->inbound == GNUNET_YES) { -#if DEBUG_HTTP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Using inbound server %p session to send to `%session'\n", session, + "Using inbound server %p session to send to `%s'\n", session, GNUNET_i2s (&session->target)); -#endif - server_send (session, msg); res = msgbuf_size; } @@ -741,14 +871,13 @@ http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) } } -static void -nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, - socklen_t addrlen) + +static void * +find_address (struct Plugin *plugin, const struct sockaddr *addr, socklen_t addrlen) { - struct Plugin *plugin = cls; + int af; struct IPv4HttpAddressWrapper *w_t4 = NULL; struct IPv6HttpAddressWrapper *w_t6 = NULL; - int af; af = addr->sa_family; switch (af) @@ -773,25 +902,7 @@ nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, break; w_t4 = w_t4->next; } - if (w_t4 == NULL) - { - w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper)); - memcpy (&w_t4->addr.ipv4_addr, &a4->sin_addr, sizeof (struct in_addr)); - w_t4->addr.u4_port = a4->sin_port; - - GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, - plugin->ipv4_addr_tail, w_t4); - } -#if DEBUG_HTTP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Notifying transport to add IPv4 address `%s'\n", - http_plugin_address_to_string (NULL, &w_t4->addr, - sizeof (struct - IPv4HttpAddress))); -#endif - plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, - sizeof (struct IPv4HttpAddress)); - + return w_t4; break; case AF_INET6: w_t6 = plugin->ipv6_addr_head; @@ -811,25 +922,68 @@ nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, break; w_t6 = w_t6->next; } + return w_t6; + break; + default: + return NULL; + } + return NULL; +} + + +static void +nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, + socklen_t addrlen) +{ + struct Plugin *plugin = cls; + struct IPv4HttpAddressWrapper *w_t4 = NULL; + struct IPv6HttpAddressWrapper *w_t6 = NULL; + int af; + + af = addr->sa_family; + switch (af) + { + case AF_INET: + w_t4 = find_address (plugin, addr, addrlen); + if (w_t4 == NULL) + { + struct sockaddr_in *a4 = (struct sockaddr_in *) addr; + w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper)); + memcpy (&w_t4->addr.ipv4_addr, &a4->sin_addr, sizeof (struct in_addr)); + w_t4->addr.u4_port = a4->sin_port; + + GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, + plugin->ipv4_addr_tail, w_t4); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Notifying transport to add IPv4 address `%s'\n", + http_plugin_address_to_string (NULL, &w_t4->addr, + sizeof (struct + IPv4HttpAddress))); + plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, + sizeof (struct IPv4HttpAddress)); + } + break; + case AF_INET6: + w_t6 = find_address (plugin, addr, addrlen); if (w_t6 == NULL) { w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper)); - + struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr; memcpy (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, sizeof (struct in6_addr)); w_t6->addr6.u6_port = a6->sin6_port; GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, w_t6); - } -#if DEBUG_HTTP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Notifying transport to add IPv6 address `%s'\n", http_plugin_address_to_string (NULL, &w_t6->addr6, sizeof (struct IPv6HttpAddress))); -#endif - plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6, + plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6, sizeof (struct IPv6HttpAddress)); + } break; default: return; @@ -837,6 +991,7 @@ nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, } + static void nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) @@ -850,35 +1005,16 @@ nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr, switch (af) { case AF_INET: - w_t4 = plugin->ipv4_addr_head; - struct sockaddr_in *a4 = (struct sockaddr_in *) addr; - - while (w_t4 != NULL) - { - int res = memcmp (&w_t4->addr.ipv4_addr, - &a4->sin_addr, - sizeof (struct in_addr)); - - if (res == 0) - { - if (a4->sin_port != w_t4->addr.u4_port) - res = -1; - } - - if (0 == res) - break; - w_t4 = w_t4->next; - } + w_t4 = find_address (plugin, addr, addrlen); if (w_t4 == NULL) return; -#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Notifying transport to remove IPv4 address `%s'\n", http_plugin_address_to_string (NULL, &w_t4->addr, sizeof (struct IPv4HttpAddress))); -#endif plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, sizeof (struct IPv4HttpAddress)); @@ -887,32 +1023,16 @@ nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr, GNUNET_free (w_t4); break; case AF_INET6: - w_t6 = plugin->ipv6_addr_head; - struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr; - - while (w_t6) - { - int res = memcmp (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, - sizeof (struct in6_addr)); - - if (res == 0) - { - if (a6->sin6_port != w_t6->addr6.u6_port) - res = -1; - } - if (0 == res) - break; - w_t6 = w_t6->next; - } + w_t6 = find_address (plugin, addr, addrlen); if (w_t6 == NULL) return; -#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Notifying transport to remove IPv6 address `%s'\n", http_plugin_address_to_string (NULL, &w_t6->addr6, sizeof (struct IPv6HttpAddress))); -#endif + plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6, sizeof (struct IPv6HttpAddress)); @@ -923,9 +1043,9 @@ nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr, default: return; } - } + /** * Our external IP address/port mapping has changed. * @@ -940,15 +1060,13 @@ nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { GNUNET_assert (cls != NULL); -#if DEBUG_HTTP struct Plugin *plugin = cls; -#endif -#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "NPMC called %s to address `%s'\n", (add_remove == GNUNET_NO) ? "remove" : "add", GNUNET_a2s (addr, addrlen)); -#endif + switch (add_remove) { case GNUNET_YES: @@ -960,6 +1078,7 @@ nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, } } + void http_check_ipv6 (struct Plugin *plugin) { @@ -993,6 +1112,7 @@ http_check_ipv6 (struct Plugin *plugin) } } + int http_get_addresses (struct Plugin *plugin, const char *serviceName, const struct GNUNET_CONFIGURATION_Handle *cfg, @@ -1203,6 +1323,7 @@ start_report_addresses (struct Plugin *plugin) } } + static void stop_report_addresses (struct Plugin *plugin) { @@ -1230,6 +1351,7 @@ stop_report_addresses (struct Plugin *plugin) } } + static int configure_plugin (struct Plugin *plugin) { @@ -1362,6 +1484,91 @@ fail: return res; } + +/** + * Session was idle, so disconnect it + */ +static void +session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (NULL != cls); + struct Session *s = cls; + + s->timeout_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %p was idle for %llu, disconnecting\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + + /* call session destroy function */ + if (s->inbound == GNUNET_NO) + GNUNET_assert (GNUNET_OK == client_disconnect (s)); + else + GNUNET_assert (GNUNET_OK == server_disconnect (s)); + +} + + +/** + * Start session timeout + */ +static void +start_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task); + + s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &session_timeout, + s); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p set to %llu\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); +} + + +/** + * Increment session timeout due to activity + */ +static void +reschedule_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); + + GNUNET_SCHEDULER_cancel (s->timeout_task); + s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &session_timeout, + s); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p set to %llu\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); +} + + +/** + * Cancel timeout + */ +static void +stop_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + + if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) + { + GNUNET_SCHEDULER_cancel (s->timeout_task); + s->timeout_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p canceled\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p was not active\n", + s); + } +} + + /** * Entry point for the plugin. */ @@ -1373,14 +1580,29 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) struct Plugin *plugin; int res; + if (NULL == env->receive) + { + /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully + initialze the plugin or the API */ + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = NULL; + api->address_pretty_printer = &http_plugin_address_pretty_printer; + api->address_to_string = &http_plugin_address_to_string; + api->string_to_address = &http_string_to_address; + return api; + } + plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->env = env; + plugin->outbound_sessions = 0; + plugin->inbound_sessions = 0; api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = plugin; api->disconnect = &http_plugin_disconnect; api->address_pretty_printer = &http_plugin_address_pretty_printer; api->check_address = &http_plugin_address_suggested; api->address_to_string = &http_plugin_address_to_string; + api->string_to_address = &http_string_to_address; api->get_session = &http_get_session; api->send = &http_plugin_send; @@ -1435,11 +1657,8 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) /* Report addresses to transport service */ start_report_addresses (plugin); -#if DEBUG_HTTP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Plugin `%s' loaded\n", plugin->name); -#endif - return api; } @@ -1452,7 +1671,13 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; - struct Session *s = NULL; + struct Session *s; + + if (NULL == plugin) + { + GNUNET_free (api); + return NULL; + } /* Stop reporting addresses to transport service */ stop_report_addresses (plugin); @@ -1461,10 +1686,8 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) s = plugin->head; while (s != NULL) { -#if DEBUG_HTTP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Disconnecting `%s' \n", GNUNET_i2s (&s->target)); -#endif if (s->inbound == GNUNET_NO) GNUNET_assert (GNUNET_OK == client_disconnect (s)); else @@ -1472,15 +1695,11 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) s = s->next; } -#if DEBUG_HTTP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping server\n"); -#endif /* Stop server */ server_stop (plugin); -#if DEBUG_HTTP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping client\n"); -#endif /* Stop client */ client_stop (plugin); @@ -1512,17 +1731,12 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) s = t; } - -#if DEBUG_HTTP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Plugin `%s' unloaded\n", plugin->name); -#endif - GNUNET_free_non_null (plugin->server_addr_v4); GNUNET_free_non_null (plugin->server_addr_v6); GNUNET_free (plugin); GNUNET_free (api); - return NULL; } diff --git a/src/transport/plugin_transport_http.h b/src/transport/plugin_transport_http.h index be8f93d..986d7d7 100644 --- a/src/transport/plugin_transport_http.h +++ b/src/transport/plugin_transport_http.h @@ -45,7 +45,7 @@ #define DEBUG_HTTP GNUNET_EXTRA_LOGGING #define VERBOSE_SERVER GNUNET_EXTRA_LOGGING #define VERBOSE_CLIENT GNUNET_EXTRA_LOGGING -#define VERBOSE_CURL GNUNET_EXTRA_LOGGING +#define VERBOSE_CURL GNUNET_NO #if BUILD_HTTPS #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_init @@ -160,6 +160,16 @@ struct Plugin int max_connections; /** + * Number of outbound sessions + */ + unsigned int outbound_sessions; + + /** + * Number of inbound sessions + */ + unsigned int inbound_sessions; + + /** * Plugin HTTPS SSL/TLS options * ---------------------------- */ @@ -216,6 +226,11 @@ struct Plugin GNUNET_SCHEDULER_TaskIdentifier server_v4_task; /** + * The IPv4 server is scheduled to run asap + */ + int server_v4_immediately; + + /** * MHD IPv6 daemon */ struct MHD_Daemon *server_v6; @@ -226,6 +241,12 @@ struct Plugin GNUNET_SCHEDULER_TaskIdentifier server_v6_task; /** + * The IPv6 server is scheduled to run asap + */ + + int server_v6_immediately; + + /** * IPv4 server socket to bind to */ struct sockaddr_in *server_addr_v4; @@ -295,6 +316,24 @@ struct IPv6HttpAddress }; GNUNET_NETWORK_STRUCT_END + +struct ServerConnection +{ + /* _RECV or _SEND */ + int direction; + + /* Should this connection get disconnected? GNUNET_YES/NO */ + int disconnect; + + /* The session this server connection belongs to */ + struct Session *session; + + /* The MHD connection */ + struct MHD_Connection *mhd_conn; +}; + + + /** * Session handle for connections. */ @@ -390,6 +429,11 @@ struct Session GNUNET_SCHEDULER_TaskIdentifier recv_wakeup_task; /** + * Session timeout task + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** * Is client send handle paused since there are no data to send? * GNUNET_YES/NO */ @@ -402,12 +446,12 @@ struct Session /** * Client send handle */ - void *server_recv; + struct ServerConnection *server_recv; /** * Client send handle */ - void *server_send; + struct ServerConnection *server_send; }; /** @@ -453,13 +497,18 @@ struct HTTP_Message void *transmit_cont_cls; }; +struct Session * +create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, + const void *addr, size_t addrlen); + +int +exist_session (struct Plugin *plugin, struct Session *s); + void delete_session (struct Session *s); -struct Session * -create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, - const void *addr, size_t addrlen, - GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls); +int +exist_session (struct Plugin *plugin, struct Session *s); struct GNUNET_TIME_Relative http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity *peer, diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c index 4679e45..f55311f 100644 --- a/src/transport/plugin_transport_http_client.c +++ b/src/transport/plugin_transport_http_client.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + (C) 2002--2012 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 @@ -26,6 +26,8 @@ #include "plugin_transport_http.h" +static struct Plugin * p; + #if VERBOSE_CURL /** * Function to log curl debug messages with GNUNET_log @@ -53,10 +55,10 @@ client_log (CURL * curl, curl_infotype type, char *data, size_t size, void *cls) } #if BUILD_HTTPS GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-https", - "Client: %X - %s", cls, text); + "Client: %p - %s", cls, text); #else GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-http", - "Client: %X - %s", cls, text); + "Client: %p - %s", cls, text); #endif } return 0; @@ -71,6 +73,7 @@ client_log (CURL * curl, curl_infotype type, char *data, size_t size, void *cls) static void client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + /** * Function setting up file descriptors and scheduling task to run * @@ -97,7 +100,6 @@ client_schedule (struct Plugin *plugin, int now) GNUNET_SCHEDULER_cancel (plugin->client_perform_task); plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; } - max = -1; FD_ZERO (&rs); FD_ZERO (&ws); @@ -133,7 +135,7 @@ client_schedule (struct Plugin *plugin, int now) plugin->client_perform_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, timeout, grs, gws, + timeout, grs, gws, &client_run, plugin); GNUNET_NETWORK_fdset_destroy (gws); GNUNET_NETWORK_fdset_destroy (grs); @@ -145,27 +147,29 @@ int client_send (struct Session *s, struct HTTP_Message *msg) { GNUNET_assert (s != NULL); - GNUNET_CONTAINER_DLL_insert (s->msg_head, s->msg_tail, msg); + GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); + if (GNUNET_YES != exist_session(p, s)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } if (s->client_put_paused == GNUNET_YES) { -#if VERBOSE_CLIENT GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, - "Client: %X was suspended, unpausing\n", s->client_put); -#endif + "Client: %p was suspended, unpausing\n", s->client_put); s->client_put_paused = GNUNET_NO; curl_easy_pause (s->client_put, CURLPAUSE_CONT); } - client_schedule (s->plugin, GNUNET_YES); return GNUNET_OK; } - /** * Task performing curl operations + * * @param cls plugin as closure * @param tc gnunet scheduler task context */ @@ -210,12 +214,19 @@ client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_assert (CURLE_OK == curl_easy_getinfo (easy_h, CURLINFO_PRIVATE, &d)); s = (struct Session *) d; + + if (GNUNET_YES != exist_session(plugin, s)) + { + GNUNET_break (0); + return; + } + GNUNET_assert (s != NULL); if (msg->msg == CURLMSG_DONE) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Client: %X connection to '%s' %s ended with reason %i: `%s'\n", + "Client: %p connection to '%s' %s ended with reason %i: `%s'\n", msg->easy_handle, GNUNET_i2s (&s->target), http_plugin_address_to_string (NULL, s->addr, s->addrlen), @@ -223,7 +234,11 @@ client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) curl_easy_strerror (msg->data.result)); client_disconnect (s); - //GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,"Notifying about ended session to peer `%s' `%s'\n", GNUNET_i2s (&s->target), http_plugin_address_to_string (plugin, s->addr, s->addrlen)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + plugin->name, + "Notifying about ended session to peer `%s' `%s'\n", + GNUNET_i2s (&s->target), + http_plugin_address_to_string (plugin, s->addr, s->addrlen)); notify_session_end (plugin, &s->target, s); } } @@ -232,6 +247,7 @@ client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) client_schedule (plugin, GNUNET_NO); } + int client_disconnect (struct Session *s) { @@ -241,15 +257,17 @@ client_disconnect (struct Session *s) struct HTTP_Message *msg; struct HTTP_Message *t; - + if (GNUNET_YES != exist_session(plugin, s)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } if (s->client_put != NULL) { -#if DEBUG_HTTP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Client: %X Deleting outbound PUT session to peer `%s'\n", + "Client: %p Deleting outbound PUT session to peer `%s'\n", s->client_put, GNUNET_i2s (&s->target)); -#endif mret = curl_multi_remove_handle (plugin->client_mh, s->client_put); if (mret != CURLM_OK) @@ -271,11 +289,9 @@ client_disconnect (struct Session *s) if (s->client_get != NULL) { -#if DEBUG_HTTP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Client: %X Deleting outbound GET session to peer `%s'\n", + "Client: %p Deleting outbound GET session to peer `%s'\n", s->client_get, GNUNET_i2s (&s->target)); -#endif mret = curl_multi_remove_handle (plugin->client_mh, s->client_get); if (mret != CURLM_OK) @@ -300,6 +316,14 @@ client_disconnect (struct Session *s) } plugin->cur_connections -= 2; + + GNUNET_assert (plugin->outbound_sessions > 0); + plugin->outbound_sessions --; + GNUNET_STATISTICS_set (plugin->env->stats, + "# HTTP outbound sessions", + plugin->outbound_sessions, + GNUNET_NO); + /* Re-schedule since handles have changed */ if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) { @@ -312,84 +336,86 @@ client_disconnect (struct Session *s) return res; } -static void +static int client_receive_mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message) { struct Session *s = cls; struct GNUNET_TIME_Relative delay; + if (GNUNET_YES != exist_session(p, s)) + { + GNUNET_break (0); + return GNUNET_OK; + } + delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); s->next_receive = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); if (GNUNET_TIME_absolute_get ().abs_value < s->next_receive.abs_value) { -#if VERBOSE_CLIENT struct Plugin *plugin = s->plugin; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: peer `%s' address `%s' next read delayed for %llu ms\n", GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen), delay); -#endif } + return GNUNET_OK; } + static void client_wake_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Session *s = cls; + if (GNUNET_YES != exist_session(p, s)) + { + GNUNET_break (0); + return; + } s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, - "Client: %X Waking up receive handle\n", s->client_get); - + "Client: %p Waking up receive handle\n", s->client_get); if (s->client_get != NULL) curl_easy_pause (s->client_get, CURLPAUSE_CONT); - } + /** -* Callback method used with libcurl -* Method is called when libcurl needs to write data during sending -* @param stream pointer where to write data -* @param size size of an individual element -* @param nmemb count of elements that can be written to the buffer -* @param cls destination pointer, passed to the libcurl handle -* @return bytes read from stream -*/ + * Callback method used with libcurl + * Method is called when libcurl needs to write data during sending + * + * @param stream pointer where to write data + * @param size size of an individual element + * @param nmemb count of elements that can be written to the buffer + * @param cls destination pointer, passed to the libcurl handle + * @return bytes read from stream + */ static size_t client_receive (void *stream, size_t size, size_t nmemb, void *cls) { struct Session *s = cls; struct GNUNET_TIME_Absolute now; size_t len = size * nmemb; - - -#if VERBOSE_CLIENT struct Plugin *plugin = s->plugin; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: Received %Zu bytes from peer `%s'\n", len, GNUNET_i2s (&s->target)); -#endif - now = GNUNET_TIME_absolute_get (); if (now.abs_value < s->next_receive.abs_value) { struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference (now, s->next_receive); -#if DEBUG_CLIENT GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Client: %X No inbound bandwidth available! Next read was delayed for %llu ms\n", + "Client: %p No inbound bandwidth available! Next read was delayed for %llu ms\n", s->client_get, delta.rel_value); -#endif if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); @@ -399,19 +425,17 @@ client_receive (void *stream, size_t size, size_t nmemb, void *cls) GNUNET_SCHEDULER_add_delayed (delta, &client_wake_up, s); return CURLPAUSE_ALL; } - - - if (s->msg_tk == NULL) + if (NULL == s->msg_tk) s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb, s); - GNUNET_SERVER_mst_receive (s->msg_tk, s, stream, len, GNUNET_NO, GNUNET_NO); - return len; } + /** * Callback method used with libcurl * Method is called when libcurl needs to read data during sending + * * @param stream pointer where to write data * @param size size of an individual element * @param nmemb count of elements that can be written to the buffer @@ -422,69 +446,45 @@ static size_t client_send_cb (void *stream, size_t size, size_t nmemb, void *cls) { struct Session *s = cls; - -#if VERBOSE_CLIENT struct Plugin *plugin = s->plugin; -#endif - size_t bytes_sent = 0; - size_t len; - struct HTTP_Message *msg = s->msg_head; + size_t len; - if (msg == NULL) + if (GNUNET_YES != exist_session(plugin, s)) + { + GNUNET_break (0); + return 0; + } + if (NULL == msg) { -#if VERBOSE_CLIENT GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Client: %X Nothing to send! Suspending PUT handle!\n", + "Client: %p Nothing to send! Suspending PUT handle!\n", s->client_put); -#endif s->client_put_paused = GNUNET_YES; return CURL_READFUNC_PAUSE; } - - GNUNET_assert (msg != NULL); /* data to send */ - if (msg->pos < msg->size) - { - /* data fit in buffer */ - if ((msg->size - msg->pos) <= (size * nmemb)) - { - len = (msg->size - msg->pos); - memcpy (stream, &msg->buf[msg->pos], len); - msg->pos += len; - bytes_sent = len; - } - else - { - len = size * nmemb; - memcpy (stream, &msg->buf[msg->pos], len); - msg->pos += len; - bytes_sent = len; - } - } - /* no data to send */ - else - { - GNUNET_assert (0); - bytes_sent = 0; - } - + GNUNET_assert (msg->pos < msg->size); + /* calculate how much fits in buffer */ + len = GNUNET_MIN (msg->size - msg->pos, + size * nmemb); + memcpy (stream, &msg->buf[msg->pos], len); + msg->pos += len; if (msg->pos == msg->size) { -#if VERBOSE_CLIENT GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Client: %X Message with %u bytes sent, removing message from queue\n", + "Client: %p Message with %u bytes sent, removing message from queue\n", s->client_put, msg->size, msg->pos); -#endif /* Calling transmit continuation */ + GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); if (NULL != msg->transmit_cont) msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); - GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); GNUNET_free (msg); } - return bytes_sent; + return len; } + int client_connect (struct Session *s) { @@ -493,15 +493,10 @@ client_connect (struct Session *s) char *url; CURLMcode mret; -#if VERBOSE_CLIENT -#endif GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Initiating outbound session peer `%s'\n", GNUNET_i2s (&s->target)); - - s->inbound = GNUNET_NO; - plugin->last_tag++; /* create url */ GNUNET_asprintf (&url, "%s%s;%u", @@ -595,6 +590,12 @@ client_connect (struct Session *s) /* Perform connect */ plugin->cur_connections += 2; + plugin->outbound_sessions ++; + GNUNET_STATISTICS_set (plugin->env->stats, + "# HTTP outbound sessions", + plugin->outbound_sessions, + GNUNET_NO); + /* Re-schedule since handles have changed */ if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) { @@ -606,10 +607,12 @@ client_connect (struct Session *s) return res; } + int client_start (struct Plugin *plugin) { int res = GNUNET_OK; + p = plugin; curl_global_init (CURL_GLOBAL_ALL); plugin->client_mh = curl_multi_init (); @@ -619,15 +622,17 @@ client_start (struct Plugin *plugin) GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _ ("Could not initialize curl multi handle, failed to start %s plugin!\n"), - plugin->name); + plugin->name); res = GNUNET_SYSERR; } return res; } + void client_stop (struct Plugin *plugin) { + p = NULL; if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->client_perform_task); diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c index 8ec5a5e..4b4f504 100644 --- a/src/transport/plugin_transport_http_server.c +++ b/src/transport/plugin_transport_http_server.c @@ -30,17 +30,7 @@ #define _RECEIVE 0 #define _SEND 1 -struct ServerConnection -{ - /* _RECV or _SEND */ - int direction; - - /* should this connection get disconnected? GNUNET_YES/NO */ - int disconnect; - - struct Session *session; - struct MHD_Connection *mhd_conn; -}; +static struct Plugin * p; /** * Function that queries MHD's select sets and @@ -95,12 +85,13 @@ static char * server_load_file (const char *file) { struct GNUNET_DISK_FileHandle *gn_file; - struct stat fstat; + uint64_t fsize; char *text = NULL; - if (0 != STAT (file, &fstat)) + if (GNUNET_OK != GNUNET_DISK_file_size (file, + &fsize, GNUNET_NO, GNUNET_YES)) return NULL; - text = GNUNET_malloc (fstat.st_size + 1); + text = GNUNET_malloc (fsize + 1); gn_file = GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_USER_READ); @@ -109,13 +100,13 @@ server_load_file (const char *file) GNUNET_free (text); return NULL; } - if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fstat.st_size)) + if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fsize)) { GNUNET_free (text); GNUNET_DISK_file_close (gn_file); return NULL; } - text[fstat.st_size] = '\0'; + text[fsize] = '\0'; GNUNET_DISK_file_close (gn_file); return text; } @@ -172,10 +163,8 @@ server_load_certificate (struct Plugin *plugin) GNUNET_free_non_null (plugin->cert); plugin->cert = NULL; -#if VERBOSE_SERVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No usable TLS certificate found, creating certificate\n"); -#endif errno = 0; cert_creation = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, @@ -200,7 +189,7 @@ server_load_certificate (struct Plugin *plugin) return GNUNET_SYSERR; } GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation)); - GNUNET_OS_process_close (cert_creation); + GNUNET_OS_process_destroy (cert_creation); plugin->key = server_load_file (key_file); plugin->cert = server_load_file (cert_file); @@ -226,10 +215,7 @@ server_load_certificate (struct Plugin *plugin) } GNUNET_free (key_file); GNUNET_free (cert_file); -#if DEBUG_HTTP GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n"); -#endif - return res; } #endif @@ -242,12 +228,17 @@ server_load_certificate (struct Plugin *plugin) * @param now GNUNET_YES to schedule execution immediately, GNUNET_NO to wait * until timeout */ - static void server_reschedule (struct Plugin *plugin, struct MHD_Daemon *server, int now) { if ((server == plugin->server_v4) && (plugin->server_v4 != NULL)) { + if (GNUNET_YES == plugin->server_v4_immediately) + return; /* No rescheduling, server will run asap */ + + if (GNUNET_YES == now) + plugin->server_v4_immediately = GNUNET_YES; + if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->server_v4_task); @@ -258,6 +249,12 @@ server_reschedule (struct Plugin *plugin, struct MHD_Daemon *server, int now) if ((server == plugin->server_v6) && (plugin->server_v6 != NULL)) { + if (GNUNET_YES == plugin->server_v6_immediately) + return; /* No rescheduling, server will run asap */ + + if (GNUNET_YES == now) + plugin->server_v6_immediately = GNUNET_YES; + if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->server_v6_task); @@ -273,11 +270,16 @@ server_reschedule (struct Plugin *plugin, struct MHD_Daemon *server, int now) * @param client clien * @param message the message to be forwarded to transport service */ -static void +static int server_receive_mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message) { struct Session *s = cls; + + GNUNET_assert (NULL != p); + if (GNUNET_NO == exist_session(p, s)) + return GNUNET_OK; + struct Plugin *plugin = s->plugin; struct GNUNET_TIME_Relative delay; @@ -294,8 +296,10 @@ server_receive_mst_cb (void *cls, void *client, http_plugin_address_to_string (NULL, s->addr, s->addrlen), delay); } + return GNUNET_OK; } + /** * Callback called by MHD when it needs data to send * @param cls current session @@ -308,47 +312,54 @@ static ssize_t server_send_callback (void *cls, uint64_t pos, char *buf, size_t max) { struct Session *s = cls; - + ssize_t bytes_read = 0; struct HTTP_Message *msg; - int bytes_read = 0; - //static int c = 0; + GNUNET_assert (NULL != p); + if (GNUNET_NO == exist_session(p, s)) + return 0; msg = s->msg_head; - if (msg != NULL) + if (NULL != msg) { /* sending */ - if ((msg->size - msg->pos) <= max) - { - memcpy (buf, &msg->buf[msg->pos], (msg->size - msg->pos)); - bytes_read = msg->size - msg->pos; - msg->pos += (msg->size - msg->pos); - } - else - { - memcpy (buf, &msg->buf[msg->pos], max); - msg->pos += max; - bytes_read = max; - } + bytes_read = GNUNET_MIN (msg->size - msg->pos, + max); + memcpy (buf, &msg->buf[msg->pos], bytes_read); + msg->pos += bytes_read; /* removing message */ if (msg->pos == msg->size) { + GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); if (NULL != msg->transmit_cont) msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); - GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); GNUNET_free (msg); } } + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, + "Server: %p: sent %u bytes\n", s, bytes_read); + return bytes_read; +} - struct Plugin *plugin = s->plugin; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Server: %X: sent %u bytes\n", s, bytes_read); - return bytes_read; +static struct Session * +server_lookup_session (struct Plugin *plugin, + struct ServerConnection * sc) +{ + struct Session *s; + + for (s = plugin->head; NULL != s; s = s->next) + if ((s->server_recv == sc) || (s->server_send == sc)) + return s; + for (s = plugin->server_semi_head; NULL != s; s = s->next) + if ((s->server_recv == sc) || (s->server_send == sc)) + return s; + return NULL; } + static struct ServerConnection * -server_lookup_session (struct Plugin *plugin, +server_lookup_serverconnection (struct Plugin *plugin, struct MHD_Connection *mhd_connection, const char *url, const char *method) { @@ -368,12 +379,11 @@ server_lookup_session (struct Plugin *plugin, uint32_t tag = 0; int direction = GNUNET_SYSERR; - conn_info = - MHD_get_connection_info (mhd_connection, + conn_info = MHD_get_connection_info (mhd_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS); if ((conn_info->client_addr->sa_family != AF_INET) && (conn_info->client_addr->sa_family != AF_INET6)) - return MHD_NO; + return NULL; if ((strlen (&url[1]) >= 105) && (url[104] == ';')) { @@ -408,12 +418,12 @@ server_lookup_session (struct Plugin *plugin, plugin->cur_connections++; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Server: New inbound connection from %s with tag %u\n", + "Server: New %s connection from %s with tag %u\n", + method, GNUNET_i2s (&target), tag); - /* find duplicate session */ + /* find duplicate session */ t = plugin->head; - while (t != NULL) { if ((t->inbound) && @@ -469,6 +479,12 @@ server_lookup_session (struct Plugin *plugin, "Server: Found matching semi-session, merging session for peer `%s'\n", GNUNET_i2s (&target)); + plugin->inbound_sessions ++; + GNUNET_STATISTICS_set (plugin->env->stats, + "# HTTP inbound sessions", + plugin->inbound_sessions, + GNUNET_NO); + GNUNET_assert (NULL != s); goto found; } if ((direction == _RECEIVE) && (t->server_recv != NULL)) @@ -487,6 +503,12 @@ server_lookup_session (struct Plugin *plugin, GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Found matching semi-session, merging session for peer `%s'\n", GNUNET_i2s (&target)); + plugin->inbound_sessions ++; + GNUNET_STATISTICS_set (plugin->env->stats, + "# HTTP inbound sessions", + plugin->inbound_sessions, + GNUNET_NO); + GNUNET_assert (NULL != s); goto found; } @@ -517,16 +539,15 @@ create: GNUNET_break (0); goto error; } - s = create_session (plugin, &target, a, a_len, NULL, NULL); + s = create_session (plugin, &target, a, a_len); + GNUNET_assert (NULL != s); s->ats_address_network_type = ats.value; - s->inbound = GNUNET_YES; - s->next_receive = GNUNET_TIME_absolute_get_zero (); + s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS; s->tag = tag; - if (0 == strcmp (MHD_HTTP_METHOD_PUT, method)) - s->server_recv = s; - if (0 == strcmp (MHD_HTTP_METHOD_GET, method)) - s->server_send = s; + s->server_recv = NULL; + s->server_send = NULL; + GNUNET_CONTAINER_DLL_insert (plugin->server_semi_head, plugin->server_semi_tail, s); goto found; @@ -550,7 +571,7 @@ found: int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Server: Setting timeout for %X to %u sec.\n", sc, to); + "Server: Setting timeout for %p to %u sec.\n", sc, to); MHD_set_connection_option (mhd_connection, MHD_CONNECTION_OPTION_TIMEOUT, to); struct MHD_Daemon *d = NULL; @@ -578,19 +599,17 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection, const char *upload_data, size_t * upload_data_size, void **httpSessionCache) { - struct Plugin *plugin = cls; struct ServerConnection *sc = *httpSessionCache; - struct Session *s = NULL; - - int res = MHD_YES; + struct Session *s; struct MHD_Response *response; + int res = MHD_YES; GNUNET_assert (cls != NULL); - /* new connection */ if (sc == NULL) { - sc = server_lookup_session (plugin, mhd_connection, url, method); + /* new connection */ + sc = server_lookup_serverconnection (plugin, mhd_connection, url, method); if (sc != NULL) (*httpSessionCache) = sc; else @@ -603,11 +622,22 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection, return res; } } + else + { + /* 'old' connection */ + if (NULL == server_lookup_session (plugin, sc)) + { + /* Session was already disconnected */ + return MHD_NO; + } + } /* existing connection */ sc = (*httpSessionCache); s = sc->session; + GNUNET_assert (NULL != s); + /* connection is to be disconnected */ if (sc->disconnect == GNUNET_YES) { @@ -663,7 +693,7 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection, if ((s->next_receive.abs_value <= now.abs_value)) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Server: %X: PUT with %u bytes forwarded to MST\n", s, + "Server: %p: PUT with %u bytes forwarded to MST\n", s, *upload_data_size); if (s->msg_tk == NULL) { @@ -683,7 +713,7 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection, { t = s->server_recv; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Server: Setting timeout for %X to %u sec.\n", t, + "Server: Setting timeout for %p to %u sec.\n", t, to); MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, to); @@ -692,7 +722,7 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection, { t = s->server_send; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Server: Setting timeout for %X to %u sec.\n", t, + "Server: Setting timeout for %p to %u sec.\n", t, to); MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, to); @@ -710,7 +740,7 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection, else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Server: %X no inbound bandwidth available! Next read was delayed by %llu ms\n", + "Server: %p no inbound bandwidth available! Next read was delayed by %llu ms\n", s, now.abs_value - s->next_receive.abs_value); } return MHD_YES; @@ -734,24 +764,28 @@ server_disconnect_cb (void *cls, struct MHD_Connection *connection, if (sc == NULL) return; - s = sc->session; + if (NULL == (s = server_lookup_session (p, sc))) + return; + + GNUNET_assert (NULL != p); + if (GNUNET_NO == exist_session(p, s)) + return; + plugin = s->plugin; if (sc->direction == _SEND) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Server: %X peer `%s' GET on address `%s' disconnected\n", + "Server: %p peer `%s' GET on address `%s' disconnected\n", s->server_send, GNUNET_i2s (&s->target), http_plugin_address_to_string (NULL, s->addr, s->addrlen)); - s->server_send = NULL; - - if (s->server_recv != NULL) + if (NULL != (tc = s->server_recv)) { - tc = s->server_recv; tc->disconnect = GNUNET_YES; + GNUNET_assert (NULL != tc->mhd_conn); #if MHD_VERSION >= 0x00090E00 - MHD_set_connection_option (sc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, + MHD_set_connection_option (tc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, 1); #endif } @@ -759,16 +793,16 @@ server_disconnect_cb (void *cls, struct MHD_Connection *connection, if (sc->direction == _RECEIVE) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, - "Server: %X peer `%s' PUT on address `%s' disconnected\n", + "Server: %p peer `%s' PUT on address `%s' disconnected\n", s->server_recv, GNUNET_i2s (&s->target), http_plugin_address_to_string (NULL, s->addr, s->addrlen)); s->server_recv = NULL; - if (s->server_send != NULL) + if (NULL != (tc = s->server_send)) { - tc = s->server_send; tc->disconnect = GNUNET_YES; + GNUNET_assert (NULL != tc->mhd_conn); #if MHD_VERSION >= 0x00090E00 - MHD_set_connection_option (sc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, + MHD_set_connection_option (tc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, 1); #endif } @@ -778,6 +812,7 @@ server_disconnect_cb (void *cls, struct MHD_Connection *connection, s->msg_tk = NULL; } } + GNUNET_free (sc); t = plugin->server_semi_head; @@ -814,6 +849,12 @@ server_disconnect_cb (void *cls, struct MHD_Connection *connection, s->msg_tk = NULL; } + GNUNET_assert (plugin->inbound_sessions > 0); + plugin->inbound_sessions --; + GNUNET_STATISTICS_set (plugin->env->stats, + "# HTTP inbound sessions", + plugin->inbound_sessions, GNUNET_NO); + notify_session_end (s->plugin, &s->target, s); } } @@ -821,31 +862,22 @@ server_disconnect_cb (void *cls, struct MHD_Connection *connection, int server_disconnect (struct Session *s) { - struct Plugin *plugin = s->plugin; - struct Session *t = plugin->head; - - while (t != NULL) + if (s->server_send != NULL) { - if (t->inbound == GNUNET_YES) - { - if (t->server_send != NULL) - { - ((struct ServerConnection *) t->server_send)->disconnect = GNUNET_YES; - } - if (t->server_send != NULL) - { - ((struct ServerConnection *) t->server_send)->disconnect = GNUNET_YES; - } - } - t = t->next; + ((struct ServerConnection *) s->server_send)->disconnect = GNUNET_YES; } + if (s->server_recv != NULL) + { + ((struct ServerConnection *) s->server_recv)->disconnect = GNUNET_YES; + } + return GNUNET_OK; } int server_send (struct Session *s, struct HTTP_Message *msg) { - GNUNET_CONTAINER_DLL_insert (s->msg_head, s->msg_tail, msg); + GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); if (s->addrlen == sizeof (struct IPv4HttpAddress)) { @@ -876,17 +908,15 @@ server_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_assert (cls != NULL); plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; - +#if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Running IPv4 server\n"); - +#endif + plugin->server_v4_immediately = GNUNET_NO; GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4)); - if (plugin->server_v4 != NULL) - plugin->server_v4_task = - server_schedule (plugin, plugin->server_v4, GNUNET_NO); + server_reschedule (plugin, plugin->server_v4, GNUNET_NO); } @@ -902,19 +932,16 @@ server_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) struct Plugin *plugin = cls; GNUNET_assert (cls != NULL); - plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; - +#if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Running IPv6 server\n"); - +#endif + plugin->server_v6_immediately = GNUNET_NO; GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6)); - if (plugin->server_v6 != NULL) - plugin->server_v6_task = - server_schedule (plugin, plugin->server_v6, GNUNET_NO); + server_reschedule (plugin, plugin->server_v6, GNUNET_NO); } /** @@ -936,7 +963,7 @@ server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle, struct GNUNET_NETWORK_FDSet *wws; struct GNUNET_NETWORK_FDSet *wes; int max; - unsigned long long timeout; + unsigned MHD_LONG_LONG timeout; static unsigned long long last_timeout = 0; int haveto; @@ -981,13 +1008,13 @@ server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle, GNUNET_SCHEDULER_cancel (plugin->server_v4_task); plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; } -#if VERBOSE_SERVER +#if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Scheduling IPv4 server task in %llu ms\n", tv); #endif ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws, + tv, wrs, wws, &server_v4_run, plugin); } if (daemon_handle == plugin->server_v6) @@ -997,13 +1024,13 @@ server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle, GNUNET_SCHEDULER_cancel (plugin->server_v6_task); plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; } -#if VERBOSE_SERVER +#if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Scheduling IPv6 server task in %llu ms\n", tv); #endif ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws, + tv, wrs, wws, &server_v6_run, plugin); } GNUNET_NETWORK_fdset_destroy (wrs); @@ -1017,6 +1044,8 @@ server_start (struct Plugin *plugin) { int res = GNUNET_OK; unsigned int timeout; + p = plugin; + GNUNET_assert (NULL != plugin); #if BUILD_HTTPS res = server_load_certificate (plugin); @@ -1133,13 +1162,9 @@ server_start (struct Plugin *plugin) return GNUNET_SYSERR; } server_reschedule (plugin, plugin->server_v6, GNUNET_NO); - - -#if DEBUG_HTTP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "%s server component started on port %u\n", plugin->name, plugin->port); -#endif return res; } @@ -1206,16 +1231,16 @@ server_stop (struct Plugin *plugin) s = t; } + p = NULL; + #if BUILD_HTTPS GNUNET_free_non_null (plugin->crypto_init); GNUNET_free_non_null (plugin->cert); GNUNET_free_non_null (plugin->key); #endif -#if DEBUG_HTTP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "%s server component stopped\n", plugin->name); -#endif } diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index 2b2d728..af5c715 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) + (C) 2002--2012 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 @@ -39,9 +39,14 @@ #include "gnunet_transport_plugin.h" #include "transport.h" -#define DEBUG_TCP GNUNET_EXTRA_LOGGING +#define LOG(kind,...) GNUNET_log_from (kind, "transport-tcp",__VA_ARGS__) + +/** + * How long until we give up on establishing an NAT connection? + * Must be > 4 RTT + */ +#define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) -#define DEBUG_TCP_NAT GNUNET_EXTRA_LOGGING GNUNET_NETWORK_STRUCT_BEGIN @@ -225,11 +230,6 @@ struct Session struct SessionHeader header; /** - * Stored in a linked list. - */ - struct Session *next; - - /** * Pointer to the global plugin struct. */ struct Plugin *plugin; @@ -240,6 +240,11 @@ struct Session struct GNUNET_SERVER_Client *client; /** + * Task cleaning up a NAT client connection establishment attempt; + */ + GNUNET_SCHEDULER_TaskIdentifier nat_connection_timeout; + + /** * Messages currently pending for transmission * to this peer, if any. */ @@ -254,7 +259,7 @@ struct Session /** * Handle for pending transmission request. */ - struct GNUNET_CONNECTION_TransmitHandle *transmit_handle; + struct GNUNET_SERVER_TransmitHandle *transmit_handle; /** * To whom are we talking to (set to our identity @@ -268,6 +273,11 @@ struct Session GNUNET_SCHEDULER_TaskIdentifier receive_delay_task; /** + * Session timeout task + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** * Address of the other peer (either based on our 'connect' * call or on our 'accept' call). * @@ -329,7 +339,10 @@ struct Plugin */ struct GNUNET_NAT_Handle *nat; - struct GNUNET_CONTAINER_MultiHashMap * sessionmap; + /** + * Map from peer identities to sessions for the given peer. + */ + struct GNUNET_CONTAINER_MultiHashMap *sessionmap; /** * Handle to the network service. @@ -392,6 +405,71 @@ struct Plugin /** + * Start session timeout + */ +static void +start_session_timeout (struct Session *s); + + +/** + * Increment session timeout due to activity + */ +static void +reschedule_session_timeout (struct Session *s); + + +/** + * Cancel timeout + */ +static void +stop_session_timeout (struct Session *s); + + +/* DEBUG CODE */ +static const char * +tcp_address_to_string (void *cls, const void *addr, size_t addrlen); + + +static unsigned int sessions; + + +static void +inc_sessions (struct Plugin *plugin, struct Session *session, int line) +{ + sessions++; + unsigned int size = GNUNET_CONTAINER_multihashmap_size(plugin->sessionmap); + if (sessions != size) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Inconsistent sessions %u <-> session map size: %u\n", + sessions, size); + LOG (GNUNET_ERROR_TYPE_DEBUG, "%4i Session increased to %u (session map size: %u): `%s' `%s'\n", + line, + sessions, + size, + GNUNET_i2s (&session->target), + tcp_address_to_string (NULL, session->addr, session->addrlen)); +} + + +static void +dec_sessions (struct Plugin *plugin, struct Session *session, int line) +{ + GNUNET_assert (sessions > 0); + unsigned int size = GNUNET_CONTAINER_multihashmap_size(plugin->sessionmap); + sessions--; + if (sessions != size) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Inconsistent sessions %u <-> session map size: %u\n", + sessions, size); + LOG (GNUNET_ERROR_TYPE_DEBUG, "%4i Session decreased to %u (session map size: %u): `%s' `%s'\n", + line, + sessions, + size, + GNUNET_i2s (&session->target), + tcp_address_to_string (NULL, session->addr, session->addrlen)); +} +/* DEBUG CODE */ + + +/** * Function to check if an inbound connection is acceptable. * Mostly used to limit the total number of open connections * we can have. @@ -410,6 +488,8 @@ plugin_tcp_access_check (void *cls, { struct Plugin *plugin = cls; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Accepting new incoming TCP connection\n"); if (0 == plugin->max_connections) return GNUNET_NO; plugin->max_connections--; @@ -436,9 +516,9 @@ tcp_nat_port_map_callback (void *cls, int add_remove, void *arg; size_t args; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "NPMC called with %d for address `%s'\n", add_remove, - GNUNET_a2s (addr, addrlen)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "NPMC called with %d for address `%s'\n", add_remove, + GNUNET_a2s (addr, addrlen)); /* convert 'addr' to our internal format */ switch (addr->sa_family) { @@ -490,27 +570,26 @@ tcp_address_to_string (void *cls, const void *addr, size_t addrlen) int af; uint16_t port; - if (addrlen == sizeof (struct IPv6TcpAddress)) + switch (addrlen) { + case sizeof (struct IPv6TcpAddress): t6 = addr; af = AF_INET6; port = ntohs (t6->t6_port); memcpy (&a6, &t6->ipv6_addr, sizeof (a6)); sb = &a6; - } - else if (addrlen == sizeof (struct IPv4TcpAddress)) - { + break; + case sizeof (struct IPv4TcpAddress): t4 = addr; af = AF_INET; port = ntohs (t4->t4_port); memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); sb = &a4; - } - else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", - _("Unexpected address length: %u bytes\n"), - (unsigned int) addrlen); + break; + default: + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Unexpected address length: %u bytes\n"), + (unsigned int) addrlen); GNUNET_break (0); return NULL; } @@ -525,15 +604,88 @@ tcp_address_to_string (void *cls, const void *addr, size_t addrlen) } +/** + * Function called to convert a string address to + * a binary address. + * + * @param cls closure ('struct Plugin*') + * @param addr string address + * @param addrlen length of the address + * @param buf location to store the buffer + * @param added location to store the number of bytes in the buffer. + * If the function returns GNUNET_SYSERR, its contents are undefined. + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +static int +tcp_string_to_address (void *cls, const char *addr, uint16_t addrlen, + void **buf, size_t *added) +{ + struct sockaddr_storage socket_address; + + if ((NULL == addr) || (addrlen == 0)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if ('\0' != addr[addrlen - 1]) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (strlen (addr) != addrlen - 1) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_STRINGS_to_address_ip (addr, strlen (addr), + &socket_address)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + switch (socket_address.ss_family) + { + case AF_INET: + { + struct IPv4TcpAddress *t4; + struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address; + + t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); + t4->ipv4_addr = in4->sin_addr.s_addr; + t4->t4_port = in4->sin_port; + *buf = t4; + *added = sizeof (struct IPv4TcpAddress); + return GNUNET_OK; + } + case AF_INET6: + { + struct IPv6TcpAddress *t6; + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address; + t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); + t6->ipv6_addr = in6->sin6_addr; + t6->t6_port = in6->sin6_port; + *buf = t6; + *added = sizeof (struct IPv6TcpAddress); + return GNUNET_OK; + } + default: + return GNUNET_SYSERR; + } +} + + struct SessionClientCtx { const struct GNUNET_SERVER_Client *client; struct Session *ret; }; -int session_lookup_by_client_it (void *cls, - const GNUNET_HashCode * key, - void *value) + +static int +session_lookup_by_client_it (void *cls, + const GNUNET_HashCode * key, + void *value) { struct SessionClientCtx *sc_ctx = cls; struct Session *s = value; @@ -546,6 +698,7 @@ int session_lookup_by_client_it (void *cls, return GNUNET_YES; } + /** * Find the session handle for the given client. * @@ -555,14 +708,13 @@ int session_lookup_by_client_it (void *cls, */ static struct Session * lookup_session_by_client (struct Plugin *plugin, - const struct GNUNET_SERVER_Client *client) + const struct GNUNET_SERVER_Client *client) { struct SessionClientCtx sc_ctx; + sc_ctx.client = client; sc_ctx.ret = NULL; - GNUNET_CONTAINER_multihashmap_iterate (plugin->sessionmap, &session_lookup_by_client_it, &sc_ctx); - return sc_ctx.ret; } @@ -572,7 +724,7 @@ lookup_session_by_client (struct Plugin *plugin, * * @param plugin the plugin * @param target peer to connect to - * @param client client to use + * @param client client to use, reference counter must have already been increased * @param is_nat this a NAT session, we should wait for a client to * connect to us from an address, then assign that to * the session @@ -586,15 +738,14 @@ create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, struct PendingMessage *pm; struct WelcomeMessage welcome; - if (is_nat != GNUNET_YES) - GNUNET_assert (client != NULL); + if (GNUNET_YES != is_nat) + GNUNET_assert (NULL != client); else - GNUNET_assert (client == NULL); - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Creating new session for peer `%4s'\n", - GNUNET_i2s (target)); + GNUNET_assert (NULL == client); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Creating new session for peer `%4s'\n", + GNUNET_i2s (target)); ret = GNUNET_malloc (sizeof (struct Session)); ret->last_activity = GNUNET_TIME_absolute_get (); ret->plugin = plugin; @@ -617,10 +768,14 @@ create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, pm->message_size, GNUNET_NO); GNUNET_CONTAINER_DLL_insert (ret->pending_messages_head, ret->pending_messages_tail, pm); - if (is_nat != GNUNET_YES) + if (GNUNET_YES != is_nat) + { GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# TCP sessions active"), 1, GNUNET_NO); + } + start_session_timeout (ret); + return ret; } @@ -659,16 +814,14 @@ do_transmit (void *cls, size_t size, void *buf) char *cbuf; size_t ret; - GNUNET_assert (session != NULL); + GNUNET_assert (NULL != session); session->transmit_handle = NULL; plugin = session->plugin; - if (buf == NULL) + if (NULL == buf) { -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Timeout trying to transmit to peer `%4s', discarding message queue.\n", - GNUNET_i2s (&session->target)); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Timeout trying to transmit to peer `%4s', discarding message queue.\n", + GNUNET_i2s (&session->target)); /* timeout; cancel all messages that have already expired */ hd = NULL; tl = NULL; @@ -679,11 +832,9 @@ do_transmit (void *cls, size_t size, void *buf) { GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, session->pending_messages_tail, pos); -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Failed to transmit %u byte message to `%4s'.\n", - pos->message_size, GNUNET_i2s (&session->target)); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to transmit %u byte message to `%4s'.\n", + pos->message_size, GNUNET_i2s (&session->target)); ret += pos->message_size; GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos); } @@ -722,9 +873,9 @@ do_transmit (void *cls, size_t size, void *buf) GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, session->pending_messages_tail, pos); GNUNET_assert (size >= pos->message_size); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Transmitting message of type %u\n", - ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting message of type %u\n", + ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type)); /* FIXME: this memcpy can be up to 7% of our total runtime */ memcpy (cbuf, pos->msg, pos->message_size); cbuf += pos->message_size; @@ -749,10 +900,8 @@ do_transmit (void *cls, size_t size, void *buf) } GNUNET_assert (hd == NULL); GNUNET_assert (tl == NULL); -#if DEBUG_TCP > 1 - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Transmitting %u bytes\n", + LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u bytes\n", ret); -#endif GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret, GNUNET_NO); @@ -801,31 +950,44 @@ disconnect_session (struct Session *session) struct PendingMessage *pm; struct Plugin * plugin = session->plugin; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Disconnecting session %p for peer `%s' address `%s'\n", - session, - GNUNET_i2s (&session->target), - tcp_address_to_string(NULL, session->addr, session->addrlen)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Disconnecting session of peer `%s' address `%s'\n", + GNUNET_i2s (&session->target), + tcp_address_to_string (NULL, session->addr, session->addrlen)); - GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(plugin->sessionmap, &session->target.hashPubKey, session)); + stop_session_timeout (session); + + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (plugin->sessionmap, &session->target.hashPubKey, session)) + { + GNUNET_STATISTICS_update (session->plugin->env->stats, + gettext_noop ("# TCP sessions active"), -1, + GNUNET_NO); + dec_sessions (plugin, session, __LINE__); + } + else GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (plugin->nat_wait_conns, &session->target.hashPubKey, session)); /* clean up state */ if (session->transmit_handle != NULL) { - GNUNET_CONNECTION_notify_transmit_ready_cancel (session->transmit_handle); + GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle); session->transmit_handle = NULL; } session->plugin->env->session_end (session->plugin->env->cls, &session->target, session); + + if (GNUNET_SCHEDULER_NO_TASK != session->nat_connection_timeout) + { + GNUNET_SCHEDULER_cancel (session->nat_connection_timeout); + session->nat_connection_timeout = GNUNET_SCHEDULER_NO_TASK; + } + while (NULL != (pm = session->pending_messages_head)) { -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - pm->transmit_cont != - NULL ? "Could not deliver message to `%4s'.\n" : - "Could not deliver message to `%4s', notifying.\n", - GNUNET_i2s (&session->target)); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + pm->transmit_cont != + NULL ? "Could not deliver message to `%4s'.\n" : + "Could not deliver message to `%4s', notifying.\n", + GNUNET_i2s (&session->target)); GNUNET_STATISTICS_update (session->plugin->env->stats, gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) pm->message_size, GNUNET_NO); @@ -840,21 +1002,18 @@ disconnect_session (struct Session *session) GNUNET_SYSERR); GNUNET_free (pm); } - GNUNET_break (session->client != NULL); if (session->receive_delay_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (session->receive_delay_task); - if (session->client != NULL) + if (NULL != session->client) GNUNET_SERVER_receive_done (session->client, GNUNET_SYSERR); } - if (session->client != NULL) + if (NULL != session->client) { + GNUNET_SERVER_client_disconnect (session->client); GNUNET_SERVER_client_drop (session->client); session->client = NULL; } - GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# TCP sessions active"), -1, - GNUNET_NO); GNUNET_free_non_null (session->addr); GNUNET_assert (NULL == session->transmit_handle); GNUNET_free (session); @@ -899,15 +1058,9 @@ tcp_plugin_send (void *cls, struct Plugin * plugin = cls; struct PendingMessage *pm; - GNUNET_assert (plugin != NULL); - GNUNET_assert (session != NULL); - GNUNET_assert (session->client != NULL); + GNUNET_assert (NULL != plugin); + GNUNET_assert (NULL != session); - GNUNET_SERVER_client_set_timeout (session->client, - GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), - msgbuf_size, GNUNET_NO); /* create new message entry */ pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size); pm->msg = (const char *) &pm[1]; @@ -917,40 +1070,79 @@ tcp_plugin_send (void *cls, pm->transmit_cont = cont; pm->transmit_cont_cls = cont_cls; - /* append pm to pending_messages list */ - GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, - session->pending_messages_tail, pm); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Asked to transmit %u bytes to `%s', added message to list.\n", + msgbuf_size, GNUNET_i2s (&session->target)); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Asked to transmit %u bytes to `%s', added message to list.\n", - msgbuf_size, GNUNET_i2s (&session->target)); + reschedule_session_timeout (session); - process_pending_messages (session); - return msgbuf_size; + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains_value(plugin->sessionmap, &session->target.hashPubKey, session)) + { + GNUNET_assert (session->client != NULL); + + GNUNET_SERVER_client_set_timeout (session->client, + GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# bytes currently in TCP buffers"), + msgbuf_size, GNUNET_NO); + + /* append pm to pending_messages list */ + GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, + session->pending_messages_tail, pm); + + process_pending_messages (session); + return msgbuf_size; + } + else if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains_value(plugin->nat_wait_conns, &session->target.hashPubKey, session)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "This NAT WAIT session for peer `%s' is not yet ready!\n", + GNUNET_i2s (&session->target)); + + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# bytes currently in TCP buffers"), + msgbuf_size, GNUNET_NO); + + /* append pm to pending_messages list */ + GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, + session->pending_messages_tail, pm); + return msgbuf_size; + } + else + { + if (NULL != cont) + cont (cont_cls, &session->target, GNUNET_SYSERR); + GNUNET_break (0); + GNUNET_free (pm); + return GNUNET_SYSERR; /* session does not exist here */ + } } + struct SessionItCtx { - void * addr; + void *addr; size_t addrlen; - struct Session * result; + struct Session *result; }; -int session_lookup_it (void *cls, - const GNUNET_HashCode * key, - void *value) + +static int +session_lookup_it (void *cls, + const GNUNET_HashCode *key, + void *value) { struct SessionItCtx * si_ctx = cls; struct Session * session = value; #if 0 char * a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen)); char * a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen)); - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", - "Comparing: %s %u <-> %s %u\n", - a1, - session->addrlen, - a2, - si_ctx->addrlen); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Comparing: %s %u <-> %s %u\n", + a1, + session->addrlen, + a2, + si_ctx->addrlen); GNUNET_free (a1); GNUNET_free (a2); #endif @@ -965,12 +1157,12 @@ int session_lookup_it (void *cls, #if 0 a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen)); a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen)); - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", - "Comparing: %s %u <-> %s %u , OK!\n", - a1, - session->addrlen, - a2, - si_ctx->addrlen); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Comparing: %s %u <-> %s %u , OK!\n", + a1, + session->addrlen, + a2, + si_ctx->addrlen); GNUNET_free (a1); GNUNET_free (a2); #endif @@ -981,6 +1173,21 @@ int session_lookup_it (void *cls, /** + * Task cleaning up a NAT connection attempt after timeout + */ +static void +nat_connect_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Session *session = cls; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n", + GNUNET_i2s (&session->target), tcp_address_to_string(NULL, session->addr, session->addrlen)); + disconnect_session (session); +} + + +/** * Create a new session to transmit data to the target * This session will used to send data to this peer and the plugin will * notify us by calling the env->session_end function @@ -991,11 +1198,10 @@ int session_lookup_it (void *cls, */ static struct Session * tcp_plugin_get_session (void *cls, - const struct GNUNET_HELLO_Address *address) + const struct GNUNET_HELLO_Address *address) { struct Plugin * plugin = cls; struct Session * session = NULL; - int af; const void *sb; size_t sbs; @@ -1006,20 +1212,19 @@ tcp_plugin_get_session (void *cls, const struct IPv6TcpAddress *t6; struct GNUNET_ATS_Information ats; unsigned int is_natd = GNUNET_NO; - size_t addrlen = 0; + size_t addrlen; GNUNET_assert (plugin != NULL); GNUNET_assert (address != NULL); - addrlen = address->address_length; - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Trying to get session for `%s' address length %i\n", - tcp_address_to_string(NULL, address->address, address->address_length), - addrlen); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Trying to get session for `%s' address of peer `%s'\n", + tcp_address_to_string(NULL, address->address, address->address_length), + GNUNET_i2s (&address->peer)); /* look for existing session */ - if (GNUNET_CONTAINER_multihashmap_contains(plugin->sessionmap, &address->peer.hashPubKey)) + if (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains(plugin->sessionmap, &address->peer.hashPubKey)) { struct SessionItCtx si_ctx; @@ -1032,13 +1237,17 @@ tcp_plugin_get_session (void *cls, if (si_ctx.result != NULL) { session = si_ctx.result; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Found exisiting session for `%s' address `%s' session %p\n", - GNUNET_i2s (&address->peer), - tcp_address_to_string(NULL, address->address, address->address_length), - session); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Found exisiting session for `%s' address `%s' session %p\n", + GNUNET_i2s (&address->peer), + tcp_address_to_string(NULL, address->address, address->address_length), + session); return session; } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Existing sessions did not match address `%s' or peer `%s'\n", + tcp_address_to_string(NULL, address->address, address->address_length), + GNUNET_i2s (&address->peer)); } if (addrlen == sizeof (struct IPv6TcpAddress)) @@ -1077,8 +1286,8 @@ tcp_plugin_get_session (void *cls, } else { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", - _("Address of unexpected length: %u\n"), addrlen); + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Address of unexpected length: %u\n"), addrlen); GNUNET_break (0); return NULL; } @@ -1111,26 +1320,34 @@ tcp_plugin_get_session (void *cls, GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns, &address->peer.hashPubKey))) { -#if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - _("Found valid IPv4 NAT address (creating session)!\n")); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Found valid IPv4 NAT address (creating session)!\n") ; session = create_session (plugin, &address->peer, NULL, GNUNET_YES); session->addrlen = 0; session->addr = NULL; session->ats_address_network_type = ats.value; + session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed(NAT_TIMEOUT, + &nat_connect_timeout, + session); GNUNET_assert (session != NULL); - GNUNET_assert (GNUNET_CONTAINER_multihashmap_put (plugin->nat_wait_conns, &address->peer.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) == GNUNET_OK); -#if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Created NAT WAIT connection to `%4s' at `%s'\n", - GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs)); -#endif - GNUNET_NAT_run_client (plugin->nat, &a4); - return session; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Created NAT WAIT connection to `%4s' at `%s'\n", + GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs)); + + if (GNUNET_OK == GNUNET_NAT_run_client (plugin->nat, &a4)) + return session; + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Running NAT client for `%4s' at `%s' failed\n", + GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs)); + disconnect_session (session); + return NULL; + } } /* create new outbound session */ @@ -1138,18 +1355,16 @@ tcp_plugin_get_session (void *cls, sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs); if (sa == NULL) { -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Failed to create connection to `%4s' at `%s'\n", - GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs)); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to create connection to `%4s' at `%s'\n", + GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs)); return NULL; } plugin->max_connections--; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Asked to transmit to `%4s', creating fresh session using address `%s'.\n", - GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Asked to transmit to `%4s', creating fresh session using address `%s'.\n", + GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs)); session = create_session (plugin, &address->peer, @@ -1161,13 +1376,12 @@ tcp_plugin_get_session (void *cls, session->ats_address_network_type = ats.value; GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &address->peer.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Creating new session for `%s' address `%s' session %p\n", - GNUNET_i2s (&address->peer), - tcp_address_to_string(NULL, address->address, address->address_length), - session); - + inc_sessions (plugin, session, __LINE__); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Creating new session for `%s' address `%s' session %p\n", + GNUNET_i2s (&address->peer), + tcp_address_to_string(NULL, address->address, address->address_length), + session); /* Send TCP Welcome */ process_pending_messages (session); @@ -1175,9 +1389,10 @@ tcp_plugin_get_session (void *cls, } -int session_disconnect_it (void *cls, - const GNUNET_HashCode * key, - void *value) +static int +session_disconnect_it (void *cls, + const GNUNET_HashCode * key, + void *value) { struct Session *session = value; @@ -1189,25 +1404,6 @@ int session_disconnect_it (void *cls, return GNUNET_YES; } -int session_nat_disconnect_it (void *cls, - const GNUNET_HashCode * key, - void *value) -{ - struct Session *session = value; - - if (session != NULL) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Cleaning up pending NAT session for peer `%4s'\n", GNUNET_i2s (&session->target)); - GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (session->plugin->nat_wait_conns, &session->target.hashPubKey, session)); - GNUNET_SERVER_client_drop (session->client); - GNUNET_SERVER_receive_done (session->client, GNUNET_SYSERR); - GNUNET_free (session); - } - - return GNUNET_YES; -} - /** * Function that can be called to force a disconnect from the @@ -1229,23 +1425,11 @@ static void tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { struct Plugin *plugin = cls; - struct Session *nat_session = NULL; - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Disconnecting peer `%4s'\n", GNUNET_i2s (target)); - GNUNET_CONTAINER_multihashmap_get_multiple (plugin->sessionmap, &target->hashPubKey, session_disconnect_it, plugin); - - nat_session = GNUNET_CONTAINER_multihashmap_get(plugin->nat_wait_conns, &target->hashPubKey); - if (nat_session != NULL) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Cleaning up pending NAT session for peer `%4s'\n", GNUNET_i2s (target)); - GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (plugin->nat_wait_conns, &target->hashPubKey, nat_session)); - GNUNET_SERVER_client_drop (nat_session->client); - GNUNET_SERVER_receive_done (nat_session->client, GNUNET_SYSERR); - GNUNET_free (nat_session); - } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Disconnecting peer `%4s'\n", GNUNET_i2s (target)); + GNUNET_CONTAINER_multihashmap_get_multiple (plugin->sessionmap, &target->hashPubKey, &session_disconnect_it, plugin); + GNUNET_CONTAINER_multihashmap_get_multiple (plugin->nat_wait_conns, &target->hashPubKey, &session_disconnect_it, plugin); } @@ -1268,6 +1452,8 @@ struct PrettyPrinterContext * Port to add after the IP address. */ uint16_t port; + + int ipv6; }; @@ -1289,7 +1475,10 @@ append_port (void *cls, const char *hostname) GNUNET_free (ppc); return; } - GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port); + if (GNUNET_YES == ppc->ipv6) + GNUNET_asprintf (&ret, "[%s]:%d", hostname, ppc->port); + else + GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port); ppc->asc (ppc->asc_cls, ret); GNUNET_free (ret); } @@ -1348,6 +1537,12 @@ tcp_plugin_address_pretty_printer (void *cls, const char *type, sb = &a4; sbs = sizeof (a4); } + else if (0 == addrlen) + { + asc (asc_cls, "<inbound connection>"); + asc (asc_cls, NULL); + return; + } else { /* invalid address */ @@ -1356,6 +1551,10 @@ tcp_plugin_address_pretty_printer (void *cls, const char *type, return; } ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); + if (addrlen == sizeof (struct IPv6TcpAddress)) + ppc->ipv6 = GNUNET_YES; + else + ppc->ipv6 = GNUNET_NO; ppc->asc = asc; ppc->asc_cls = asc_cls; ppc->port = port; @@ -1462,7 +1661,7 @@ handle_tcp_nat_probe (void *cls, struct GNUNET_SERVER_Client *client, const struct sockaddr_in *s4; const struct sockaddr_in6 *s6; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "received NAT probe\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "received NAT probe\n"); /* We have received a TCP NAT probe, meaning we (hopefully) initiated * a connection to this peer by running gnunet-nat-client. This peer @@ -1493,36 +1692,39 @@ handle_tcp_nat_probe (void *cls, struct GNUNET_SERVER_Client *client, clientIdentity.hashPubKey); if (session == NULL) { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Did NOT find session for NAT probe!\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Did NOT find session for NAT probe!\n"); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Found session for NAT probe!\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Found session for NAT probe!\n"); + + if (session->nat_connection_timeout != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (session->nat_connection_timeout); + session->nat_connection_timeout = GNUNET_SCHEDULER_NO_TASK; + } - GNUNET_assert (GNUNET_CONTAINER_multihashmap_remove - (plugin->nat_wait_conns, - &tcp_nat_probe->clientIdentity.hashPubKey, - session) == GNUNET_YES); if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) { GNUNET_break (0); - GNUNET_free (session); - GNUNET_SERVER_receive_done (client, GNUNET_OK); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + disconnect_session (session); return; } - - GNUNET_SERVER_client_keep (client); - session->client = client; + GNUNET_assert (GNUNET_CONTAINER_multihashmap_remove + (plugin->nat_wait_conns, + &tcp_nat_probe->clientIdentity.hashPubKey, + session) == GNUNET_YES); + GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, + &session->target.hashPubKey, session, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); session->last_activity = GNUNET_TIME_absolute_get (); session->inbound = GNUNET_NO; - -#if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Found address `%s' for incoming connection\n", - GNUNET_a2s (vaddr, alen)); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Found address `%s' for incoming connection\n", + GNUNET_a2s (vaddr, alen)); switch (((const struct sockaddr *) vaddr)->sa_family) { case AF_INET: @@ -1543,20 +1745,18 @@ handle_tcp_nat_probe (void *cls, struct GNUNET_SERVER_Client *client, break; default: GNUNET_break_op (0); - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Bad address for incoming connection!\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Bad address for incoming connection!\n"); GNUNET_free (vaddr); - - GNUNET_SERVER_client_drop (client); - GNUNET_free (session); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + disconnect_session (session); return; } GNUNET_free (vaddr); - - GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &session->target.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - + GNUNET_break (NULL == session->client); + GNUNET_SERVER_client_keep (client); + session->client = client; + inc_sessions (plugin, session, __LINE__); GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# TCP sessions active"), 1, GNUNET_NO); @@ -1595,23 +1795,21 @@ handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client, GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Received %s message from `%4s'\n", "WELCOME", - GNUNET_i2s (&wm->clientIdentity)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received %s message from `%4s'\n", "WELCOME", + GNUNET_i2s (&wm->clientIdentity)); GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# TCP WELCOME messages received"), 1, GNUNET_NO); - session = lookup_session_by_client (plugin, client); if (session != NULL) { if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Found existing session %p for peer `%s'\n", - session, - GNUNET_a2s (vaddr, alen)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Found existing session %p for peer `%s'\n", + session, + GNUNET_a2s (vaddr, alen)); GNUNET_free (vaddr); } } @@ -1620,7 +1818,6 @@ handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client, GNUNET_SERVER_client_keep (client); session = create_session (plugin, &wm->clientIdentity, client, GNUNET_NO); session->inbound = GNUNET_YES; - if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) { if (alen == sizeof (struct sockaddr_in)) @@ -1650,12 +1847,11 @@ handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client, } else { -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Did not obtain TCP socket address for incoming connection\n"); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Did not obtain TCP socket address for incoming connection\n"); } GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &wm->clientIdentity.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + inc_sessions (plugin, session, __LINE__); } if (session->expecting_welcome != GNUNET_YES) @@ -1695,6 +1891,8 @@ delayed_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) session->plugin->env->receive (session->plugin->env->cls, &session->target, NULL, &ats, 0, session, NULL, 0); + reschedule_session_timeout (session); + if (delay.rel_value == 0) GNUNET_SERVER_receive_done (session->client, GNUNET_OK); else @@ -1732,21 +1930,40 @@ handle_tcp_data (void *cls, struct GNUNET_SERVER_Client *client, if (NULL == session) { /* No inbound session found */ + void *vaddr; + size_t alen; + + GNUNET_SERVER_client_get_address (client, &vaddr, &alen); + LOG (GNUNET_ERROR_TYPE_ERROR, + "Received unexpected %u bytes of type %u from `%s'\n", + (unsigned int) ntohs (message->size), + (unsigned int) ntohs (message->type), + GNUNET_a2s(vaddr, alen)); GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + GNUNET_free_non_null(vaddr); return; } else if (GNUNET_YES == session->expecting_welcome) { /* Session is expecting WELCOME message */ + void *vaddr; + size_t alen; + + GNUNET_SERVER_client_get_address (client, &vaddr, &alen); + LOG (GNUNET_ERROR_TYPE_ERROR, + "Received unexpected %u bytes of type %u from `%s'\n", + (unsigned int) ntohs (message->size), + (unsigned int) ntohs (message->type), + GNUNET_a2s(vaddr, alen)); GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + GNUNET_free_non_null(vaddr); return; } session->last_activity = GNUNET_TIME_absolute_get (); - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + LOG (GNUNET_ERROR_TYPE_DEBUG, "Passing %u bytes of type %u from `%4s' to transport service.\n", (unsigned int) ntohs (message->size), (unsigned int) ntohs (message->type), @@ -1763,6 +1980,10 @@ handle_tcp_data (void *cls, struct GNUNET_SERVER_Client *client, distance[1].value = session->ats_address_network_type; GNUNET_break (ntohl(session->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED); + GNUNET_assert (GNUNET_CONTAINER_multihashmap_contains_value (plugin->sessionmap, + &session->target.hashPubKey, + session)); + delay = plugin->env->receive (plugin->env->cls, &session->target, message, @@ -1770,18 +1991,19 @@ handle_tcp_data (void *cls, struct GNUNET_SERVER_Client *client, 1, session, (GNUNET_YES == session->inbound) ? NULL : session->addr, (GNUNET_YES == session->inbound) ? 0 : session->addrlen); + + reschedule_session_timeout (session); + if (delay.rel_value == 0) { GNUNET_SERVER_receive_done (client, GNUNET_OK); } else { -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Throttling receiving from `%s' for %llu ms\n", - GNUNET_i2s (&session->target), - (unsigned long long) delay.rel_value); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Throttling receiving from `%s' for %llu ms\n", + GNUNET_i2s (&session->target), + (unsigned long long) delay.rel_value); GNUNET_SERVER_disable_receive_done_warning (client); session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session); @@ -1808,16 +2030,14 @@ disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client) session = lookup_session_by_client (plugin, client); if (session == NULL) return; /* unknown, nothing to do */ -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Destroying session of `%4s' with %s due to network-level disconnect.\n", - GNUNET_i2s (&session->target), - (session->addr != - NULL) ? tcp_address_to_string (session->plugin, - session->addr, - session->addrlen) : - "*"); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Destroying session of `%4s' with %s due to network-level disconnect.\n", + GNUNET_i2s (&session->target), + (session->addr != + NULL) ? tcp_address_to_string (session->plugin, + session->addr, + session->addrlen) : + "*"); GNUNET_STATISTICS_update (session->plugin->env->stats, gettext_noop ("# network-level TCP disconnect events"), 1, @@ -1846,7 +2066,7 @@ notify_send_probe (void *cls, size_t size, void *buf) tcp_probe_ctx); if (buf == NULL) { - GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock, GNUNET_NO); + GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock); GNUNET_free (tcp_probe_ctx); return 0; } @@ -1913,6 +2133,91 @@ try_connection_reversal (void *cls, const struct sockaddr *addr, /** + * Session was idle, so disconnect it + */ +static void +session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (NULL != cls); + struct Session *s = cls; + + s->timeout_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Session %p was idle for %llu, disconnecting\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + /* call session destroy function */ + disconnect_session(s); +} + + +/** + * Start session timeout + */ +static void +start_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task); + s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &session_timeout, + s); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout for session %p set to %llu\n", + s, + GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); +} + + +/** + * Increment session timeout due to activity + */ +static void +reschedule_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + if (GNUNET_SCHEDULER_NO_TASK == s->timeout_task) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout for peer `%s' %s not scheduled\n", + GNUNET_i2s (&s->target), + tcp_address_to_string(NULL, s->addr, s->addrlen)); + return; + } + GNUNET_SCHEDULER_cancel (s->timeout_task); + s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &session_timeout, + s); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p set to %llu\n", + s, + (unsigned long long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); +} + + +/** + * Cancel timeout + */ +static void +stop_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) + { + GNUNET_SCHEDULER_cancel (s->timeout_task); + s->timeout_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout rescheduled for session %p canceled\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout for session %p was not active\n", + s); + } +} + + +/** * Entry point for the plugin. * * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*' @@ -1942,6 +2247,18 @@ libgnunet_plugin_transport_tcp_init (void *cls) struct sockaddr **addrs; socklen_t *addrlens; + if (NULL == env->receive) + { + /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully + initialze the plugin or the API */ + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = NULL; + api->address_pretty_printer = &tcp_plugin_address_pretty_printer; + api->address_to_string = &tcp_address_to_string; + api->string_to_address = &tcp_string_to_address; + return api; + } + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", "MAX_CONNECTIONS", @@ -1957,10 +2274,10 @@ libgnunet_plugin_transport_tcp_init (void *cls) "ADVERTISED-PORT", &aport)) && (aport > 65535))) { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", - _ - ("Require valid port number for service `%s' in configuration!\n"), - "transport-tcp"); + LOG (GNUNET_ERROR_TYPE_ERROR, + _ + ("Require valid port number for service `%s' in configuration!\n"), + "transport-tcp"); return NULL; } if (aport == 0) @@ -1969,19 +2286,17 @@ libgnunet_plugin_transport_tcp_init (void *cls) aport = 0; if (bport != 0) { - service = GNUNET_SERVICE_start ("transport-tcp", env->cfg); + service = GNUNET_SERVICE_start ("transport-tcp", env->cfg, GNUNET_SERVICE_OPTION_NONE); if (service == NULL) { - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "tcp", - _("Failed to start service.\n")); + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Failed to start service.\n")); return NULL; } } else service = NULL; - - plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->sessionmap = GNUNET_CONTAINER_multihashmap_create(max_connections); plugin->max_connections = max_connections; @@ -2024,6 +2339,7 @@ libgnunet_plugin_transport_tcp_init (void *cls) api->address_pretty_printer = &tcp_plugin_address_pretty_printer; api->check_address = &tcp_plugin_check_address; api->address_to_string = &tcp_address_to_string; + api->string_to_address = &tcp_string_to_address; plugin->service = service; if (service != NULL) { @@ -2035,9 +2351,9 @@ libgnunet_plugin_transport_tcp_init (void *cls) GNUNET_CONFIGURATION_get_value_time (env->cfg, "transport-tcp", "TIMEOUT", &idle_timeout)) { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", - _("Failed to find option %s in section %s!\n"), - "TIMEOUT", "transport-tcp"); + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Failed to find option %s in section %s!\n"), + "TIMEOUT", "transport-tcp"); if (plugin->nat != NULL) GNUNET_NAT_unregister (plugin->nat); GNUNET_free (plugin); @@ -2058,17 +2374,21 @@ libgnunet_plugin_transport_tcp_init (void *cls) GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify, plugin); plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create (16); if (bport != 0) - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp", - _("TCP transport listening on port %llu\n"), bport); + LOG (GNUNET_ERROR_TYPE_INFO, + _("TCP transport listening on port %llu\n"), bport); else - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp", - _ - ("TCP transport not listening on any port (client only)\n")); + LOG (GNUNET_ERROR_TYPE_INFO, + _ + ("TCP transport not listening on any port (client only)\n")); if (aport != bport) - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp", + LOG (GNUNET_ERROR_TYPE_INFO, _ ("TCP transport advertises itself as being on port %llu\n"), aport); + /* Initially set connections to 0 */ + GNUNET_STATISTICS_set(plugin->env->stats, + gettext_noop ("# TCP sessions active"), 0, + GNUNET_NO); return api; } @@ -2083,13 +2403,17 @@ libgnunet_plugin_transport_tcp_done (void *cls) struct Plugin *plugin = api->cls; struct TCPProbeContext *tcp_probe; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Shutting down TCP plugin\n"); - + if (NULL == plugin) + { + GNUNET_free (api); + return NULL; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down TCP plugin\n"); /* Removing leftover sessions */ GNUNET_CONTAINER_multihashmap_iterate(plugin->sessionmap, &session_disconnect_it, NULL); /* Removing leftover NAT sessions */ - GNUNET_CONTAINER_multihashmap_iterate(plugin->nat_wait_conns, &session_nat_disconnect_it, NULL); + GNUNET_CONTAINER_multihashmap_iterate(plugin->nat_wait_conns, &session_disconnect_it, NULL); if (plugin->service != NULL) GNUNET_SERVICE_stop (plugin->service); @@ -2102,7 +2426,7 @@ libgnunet_plugin_transport_tcp_done (void *cls) { GNUNET_CONTAINER_DLL_remove (plugin->probe_head, plugin->probe_tail, tcp_probe); - GNUNET_CONNECTION_destroy (tcp_probe->sock, GNUNET_NO); + GNUNET_CONNECTION_destroy (tcp_probe->sock); GNUNET_free (tcp_probe); } GNUNET_CONTAINER_multihashmap_destroy (plugin->nat_wait_conns); diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c index 7141563..c5a4c7b 100644 --- a/src/transport/plugin_transport_udp.c +++ b/src/transport/plugin_transport_udp.c @@ -85,6 +85,7 @@ struct PrettyPrinterContext uint16_t port; }; + struct Session { /** @@ -92,13 +93,13 @@ struct Session */ struct GNUNET_PeerIdentity target; + struct FragmentationContext * frag_ctx; + /** * Address of the other peer */ const struct sockaddr *sock_addr; - size_t addrlen; - /** * Desired delay for next sending we send to other peer */ @@ -110,14 +111,23 @@ struct Session struct GNUNET_TIME_Absolute flow_delay_from_other_peer; /** + * Session timeout task + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** * expected delay for ACKs */ struct GNUNET_TIME_Relative last_expected_delay; - struct GNUNET_ATS_Information ats; - struct FragmentationContext * frag_ctx; + size_t addrlen; + + + unsigned int rc; + + int in_destroy; }; @@ -143,12 +153,12 @@ struct SourceInformation */ const void *arg; + struct Session *session; /** * Number of bytes in source address. */ size_t args; - struct Session *session; }; @@ -167,12 +177,13 @@ struct FindReceiveContext */ const struct sockaddr *addr; + struct Session *session; + /** * Number of bytes in 'addr'. */ socklen_t addr_len; - struct Session *session; }; @@ -225,9 +236,6 @@ struct FragmentationContext struct GNUNET_FRAGMENT_Context * frag; struct Session * session; - struct GNUNET_TIME_Absolute timeout; - - /** * Function to call upon completion of the transmission. */ @@ -238,6 +246,8 @@ struct FragmentationContext */ void *cont_cls; + struct GNUNET_TIME_Absolute timeout; + size_t bytes_to_send; }; @@ -248,9 +258,6 @@ struct UDPMessageWrapper struct UDPMessageWrapper *prev; struct UDPMessageWrapper *next; char *udp; - size_t msg_size; - - struct GNUNET_TIME_Absolute timeout; /** * Function to call upon completion of the transmission. @@ -264,6 +271,9 @@ struct UDPMessageWrapper struct FragmentationContext *frag_ctx; + size_t msg_size; + + struct GNUNET_TIME_Absolute timeout; }; @@ -290,6 +300,12 @@ struct UDP_ACK_Message }; /** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin * plugin; + + +/** * We have been notified that our readset 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. @@ -300,6 +316,7 @@ struct UDP_ACK_Message static void udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + /** * We have been notified that our readset has something to read. We don't * know which socket needs to be read, so we have to check each one @@ -311,6 +328,27 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); static void udp_plugin_select_v6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Start session timeout + */ +static void +start_session_timeout (struct Session *s); + +/** + * Increment session timeout due to activity + */ +static void +reschedule_session_timeout (struct Session *s); + +/** + * Cancel timeout + */ +static void +stop_session_timeout (struct Session *s); + + + /** * Function called for a quick conversion of the binary address to * a numeric address. Note that the caller must not free the @@ -364,6 +402,77 @@ udp_address_to_string (void *cls, const void *addr, size_t addrlen) /** + * Function called to convert a string address to + * a binary address. + * + * @param cls closure ('struct Plugin*') + * @param addr string address + * @param addrlen length of the address + * @param buf location to store the buffer + * @param added location to store the number of bytes in the buffer. + * If the function returns GNUNET_SYSERR, its contents are undefined. + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +static int +udp_string_to_address (void *cls, const char *addr, uint16_t addrlen, + void **buf, size_t *added) +{ + struct sockaddr_storage socket_address; + + if ((NULL == addr) || (0 == addrlen)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if ('\0' != addr[addrlen - 1]) + { + return GNUNET_SYSERR; + } + + if (strlen (addr) != addrlen - 1) + { + return GNUNET_SYSERR; + } + + if (GNUNET_OK != GNUNET_STRINGS_to_address_ip (addr, strlen (addr), + &socket_address)) + { + return GNUNET_SYSERR; + } + + switch (socket_address.ss_family) + { + case AF_INET: + { + struct IPv4UdpAddress *u4; + struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address; + u4 = GNUNET_malloc (sizeof (struct IPv4UdpAddress)); + u4->ipv4_addr = in4->sin_addr.s_addr; + u4->u4_port = in4->sin_port; + *buf = u4; + *added = sizeof (struct IPv4UdpAddress); + return GNUNET_OK; + } + case AF_INET6: + { + struct IPv6UdpAddress *u6; + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address; + u6 = GNUNET_malloc (sizeof (struct IPv6UdpAddress)); + u6->ipv6_addr = in6->sin6_addr; + u6->u6_port = in6->sin6_port; + *buf = u6; + *added = sizeof (struct IPv6UdpAddress); + return GNUNET_OK; + } + default: + GNUNET_break (0); + return GNUNET_SYSERR; + } +} + + +/** * Append our port and forward the result. * * @param cls a 'struct PrettyPrinterContext' @@ -446,6 +555,12 @@ udp_plugin_address_pretty_printer (void *cls, const char *type, sb = &a4; sbs = sizeof (a4); } + else if (0 == addrlen) + { + asc (asc_cls, "<inbound connection>"); + asc (asc_cls, NULL); + return; + } else { /* invalid address */ @@ -461,6 +576,21 @@ udp_plugin_address_pretty_printer (void *cls, const char *type, } +static void +call_continuation (struct UDPMessageWrapper *udpw, int result) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Calling continuation for %u byte message to `%s' with result %s\n", + udpw->msg_size, GNUNET_i2s (&udpw->session->target), + (GNUNET_OK == result) ? "OK" : "SYSERR"); + if (NULL != udpw->cont) + { + udpw->cont (udpw->cont_cls, &udpw->session->target,result); + } + +} + + /** * Check if the given port is plausible (must be either our listen * port or our advertised port). If it is neither, we return @@ -479,7 +609,6 @@ check_port (struct Plugin *plugin, uint16_t in_port) } - /** * 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 @@ -539,75 +668,105 @@ udp_plugin_check_address (void *cls, const void *addr, size_t addrlen) /** - * Destroy a session, plugin is being unloaded. + * Task to free resources associated with a session. * - * @param cls unused - * @param key hash of public key of target peer - * @param value a 'struct PeerSession*' to clean up - * @return GNUNET_OK (continue to iterate) + * @param s session to free */ -static int -disconnect_and_free_it (void *cls, const GNUNET_HashCode * key, void *value) +static void +free_session (struct Session *s) +{ + if (s->frag_ctx != NULL) + { + GNUNET_FRAGMENT_context_destroy(s->frag_ctx->frag); + GNUNET_free (s->frag_ctx); + s->frag_ctx = NULL; + } + GNUNET_free (s); +} + + +/** + * Functions with this signature are called whenever we need + * to close a session due to a disconnect or failure to + * establish a connection. + * + * @param s session to close down + */ +static void +disconnect_session (struct Session *s) { - struct Plugin *plugin = cls; - struct Session *s = value; struct UDPMessageWrapper *udpw; struct UDPMessageWrapper *next; -#if DEBUG_UDP + GNUNET_assert (GNUNET_YES != s->in_destroy); LOG (GNUNET_ERROR_TYPE_DEBUG, "Session %p to peer `%s' address ended \n", s, GNUNET_i2s (&s->target), GNUNET_a2s (s->sock_addr, s->addrlen)); -#endif - - if (s->frag_ctx != NULL) - { - GNUNET_FRAGMENT_context_destroy(s->frag_ctx->frag); - GNUNET_free (s->frag_ctx); - s->frag_ctx = NULL; - } - - udpw = plugin->ipv4_queue_head; - while (udpw != NULL) + stop_session_timeout(s); + next = plugin->ipv4_queue_head; + while (NULL != (udpw = next)) { next = udpw->next; if (udpw->session == s) { GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); - - if (udpw->cont != NULL) - udpw->cont (udpw->cont_cls, &s->target, GNUNET_SYSERR); + call_continuation(udpw, GNUNET_SYSERR); GNUNET_free (udpw); } - udpw = next; } - - udpw = plugin->ipv6_queue_head; - while (udpw != NULL) + next = plugin->ipv6_queue_head; + while (NULL != (udpw = next)) { next = udpw->next; if (udpw->session == s) { GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); - - if (udpw->cont != NULL) - udpw->cont (udpw->cont_cls, &s->target, GNUNET_SYSERR); + call_continuation(udpw, GNUNET_SYSERR); GNUNET_free (udpw); } udpw = next; } - plugin->env->session_end (plugin->env->cls, &s->target, s); + if (NULL != s->frag_ctx) + { + if (NULL != s->frag_ctx->cont) + { + s->frag_ctx->cont (s->frag_ctx->cont_cls, &s->target, GNUNET_SYSERR); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Calling continuation for fragemented message to `%s' with result SYSERR\n", + GNUNET_i2s (&s->target)); + } + } + GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (plugin->sessions, &s->target.hashPubKey, s)); + GNUNET_STATISTICS_set(plugin->env->stats, + "# UDP sessions active", + GNUNET_CONTAINER_multihashmap_size(plugin->sessions), + GNUNET_NO); + if (s->rc > 0) + s->in_destroy = GNUNET_YES; + else + free_session (s); +} - - GNUNET_free (s); +/** + * Destroy a session, plugin is being unloaded. + * + * @param cls unused + * @param key hash of public key of target peer + * @param value a 'struct PeerSession*' to clean up + * @return GNUNET_OK (continue to iterate) + */ +static int +disconnect_and_free_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + disconnect_session(value); return GNUNET_OK; } @@ -626,14 +785,13 @@ udp_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) GNUNET_assert (plugin != NULL); GNUNET_assert (target != NULL); -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer `%s'\n", GNUNET_i2s (target)); -#endif /* Clean up sessions */ GNUNET_CONTAINER_multihashmap_get_multiple (plugin->sessions, &target->hashPubKey, &disconnect_and_free_it, plugin); } + static struct Session * create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, const void *addr, size_t addrlen, @@ -688,20 +846,19 @@ create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, GNUNET_break_op (0); return NULL; } - s->addrlen = len; s->target = *target; s->sock_addr = (const struct sockaddr *) &s[1]; - s->flow_delay_for_other_peer = GNUNET_TIME_relative_get_zero(); - s->flow_delay_from_other_peer = GNUNET_TIME_absolute_get_zero(); s->last_expected_delay = GNUNET_TIME_UNIT_SECONDS; - + start_session_timeout(s); return s; } -static int session_cmp_it (void *cls, - const GNUNET_HashCode * key, - void *value) + +static int +session_cmp_it (void *cls, + const GNUNET_HashCode * key, + void *value) { struct SessionCompareContext * cctx = cls; const struct GNUNET_HELLO_Address *address = cctx->addr; @@ -709,12 +866,9 @@ static int session_cmp_it (void *cls, socklen_t s_addrlen = s->addrlen; -#if VERBOSE_UDP - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing address %s <-> %s\n", + LOG (GNUNET_ERROR_TYPE_DEBUG, "Comparing address %s <-> %s\n", udp_address_to_string (NULL, (void *) address->address, address->address_length), GNUNET_a2s (s->sock_addr, s->addrlen)); -#endif - if ((address->address_length == sizeof (struct IPv4UdpAddress)) && (s_addrlen == sizeof (struct sockaddr_in))) { @@ -742,8 +896,6 @@ static int session_cmp_it (void *cls, return GNUNET_NO; } } - - return GNUNET_YES; } @@ -799,15 +951,14 @@ udp_plugin_get_session (void *cls, struct SessionCompareContext cctx; cctx.addr = address; cctx.res = NULL; -#if VERBOSE_UDP - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for existing session for peer `%s' `%s' \n", GNUNET_i2s (&address->peer), udp_address_to_string(NULL, address->address, address->address_length)); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Looking for existing session for peer `%s' `%s' \n", + GNUNET_i2s (&address->peer), + udp_address_to_string(NULL, address->address, address->address_length)); GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessions, &address->peer.hashPubKey, session_cmp_it, &cctx); if (cctx.res != NULL) { -#if VERBOSE_UDP - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found existing session %p\n", cctx.res); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing session %p\n", cctx.res); return cctx.res; } @@ -817,23 +968,28 @@ udp_plugin_get_session (void *cls, address->address, address->address_length, NULL, NULL); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating new session %p for peer `%s' address `%s'\n", - s, - GNUNET_i2s(&address->peer), - udp_address_to_string(NULL,address->address,address->address_length)); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Creating new session %p for peer `%s' address `%s'\n", + s, + GNUNET_i2s(&address->peer), + udp_address_to_string(NULL,address->address,address->address_length)); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (plugin->sessions, &s->target.hashPubKey, s, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); + GNUNET_STATISTICS_set(plugin->env->stats, + "# UDP sessions active", + GNUNET_CONTAINER_multihashmap_size(plugin->sessions), + GNUNET_NO); + return s; } -static void enqueue (struct Plugin *plugin, struct UDPMessageWrapper * udpw) + +static void +enqueue (struct Plugin *plugin, struct UDPMessageWrapper * udpw) { if (udpw->session->addrlen == sizeof (struct sockaddr_in)) @@ -842,6 +998,26 @@ static void enqueue (struct Plugin *plugin, struct UDPMessageWrapper * udpw) GNUNET_CONTAINER_DLL_insert(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); } + +/** + * Fragment message was transmitted via UDP, let fragmentation know + * to send the next fragment now. + * + * @param cls the 'struct UDPMessageWrapper' of the fragment + * @param target destination peer (ignored) + * @param result GNUNET_OK on success (ignored) + */ +static void +send_next_fragment (void *cls, + const struct GNUNET_PeerIdentity *target, + int result) +{ + struct UDPMessageWrapper *udpw = cls; + + GNUNET_FRAGMENT_context_transmission_done (udpw->frag_ctx->frag); +} + + /** * Function that is called with messages created by the fragmentation * module. In the case of the 'proc' callback of the @@ -858,28 +1034,23 @@ enqueue_fragment (void *cls, const struct GNUNET_MessageHeader *msg) struct Plugin *plugin = frag_ctx->plugin; struct UDPMessageWrapper * udpw; struct Session *s; - size_t msg_len = ntohs (msg->size); -#if VERBOSE_UDP - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Enqueuing fragment with %u bytes %u\n", msg_len , sizeof (struct UDPMessageWrapper)); -#endif - + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Enqueuing fragment with %u bytes %u\n", msg_len , sizeof (struct UDPMessageWrapper)); udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + msg_len); udpw->session = frag_ctx->session; s = udpw->session; udpw->udp = (char *) &udpw[1]; udpw->msg_size = msg_len; - udpw->cont = frag_ctx->cont; - udpw->cont_cls = frag_ctx->cont_cls; + udpw->cont = &send_next_fragment; + udpw->cont_cls = udpw; udpw->timeout = frag_ctx->timeout; udpw->frag_ctx = frag_ctx; memcpy (udpw->udp, msg, msg_len); - enqueue (plugin, udpw); - if (s->addrlen == sizeof (struct sockaddr_in)) { if (plugin->with_v4_ws == GNUNET_NO) @@ -889,7 +1060,6 @@ enqueue_fragment (void *cls, const struct GNUNET_MessageHeader *msg) plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v4, plugin->ws_v4, @@ -897,7 +1067,6 @@ enqueue_fragment (void *cls, const struct GNUNET_MessageHeader *msg) plugin->with_v4_ws = GNUNET_YES; } } - else if (s->addrlen == sizeof (struct sockaddr_in6)) { if (plugin->with_v6_ws == GNUNET_NO) @@ -907,7 +1076,6 @@ enqueue_fragment (void *cls, const struct GNUNET_MessageHeader *msg) plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v6, plugin->ws_v6, @@ -915,12 +1083,9 @@ enqueue_fragment (void *cls, const struct GNUNET_MessageHeader *msg) plugin->with_v6_ws = GNUNET_YES; } } - } - - /** * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a @@ -958,7 +1123,6 @@ udp_plugin_send (void *cls, { struct Plugin *plugin = cls; size_t mlen = msgbuf_size + sizeof (struct UDPMessage); - struct UDPMessageWrapper * udpw; struct UDPMessage *udp; char mbuf[mlen]; @@ -967,29 +1131,24 @@ udp_plugin_send (void *cls, if ((s->addrlen == sizeof (struct sockaddr_in6)) && (plugin->sockv6 == NULL)) return GNUNET_SYSERR; - - if ((s->addrlen == sizeof (struct sockaddr_in)) && (plugin->sockv4 == NULL)) - return GNUNET_SYSERR; - - + if ((s->addrlen == sizeof (struct sockaddr_in)) && (plugin->sockv4 == NULL)) + return GNUNET_SYSERR; if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return GNUNET_SYSERR; } - if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains_value(plugin->sessions, &s->target.hashPubKey, s)) { GNUNET_break (0); return GNUNET_SYSERR; } - LOG (GNUNET_ERROR_TYPE_DEBUG, "UDP transmits %u-byte message to `%s' using address `%s'\n", - msgbuf_size, - GNUNET_i2s (&s->target), - GNUNET_a2s(s->sock_addr, s->addrlen)); - + mlen, + GNUNET_i2s (&s->target), + GNUNET_a2s(s->sock_addr, s->addrlen)); + /* Message */ udp = (struct UDPMessage *) mbuf; udp->header.size = htons (mlen); @@ -997,6 +1156,7 @@ udp_plugin_send (void *cls, udp->reserved = htonl (0); udp->sender = *plugin->env->my_identity; + reschedule_session_timeout(s); if (mlen <= UDP_MTU) { udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + mlen); @@ -1007,7 +1167,6 @@ udp_plugin_send (void *cls, udpw->cont = cont; udpw->cont_cls = cont_cls; udpw->frag_ctx = NULL; - memcpy (udpw->udp, udp, sizeof (struct UDPMessage)); memcpy (&udpw->udp[sizeof (struct UDPMessage)], msgbuf, msgbuf_size); @@ -1037,7 +1196,6 @@ udp_plugin_send (void *cls, frag_ctx); s->frag_ctx = frag_ctx; - } if (s->addrlen == sizeof (struct sockaddr_in)) @@ -1049,7 +1207,6 @@ udp_plugin_send (void *cls, plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v4, plugin->ws_v4, @@ -1057,7 +1214,6 @@ udp_plugin_send (void *cls, plugin->with_v4_ws = GNUNET_YES; } } - else if (s->addrlen == sizeof (struct sockaddr_in6)) { if (plugin->with_v6_ws == GNUNET_NO) @@ -1067,7 +1223,6 @@ udp_plugin_send (void *cls, plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v6, plugin->ws_v6, @@ -1135,7 +1290,7 @@ udp_nat_port_map_callback (void *cls, int add_remove, * @param client the 'struct SourceInformation' * @param hdr the actual message */ -static void +static int process_inbound_tokenized_messages (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) { @@ -1145,20 +1300,23 @@ process_inbound_tokenized_messages (void *cls, void *client, struct GNUNET_TIME_Relative delay; GNUNET_assert (si->session != NULL); + if (GNUNET_YES == si->session->in_destroy) + return GNUNET_OK; /* setup ATS */ ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); ats[0].value = htonl (1); ats[1] = si->session->ats; GNUNET_break (ntohl(ats[1].value) != GNUNET_ATS_NET_UNSPECIFIED); - delay = plugin->env->receive (plugin->env->cls, - &si->sender, - hdr, - (const struct GNUNET_ATS_Information *) &ats, 2, - NULL, - si->arg, - si->args); + &si->sender, + hdr, + (const struct GNUNET_ATS_Information *) &ats, 2, + NULL, + si->arg, + si->args); si->session->flow_delay_for_other_peer = delay; + reschedule_session_timeout(si->session); + return GNUNET_OK; } @@ -1176,7 +1334,7 @@ process_udp_message (struct Plugin *plugin, const struct UDPMessage *msg, socklen_t sender_addr_len) { struct SourceInformation si; - struct Session * s = NULL; + struct Session * s; struct IPv4UdpAddress u4; struct IPv6UdpAddress u6; const void *arg; @@ -1215,12 +1373,10 @@ process_udp_message (struct Plugin *plugin, const struct UDPMessage *msg, GNUNET_break (0); return; } -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message with %u bytes from peer `%s' at `%s'\n", (unsigned int) ntohs (msg->header.size), GNUNET_i2s (&msg->sender), GNUNET_a2s (sender_addr, sender_addr_len)); -#endif struct GNUNET_HELLO_Address * address = GNUNET_HELLO_address_allocate(&msg->sender, "udp", arg, args); s = udp_plugin_get_session(plugin, address); @@ -1231,10 +1387,13 @@ process_udp_message (struct Plugin *plugin, const struct UDPMessage *msg, si.sender = msg->sender; si.arg = arg; si.args = args; - + s->rc++; GNUNET_SERVER_mst_receive (plugin->mst, &si, (const char *) &msg[1], ntohs (msg->header.size) - sizeof (struct UDPMessage), GNUNET_YES, GNUNET_NO); + s->rc--; + if ( (0 == s->rc) && (GNUNET_YES == s->in_destroy)) + free_session (s); } @@ -1290,14 +1449,17 @@ fragment_msg_proc (void *cls, const struct GNUNET_MessageHeader *msg) rc->src_addr, rc->addr_len); } + struct LookupContext { const struct sockaddr * addr; - size_t addrlen; struct Session *res; + + size_t addrlen; }; + static int lookup_session_by_addr_it (void *cls, const GNUNET_HashCode * key, void *value) { @@ -1313,6 +1475,7 @@ lookup_session_by_addr_it (void *cls, const GNUNET_HashCode * key, void *value) return GNUNET_YES; } + /** * Transmit an acknowledgement. * @@ -1324,7 +1487,6 @@ static void ack_proc (void *cls, uint32_t id, const struct GNUNET_MessageHeader *msg) { struct DefragContext *rc = cls; - size_t msize = sizeof (struct UDP_ACK_Message) + ntohs (msg->size); struct UDP_ACK_Message *udp_ack; uint32_t delay = 0; @@ -1340,12 +1502,12 @@ ack_proc (void *cls, uint32_t id, const struct GNUNET_MessageHeader *msg) &l_ctx); s = l_ctx.res; - GNUNET_assert (s != NULL); + if (NULL == s) + return; if (s->flow_delay_for_other_peer.rel_value <= UINT32_MAX) delay = s->flow_delay_for_other_peer.rel_value; -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ACK to `%s' including delay of %u ms\n", GNUNET_a2s (rc->src_addr, @@ -1353,16 +1515,11 @@ ack_proc (void *cls, uint32_t id, const struct GNUNET_MessageHeader *msg) AF_INET) ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6)), delay); -#endif udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + msize); - udpw->cont = NULL; - udpw->cont_cls = NULL; - udpw->frag_ctx = NULL; udpw->msg_size = msize; udpw->session = s; - udpw->timeout = GNUNET_TIME_absolute_get_forever(); + udpw->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; udpw->udp = (char *)&udpw[1]; - udp_ack = (struct UDP_ACK_Message *) udpw->udp; udp_ack->header.size = htons ((uint16_t) msize); udp_ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK); @@ -1374,10 +1531,11 @@ ack_proc (void *cls, uint32_t id, const struct GNUNET_MessageHeader *msg) } -static void read_process_msg (struct Plugin *plugin, - const struct GNUNET_MessageHeader *msg, - char *addr, - socklen_t fromlen) +static void +read_process_msg (struct Plugin *plugin, + const struct GNUNET_MessageHeader *msg, + const char *addr, + socklen_t fromlen) { if (ntohs (msg->size) < sizeof (struct UDPMessage)) { @@ -1386,18 +1544,19 @@ static void read_process_msg (struct Plugin *plugin, } process_udp_message (plugin, (const struct UDPMessage *) msg, (const struct sockaddr *) addr, fromlen); - return; } -static void read_process_ack (struct Plugin *plugin, - const struct GNUNET_MessageHeader *msg, - char *addr, - socklen_t fromlen) + +static void +read_process_ack (struct Plugin *plugin, + const struct GNUNET_MessageHeader *msg, + char *addr, + socklen_t fromlen) { const struct GNUNET_MessageHeader *ack; const struct UDP_ACK_Message *udp_ack; struct LookupContext l_ctx; - struct Session *s = NULL; + struct Session *s; struct GNUNET_TIME_Relative flow_delay; if (ntohs (msg->size) < @@ -1406,9 +1565,7 @@ static void read_process_ack (struct Plugin *plugin, GNUNET_break_op (0); return; } - udp_ack = (const struct UDP_ACK_Message *) msg; - l_ctx.addr = (const struct sockaddr *) addr; l_ctx.addrlen = fromlen; l_ctx.res = NULL; @@ -1436,35 +1593,33 @@ static void read_process_ack (struct Plugin *plugin, if (GNUNET_OK != GNUNET_FRAGMENT_process_ack (s->frag_ctx->frag, ack)) { -#if DEBUG_UDP - LOG (GNUNET_ERROR_TYPE_DEBUG, - "UDP processes %u-byte acknowledgement from `%s' at `%s'\n", - (unsigned int) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender), - GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "UDP processes %u-byte acknowledgement from `%s' at `%s'\n", + (unsigned int) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender), + GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); return; } -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "FULL MESSAGE ACKed\n", (unsigned int) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender), GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); -#endif s->last_expected_delay = GNUNET_FRAGMENT_context_destroy (s->frag_ctx->frag); - struct UDPMessageWrapper * udpw = NULL; + struct UDPMessageWrapper * udpw; + struct UDPMessageWrapper * tmp; if (s->addrlen == sizeof (struct sockaddr_in6)) { udpw = plugin->ipv6_queue_head; - while (udpw!= NULL) + while (NULL != udpw) { + tmp = udpw->next; if ((udpw->frag_ctx != NULL) && (udpw->frag_ctx == s->frag_ctx)) { GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); GNUNET_free (udpw); } - udpw = udpw->next; + udpw = tmp; } } if (s->addrlen == sizeof (struct sockaddr_in)) @@ -1472,43 +1627,46 @@ static void read_process_ack (struct Plugin *plugin, udpw = plugin->ipv4_queue_head; while (udpw!= NULL) { + tmp = udpw->next; if ((udpw->frag_ctx != NULL) && (udpw->frag_ctx == s->frag_ctx)) { GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); GNUNET_free (udpw); } - udpw = udpw->next; + udpw = tmp; } } if (s->frag_ctx->cont != NULL) - s->frag_ctx->cont - (s->frag_ctx->cont_cls, &udp_ack->sender, GNUNET_OK); + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Calling continuation for fragmented message to `%s' with result %s\n", + GNUNET_i2s (&s->target), "OK"); + s->frag_ctx->cont (s->frag_ctx->cont_cls, &udp_ack->sender, GNUNET_OK); + } + GNUNET_free (s->frag_ctx); s->frag_ctx = NULL; - return; } -static void read_process_fragment (struct Plugin *plugin, - const struct GNUNET_MessageHeader *msg, - char *addr, - socklen_t fromlen) + +static void +read_process_fragment (struct Plugin *plugin, + const struct GNUNET_MessageHeader *msg, + char *addr, + socklen_t fromlen) { struct DefragContext *d_ctx; struct GNUNET_TIME_Absolute now; struct FindReceiveContext frc; - frc.rc = NULL; frc.addr = (const struct sockaddr *) addr; frc.addr_len = fromlen; -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "UDP processes %u-byte fragment from `%s'\n", (unsigned int) ntohs (msg->size), GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); -#endif - /* Lookup existing receive context for this address */ GNUNET_CONTAINER_heap_iterate (plugin->defrag_ctxs, &find_receive_context, @@ -1532,19 +1690,17 @@ static void read_process_fragment (struct Plugin *plugin, GNUNET_CONTAINER_heap_insert (plugin->defrag_ctxs, d_ctx, (GNUNET_CONTAINER_HeapCostType) now.abs_value); -#if DEBUG_UDP - LOG (GNUNET_ERROR_TYPE_DEBUG, "Created new defragmentation context for %u-byte fragment from `%s'\n", - (unsigned int) ntohs (msg->size), - GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Created new defragmentation context for %u-byte fragment from `%s'\n", + (unsigned int) ntohs (msg->size), + GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); } else { -#if DEBUG_UDP - LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing defragmentation context for %u-byte fragment from `%s'\n", - (unsigned int) ntohs (msg->size), - GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Found existing defragmentation context for %u-byte fragment from `%s'\n", + (unsigned int) ntohs (msg->size), + GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); } if (GNUNET_OK == GNUNET_DEFRAGMENT_process_fragment (d_ctx->defrag, msg)) @@ -1565,6 +1721,7 @@ static void read_process_fragment (struct Plugin *plugin, } } + /** * Read and process a message from the given socket. * @@ -1576,7 +1733,7 @@ udp_select_read (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *rsock) { socklen_t fromlen; char addr[32]; - char buf[65536]; + char buf[65536] GNUNET_ALIGN; ssize_t size; const struct GNUNET_MessageHeader *msg; @@ -1613,7 +1770,7 @@ udp_select_read (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *rsock) return; case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK: - read_process_ack (plugin, msg, addr, fromlen);; + read_process_ack (plugin, msg, addr, fromlen); return; case GNUNET_MESSAGE_TYPE_FRAGMENT: @@ -1626,14 +1783,13 @@ udp_select_read (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *rsock) } } -size_t + +static size_t udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock) { ssize_t sent; size_t slen; struct GNUNET_TIME_Absolute max; - struct GNUNET_TIME_Absolute ; - struct UDPMessageWrapper *udpw = NULL; if (sock == plugin->sockv4) @@ -1660,25 +1816,21 @@ udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock) if (max.abs_value != udpw->timeout.abs_value) { /* Message timed out */ - - if (udpw->cont != NULL) - udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR); + call_continuation(udpw, GNUNET_SYSERR); if (udpw->frag_ctx != NULL) { -#if DEBUG_UDP - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fragmented message for peer `%s' with size %u timed out\n", - GNUNET_i2s(&udpw->session->target), udpw->frag_ctx->bytes_to_send); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Fragmented message for peer `%s' with size %u timed out\n", + GNUNET_i2s(&udpw->session->target), udpw->frag_ctx->bytes_to_send); udpw->session->last_expected_delay = GNUNET_FRAGMENT_context_destroy(udpw->frag_ctx->frag); GNUNET_free (udpw->frag_ctx); udpw->session->frag_ctx = NULL; } else { -#if DEBUG_UDP - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' with size %u timed out\n", - GNUNET_i2s(&udpw->session->target), udpw->msg_size); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Message for peer `%s' with size %u timed out\n", + GNUNET_i2s(&udpw->session->target), udpw->msg_size); } if (sock == plugin->sockv4) @@ -1700,20 +1852,21 @@ udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock) if (delta.rel_value == 0) { /* this message is not delayed */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' (%u bytes) is not delayed \n", - GNUNET_i2s(&udpw->session->target), udpw->msg_size); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Message for peer `%s' (%u bytes) is not delayed \n", + GNUNET_i2s(&udpw->session->target), udpw->msg_size); break; } else { /* this message is delayed, try next */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' (%u bytes) is delayed for %llu \n", - GNUNET_i2s(&udpw->session->target), udpw->msg_size, - delta); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Message for peer `%s' (%u bytes) is delayed for %llu \n", + GNUNET_i2s(&udpw->session->target), udpw->msg_size, + delta); udpw = udpw->next; } } - } if (udpw == NULL) @@ -1726,29 +1879,40 @@ udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock) if (GNUNET_SYSERR == sent) { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto"); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "UDP transmitted %u-byte message to %s (%d: %s)\n", - (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), (int) sent, - (sent < 0) ? STRERROR (errno) : "ok"); - if (udpw->cont != NULL) - udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "UDP transmitted %u-byte message to %s (%d: %s)\n", - (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), (int) sent, - (sent < 0) ? STRERROR (errno) : "ok"); + const struct GNUNET_ATS_Information type = plugin->env->get_address_type + (plugin->env->cls,sa, slen); - /* This was just a message fragment */ - if (udpw->frag_ctx != NULL) - { - GNUNET_FRAGMENT_context_transmission_done (udpw->frag_ctx->frag); + if ((GNUNET_ATS_NET_WAN == type.value) && + ((ENETUNREACH == errno) || (ENETDOWN == errno))) + { + /* "Network unreachable" or "Network down" */ + /* + * This indicates that this system is IPv6 enabled, but does not + * have a valid global IPv6 address assigned + */ + LOG (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + _("UDP could not message to `%s': `%s'. " + "Please check your network configuration and disable IPv6 if your " + "connection does not have a global IPv6 address\n"), + GNUNET_a2s (sa, slen), + STRERROR (errno)); + } + else + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "UDP could not transmit %u-byte message to `%s': `%s'\n", + (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), + STRERROR (errno)); + } + call_continuation(udpw, GNUNET_SYSERR); } - /* This was a complete message*/ else { - if (udpw->cont != NULL) - udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_OK); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "UDP transmitted %u-byte message to `%s' (%d: %s)\n", + (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), (int) sent, + (sent < 0) ? STRERROR (errno) : "ok"); + call_continuation(udpw, GNUNET_OK); } if (sock == plugin->sockv4) @@ -1761,6 +1925,7 @@ udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock) return sent; } + /** * We have been notified that our readset has something to read. We don't * know which socket needs to be read, so we have to check each one @@ -1799,7 +1964,6 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (plugin->select_task); plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v4, (plugin->ipv4_queue_head != NULL) ? plugin->ws_v4 : NULL, @@ -1847,7 +2011,6 @@ udp_plugin_select_v6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (plugin->select_task_v6); plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v6, (plugin->ipv6_queue_head != NULL) ? plugin->ws_v6 : NULL, @@ -1875,7 +2038,7 @@ setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct plugin->sockv6 = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 0); if (NULL == plugin->sockv6) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Disabling IPv6 since it is not supported on this system!\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "Disabling IPv6 since it is not supported on this system!\n"); plugin->enable_ipv6 = GNUNET_NO; } else @@ -1888,20 +2051,16 @@ setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct serverAddrv6->sin6_port = htons (plugin->port); addrlen = sizeof (struct sockaddr_in6); serverAddr = (struct sockaddr *) serverAddrv6; -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding to IPv6 port %d\n", ntohs (serverAddrv6->sin6_port)); -#endif tries = 0; while (GNUNET_NETWORK_socket_bind (plugin->sockv6, serverAddr, addrlen) != GNUNET_OK) { serverAddrv6->sin6_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 Binding failed, trying new port %d\n", ntohs (serverAddrv6->sin6_port)); -#endif tries++; if (tries > 10) { @@ -1912,11 +2071,9 @@ setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct } if (plugin->sockv6 != NULL) { -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 socket created on port %d\n", ntohs (serverAddrv6->sin6_port)); -#endif addrs[sockets_created] = (struct sockaddr *) serverAddrv6; addrlens[sockets_created] = sizeof (struct sockaddr_in6); sockets_created++; @@ -1941,19 +2098,15 @@ setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct addrlen = sizeof (struct sockaddr_in); serverAddr = (struct sockaddr *) serverAddrv4; -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding to IPv4 port %d\n", ntohs (serverAddrv4->sin_port)); -#endif tries = 0; while (GNUNET_NETWORK_socket_bind (plugin->sockv4, serverAddr, addrlen) != GNUNET_OK) { serverAddrv4->sin_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv4 Binding failed, trying new port %d\n", ntohs (serverAddrv4->sin_port)); -#endif tries++; if (tries > 10) { @@ -1982,11 +2135,10 @@ setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct } if (sockets_created == 0) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UDP sockets\n")); + LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UDP sockets\n")); plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v4, NULL, @@ -2007,7 +2159,6 @@ setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v6, NULL, @@ -2024,6 +2175,82 @@ setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct return sockets_created; } +/** + * Session was idle, so disconnect it + */ +static void +session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (NULL != cls); + struct Session *s = cls; + + s->timeout_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %p was idle for %llu, disconnecting\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + + /* call session destroy function */ + disconnect_session(s); + +} + +/** + * Start session timeout + */ +static void +start_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task); + + s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &session_timeout, + s); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p set to %llu\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); +} + +/** + * Increment session timeout due to activity + */ +static void +reschedule_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); + + GNUNET_SCHEDULER_cancel (s->timeout_task); + s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &session_timeout, + s); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p set to %llu\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); +} + +/** + * Cancel timeout + */ +static void +stop_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + + if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) + { + GNUNET_SCHEDULER_cancel (s->timeout_task); + s->timeout_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p canceled\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p was not active\n", + s); + } +} /** * The exported method. Makes the core api available via a global and @@ -2037,8 +2264,7 @@ libgnunet_plugin_transport_udp_init (void *cls) { struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; struct GNUNET_TRANSPORT_PluginFunctions *api; - struct Plugin *plugin; - + struct Plugin *p; unsigned long long port; unsigned long long aport; unsigned long long broadcast; @@ -2047,12 +2273,24 @@ libgnunet_plugin_transport_udp_init (void *cls) char * bind4_address; char * bind6_address; struct GNUNET_TIME_Relative interval; - struct sockaddr_in serverAddrv4; struct sockaddr_in6 serverAddrv6; - int res; + if (NULL == env->receive) + { + /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully + initialze the plugin or the API */ + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = NULL; + api->address_pretty_printer = &udp_plugin_address_pretty_printer; + api->address_to_string = &udp_address_to_string; + api->string_to_address = &udp_string_to_address; + return api; + } + + GNUNET_assert( NULL != env->stats); + /* Get port number */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp", "PORT", @@ -2080,7 +2318,6 @@ libgnunet_plugin_transport_udp_init (void *cls) else enable_v6 = GNUNET_YES; - /* Addresses */ memset (&serverAddrv6, 0, sizeof (serverAddrv6)); memset (&serverAddrv4, 0, sizeof (serverAddrv4)); @@ -2117,7 +2354,6 @@ libgnunet_plugin_transport_udp_init (void *cls) } } - /* Enable neighbour discovery */ broadcast = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "transport-udp", "BROADCAST"); @@ -2137,56 +2373,60 @@ libgnunet_plugin_transport_udp_init (void *cls) udp_max_bps = 1024 * 1024 * 50; /* 50 MB/s == infinity for practical purposes */ } - plugin = GNUNET_malloc (sizeof (struct Plugin)); + p = GNUNET_malloc (sizeof (struct Plugin)); api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); - GNUNET_BANDWIDTH_tracker_init (&plugin->tracker, + GNUNET_BANDWIDTH_tracker_init (&p->tracker, GNUNET_BANDWIDTH_value_init ((uint32_t)udp_max_bps), 30); - - - plugin->sessions = GNUNET_CONTAINER_multihashmap_create (10); - plugin->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); - plugin->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages, plugin); - plugin->port = port; - plugin->aport = aport; - plugin->broadcast_interval = interval; - plugin->enable_ipv6 = enable_v6; - plugin->env = env; - - api->cls = plugin; + p->sessions = GNUNET_CONTAINER_multihashmap_create (10); + p->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + p->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages, p); + p->port = port; + p->aport = aport; + p->broadcast_interval = interval; + p->enable_ipv6 = enable_v6; + p->env = env; + + plugin = p; + + api->cls = p; api->send = NULL; api->disconnect = &udp_disconnect; api->address_pretty_printer = &udp_plugin_address_pretty_printer; api->address_to_string = &udp_address_to_string; + api->string_to_address = &udp_string_to_address; api->check_address = &udp_plugin_check_address; api->get_session = &udp_plugin_get_session; api->send = &udp_plugin_send; LOG (GNUNET_ERROR_TYPE_DEBUG, "Setting up sockets\n"); - res = setup_sockets (plugin, &serverAddrv6, &serverAddrv4); - if ((res == 0) || ((plugin->sockv4 == NULL) && (plugin->sockv6 == NULL))) + res = setup_sockets (p, &serverAddrv6, &serverAddrv4); + if ((res == 0) || ((p->sockv4 == NULL) && (p->sockv6 == NULL))) { LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to create network sockets, plugin failed\n"); - GNUNET_free (plugin); + GNUNET_free (p); GNUNET_free (api); return NULL; } - LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting broadcasting\n"); if (broadcast == GNUNET_YES) - setup_broadcast (plugin, &serverAddrv6, &serverAddrv4); - + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting broadcasting\n"); + setup_broadcast (p, &serverAddrv6, &serverAddrv4); + } GNUNET_free_non_null (bind4_address); GNUNET_free_non_null (bind6_address); return api; } -int heap_cleanup_iterator (void *cls, - struct GNUNET_CONTAINER_HeapNode * - node, void *element, - GNUNET_CONTAINER_HeapCostType - cost) + +static int +heap_cleanup_iterator (void *cls, + struct GNUNET_CONTAINER_HeapNode * + node, void *element, + GNUNET_CONTAINER_HeapCostType + cost) { struct DefragContext * d_ctx = element; @@ -2203,13 +2443,20 @@ int heap_cleanup_iterator (void *cls, * returns the udp transport API. * * @param cls our 'struct GNUNET_TRANSPORT_PluginEnvironment' - * @return our 'struct GNUNET_TRANSPORT_PluginFunctions' + * @return NULL */ void * libgnunet_plugin_transport_udp_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; + + if (NULL == plugin) + { + GNUNET_free (api); + return NULL; + } + stop_broadcast (plugin); if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) @@ -2263,8 +2510,7 @@ libgnunet_plugin_transport_udp_done (void *cls) { struct UDPMessageWrapper *tmp = udpw->next; GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); - if (udpw->cont != NULL) - udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR); + call_continuation(udpw, GNUNET_SYSERR); GNUNET_free (udpw); udpw = tmp; } @@ -2273,17 +2519,14 @@ libgnunet_plugin_transport_udp_done (void *cls) { struct UDPMessageWrapper *tmp = udpw->next; GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); - if (udpw->cont != NULL) - udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR); + call_continuation(udpw, GNUNET_SYSERR); GNUNET_free (udpw); udpw = tmp; } /* Clean up sessions */ -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up sessions\n"); -#endif GNUNET_CONTAINER_multihashmap_iterate (plugin->sessions, &disconnect_and_free_it, plugin); GNUNET_CONTAINER_multihashmap_destroy (plugin->sessions); diff --git a/src/transport/plugin_transport_udp_broadcasting.c b/src/transport/plugin_transport_udp_broadcasting.c index e33af26..baabf45 100644 --- a/src/transport/plugin_transport_udp_broadcasting.c +++ b/src/transport/plugin_transport_udp_broadcasting.c @@ -90,7 +90,7 @@ struct Mstv6Context -void +int broadcast_ipv6_mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message) { @@ -104,13 +104,11 @@ broadcast_ipv6_mst_cb (void *cls, void *client, if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON != ntohs (msg->header.type)) - return; -#if DEBUG_UDP_BROADCASTING + return GNUNET_OK; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received beacon with %u bytes from peer `%s' via address `%s'\n", ntohs (msg->header.size), GNUNET_i2s (&msg->sender), udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr))); -#endif struct GNUNET_ATS_Information atsi[2]; /* setup ATS */ @@ -130,9 +128,10 @@ broadcast_ipv6_mst_cb (void *cls, void *client, ("# IPv6 multicast HELLO beacons received via udp"), 1, GNUNET_NO); GNUNET_free (mc); + return GNUNET_OK; } -void +int broadcast_ipv4_mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message) { @@ -145,13 +144,11 @@ broadcast_ipv4_mst_cb (void *cls, void *client, if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON != ntohs (msg->header.type)) - return; -#if DEBUG_UDP_BROADCASTING + return GNUNET_OK; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received beacon with %u bytes from peer `%s' via address `%s'\n", ntohs (msg->header.size), GNUNET_i2s (&msg->sender), udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr))); -#endif struct GNUNET_ATS_Information atsi[2]; @@ -172,6 +169,7 @@ broadcast_ipv4_mst_cb (void *cls, void *client, ("# IPv4 broadcast HELLO beacons received via udp"), 1, GNUNET_NO); GNUNET_free (mc); + return GNUNET_OK; } void @@ -179,13 +177,11 @@ udp_broadcast_receive (struct Plugin *plugin, const char * buf, ssize_t size, st { struct GNUNET_ATS_Information ats; - if (addrlen == sizeof (struct sockaddr_in)) + if ((GNUNET_YES == plugin->broadcast_ipv4) && (addrlen == sizeof (struct sockaddr_in))) { -#if DEBUG_UDP_BROADCASTING LOG (GNUNET_ERROR_TYPE_DEBUG, "Received IPv4 HELLO beacon broadcast with %i bytes from address %s\n", size, GNUNET_a2s ((const struct sockaddr *) addr, addrlen)); -#endif struct Mstv4Context *mc; mc = GNUNET_malloc (sizeof (struct Mstv4Context)); @@ -195,18 +191,18 @@ udp_broadcast_receive (struct Plugin *plugin, const char * buf, ssize_t size, st mc->addr.u4_port = av4->sin_port; ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen); mc->ats_address_network_type = ats.value; + + GNUNET_assert (NULL != plugin->broadcast_ipv4_mst); if (GNUNET_OK != GNUNET_SERVER_mst_receive (plugin->broadcast_ipv4_mst, mc, buf, size, GNUNET_NO, GNUNET_NO)) GNUNET_free (mc); } - else if (addrlen == sizeof (struct sockaddr_in6)) + else if ((GNUNET_YES == plugin->broadcast_ipv4) && (addrlen == sizeof (struct sockaddr_in6))) { -#if DEBUG_UDP_BROADCASTING LOG (GNUNET_ERROR_TYPE_DEBUG, "Received IPv6 HELLO beacon broadcast with %i bytes from address %s\n", size, GNUNET_a2s ((const struct sockaddr *) &addr, addrlen)); -#endif struct Mstv6Context *mc; mc = GNUNET_malloc (sizeof (struct Mstv6Context)); @@ -216,7 +212,7 @@ udp_broadcast_receive (struct Plugin *plugin, const char * buf, ssize_t size, st mc->addr.u6_port = av6->sin6_port; ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen); mc->ats_address_network_type = ats.value; - + GNUNET_assert (NULL != plugin->broadcast_ipv4_mst); if (GNUNET_OK != GNUNET_SERVER_mst_receive (plugin->broadcast_ipv6_mst, mc, buf, size, GNUNET_NO, GNUNET_NO)) @@ -224,37 +220,42 @@ udp_broadcast_receive (struct Plugin *plugin, const char * buf, ssize_t size, st } } -static void -udp_ipv4_broadcast_send (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +static unsigned int +prepare_beacon (struct Plugin *plugin, struct UDP_Beacon_Message *msg) { - struct Plugin *plugin = cls; - int sent; - uint16_t msg_size; uint16_t hello_size; - char buf[65536]; + uint16_t msg_size; const struct GNUNET_MessageHeader *hello; - struct UDP_Beacon_Message *msg; - struct BroadcastAddress *baddr; - - plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_NO_TASK; - hello = plugin->env->get_our_hello (); hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello); msg_size = hello_size + sizeof (struct UDP_Beacon_Message); if (hello_size < (sizeof (struct GNUNET_MessageHeader)) || (msg_size > (UDP_MTU))) - return; + return 0; - msg = (struct UDP_Beacon_Message *) buf; msg->sender = *(plugin->env->my_identity); - msg->header.size = ntohs (msg_size); - msg->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON); + msg->header.size = htons (msg_size); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON); memcpy (&msg[1], hello, hello_size); - sent = 0; + return msg_size; +} + +static void +udp_ipv4_broadcast_send (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + int sent; + uint16_t msg_size; + char buf[65536] GNUNET_ALIGN; + struct BroadcastAddress *baddr; + + plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_NO_TASK; + msg_size = prepare_beacon(plugin, (struct UDP_Beacon_Message *) &buf); + sent = 0; baddr = plugin->ipv4_broadcast_head; /* just IPv4 */ while ((baddr != NULL) && (baddr->addrlen == sizeof (struct sockaddr_in))) @@ -263,19 +264,16 @@ udp_ipv4_broadcast_send (void *cls, addr->sin_port = htons (plugin->port); - sent = - GNUNET_NETWORK_socket_sendto (plugin->sockv4, msg, msg_size, + sent = GNUNET_NETWORK_socket_sendto (plugin->sockv4, &buf, msg_size, (const struct sockaddr *) addr, baddr->addrlen); if (sent == GNUNET_SYSERR) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto"); else { -#if DEBUG_UDP_BROADCASTING LOG (GNUNET_ERROR_TYPE_DEBUG, - "Sent HELLO beacon broadcast with %i bytes to address %s\n", sent, + "Sent HELLO beacon broadcast with %i bytes to address %s\n", sent, GNUNET_a2s (baddr->addr, baddr->addrlen)); -#endif } baddr = baddr->next; } @@ -292,31 +290,13 @@ udp_ipv6_broadcast_send (void *cls, struct Plugin *plugin = cls; int sent; uint16_t msg_size; - uint16_t hello_size; - char buf[65536]; - - const struct GNUNET_MessageHeader *hello; - struct UDP_Beacon_Message *msg; + char buf[65536] GNUNET_ALIGN; plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_NO_TASK; - hello = plugin->env->get_our_hello (); - hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello); - msg_size = hello_size + sizeof (struct UDP_Beacon_Message); - - if (hello_size < (sizeof (struct GNUNET_MessageHeader)) || - (msg_size > (UDP_MTU))) - return; - - msg = (struct UDP_Beacon_Message *) buf; - msg->sender = *(plugin->env->my_identity); - msg->header.size = ntohs (msg_size); - msg->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON); - memcpy (&msg[1], hello, hello_size); + msg_size = prepare_beacon(plugin, (struct UDP_Beacon_Message *) &buf); sent = 0; - - sent = - GNUNET_NETWORK_socket_sendto (plugin->sockv6, msg, msg_size, + sent = GNUNET_NETWORK_socket_sendto (plugin->sockv6, &buf, msg_size, (const struct sockaddr *) &plugin->ipv6_multicast_address, sizeof (struct sockaddr_in6)); @@ -324,16 +304,12 @@ udp_ipv6_broadcast_send (void *cls, GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto"); else { -#if DEBUG_UDP_BROADCASTING LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending IPv6 HELLO beacon broadcast with %i bytes to address %s\n", sent, GNUNET_a2s ((const struct sockaddr *) &plugin->ipv6_multicast_address, sizeof (struct sockaddr_in6))); -#endif } - - plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, &udp_ipv6_broadcast_send, plugin); @@ -349,7 +325,6 @@ iface_proc (void *cls, const char *name, int isDefault, if (addr != NULL) { -#if DEBUG_UDP_BROADCASTING GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "address %s for interface %s %p\n ", GNUNET_a2s (addr, addrlen), name, addr); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -357,7 +332,6 @@ iface_proc (void *cls, const char *name, int isDefault, GNUNET_a2s (broadcast_addr, addrlen), name, broadcast_addr); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "netmask %s for interface %s %p\n ", GNUNET_a2s (netmask, addrlen), name, netmask); -#endif /* Collecting broadcast addresses */ if (broadcast_addr != NULL) @@ -450,9 +424,7 @@ setup_broadcast (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struc } else { -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 broadcasting running\n"); -#endif plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_add_now (&udp_ipv6_broadcast_send, plugin); plugin->broadcast_ipv6 = GNUNET_YES; @@ -503,9 +475,7 @@ stop_broadcast (struct Plugin *plugin) } else { -#if DEBUG_UDP LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 Broadcasting stopped\n"); -#endif } if (plugin->send_ipv6_broadcast_task != GNUNET_SCHEDULER_NO_TASK) diff --git a/src/transport/plugin_transport_unix.c b/src/transport/plugin_transport_unix.c index 499cc23..057479d 100644 --- a/src/transport/plugin_transport_unix.c +++ b/src/transport/plugin_transport_unix.c @@ -42,9 +42,6 @@ #include "gnunet_transport_plugin.h" #include "transport.h" -#define DEBUG_UNIX GNUNET_EXTRALOGGING -#define DETAILS GNUNET_NO - #define MAX_PROBES 20 /* @@ -88,6 +85,13 @@ struct Session void *addr; size_t addrlen; struct GNUNET_PeerIdentity target; + + /** + * Session timeout task + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + struct Plugin * plugin; }; struct UNIXMessageWrapper @@ -188,12 +192,7 @@ struct Plugin */ struct GNUNET_TRANSPORT_PluginEnvironment *env; - /* - * Session of peers with whom we are currently connected - */ - struct PeerSession *sessions; - - /* + /** * Sessions */ struct GNUNET_CONTAINER_MultiHashMap *session_map; @@ -242,30 +241,167 @@ struct Plugin * ATS network */ struct GNUNET_ATS_Information ats_network; + + unsigned int bytes_in_queue; + unsigned int bytes_in_sent; + unsigned int bytes_in_recv; + unsigned int bytes_discarded; }; +/** + * Start session timeout + */ +static void +start_session_timeout (struct Session *s); -static int -get_session_delete_it (void *cls, const GNUNET_HashCode * key, void *value) +/** + * Increment session timeout due to activity + */ +static void +reschedule_session_timeout (struct Session *s); + +/** + * Cancel timeout + */ +static void +stop_session_timeout (struct Session *s); + + +static void +unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +static void +reschedule_select (struct Plugin * plugin) { - struct Session *s = value; - struct Plugin *plugin = cls; - GNUNET_assert (plugin != NULL); -#if DEBUG_UNIX - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting session for peer `%s' `%s' \n", GNUNET_i2s (&s->target), s->addr); -#endif + if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->select_task); + plugin->select_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (NULL != plugin->msg_head) + { + plugin->select_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs, + plugin->ws, + &unix_plugin_select, plugin); + plugin->with_ws = GNUNET_YES; + } + else + { + plugin->select_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs, + NULL, + &unix_plugin_select, plugin); + plugin->with_ws = GNUNET_NO; + } +} + +struct LookupCtx +{ + struct Session *s; + const struct sockaddr_un *addr; +}; + +int lookup_session_it (void *cls, + const GNUNET_HashCode * key, + void *value) +{ + struct LookupCtx *lctx = cls; + struct Session *t = value; + + if (0 == strcmp (t->addr, lctx->addr->sun_path)) + { + lctx->s = t; + return GNUNET_NO; + } + return GNUNET_YES; +} + +static struct Session * +lookup_session (struct Plugin *plugin, struct GNUNET_PeerIdentity *sender, const struct sockaddr_un *addr) +{ + struct LookupCtx lctx; + + GNUNET_assert (NULL != plugin); + GNUNET_assert (NULL != sender); + GNUNET_assert (NULL != addr); + + lctx.s = NULL; + lctx.addr = addr; + + GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &sender->hashPubKey, &lookup_session_it, &lctx); + + return lctx.s; +} + +/** + * Functions with this signature are called whenever we need + * to close a session due to a disconnect or failure to + * establish a connection. + * + * @param s session to close down + */ +static void +disconnect_session (struct Session *s) +{ + struct UNIXMessageWrapper *msgw; + struct UNIXMessageWrapper *next; + struct Plugin * plugin = s->plugin; + int removed; + GNUNET_assert (plugin != NULL); + GNUNET_assert (s != NULL); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting session for peer `%s' `%s' \n", GNUNET_i2s (&s->target), s->addr); + stop_session_timeout (s); plugin->env->session_end (plugin->env->cls, &s->target, s); + msgw = plugin->msg_head; + removed = GNUNET_NO; + next = plugin->msg_head; + while (NULL != next) + { + msgw = next; + next = msgw->next; + if (msgw->session != s) + continue; + GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw); + if (NULL != msgw->cont) + msgw->cont (msgw->cont_cls, &msgw->session->target, GNUNET_SYSERR); + GNUNET_free (msgw->msg); + GNUNET_free (msgw); + removed = GNUNET_YES; + } + if ((GNUNET_YES == removed) && (NULL == plugin->msg_head)) + reschedule_select (plugin); + GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove(plugin->session_map, &s->target.hashPubKey, s)); + GNUNET_CONTAINER_multihashmap_remove(plugin->session_map, &s->target.hashPubKey, s)); + + GNUNET_STATISTICS_set(plugin->env->stats, + "# UNIX sessions active", + GNUNET_CONTAINER_multihashmap_size(plugin->session_map), + GNUNET_NO); GNUNET_free (s); +} +static int +get_session_delete_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct Session *s = value; + disconnect_session (s); return GNUNET_YES; } + /** * Disconnect from a remote node. Clean up session if we have one for this peer * @@ -273,7 +409,7 @@ get_session_delete_it (void *cls, const GNUNET_HashCode * key, void *value) * @param target the peeridentity of the peer to disconnect * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed */ -void +static void unix_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { struct Plugin *plugin = cls; @@ -314,28 +450,14 @@ unix_transport_server_stop (void *cls) plugin->select_task = GNUNET_SCHEDULER_NO_TASK; } - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (plugin->unix_sock.desc)); - plugin->unix_sock.desc = NULL; - plugin->with_ws = GNUNET_NO; - 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 (NULL != plugin->unix_sock.desc) { - if (memcmp (&pos->target, peer, sizeof (struct GNUNET_PeerIdentity)) == 0) - return pos; - pos = pos->next; + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (plugin->unix_sock.desc)); + plugin->unix_sock.desc = NULL; + plugin->with_ws = GNUNET_NO; } - - return pos; + return GNUNET_OK; } @@ -369,7 +491,7 @@ unix_real_send (void *cls, size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { - + struct Plugin *plugin = cls; ssize_t sent; const void *sb; size_t sbs; @@ -377,34 +499,31 @@ unix_real_send (void *cls, size_t slen; int retry; + GNUNET_assert (NULL != plugin); + 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 */ + /* We do not have a send handle */ + GNUNET_break (0); if (cont != NULL) cont (cont_cls, target, GNUNET_SYSERR); - return 0; + return -1; } if ((addr == NULL) || (addrlen == 0)) { -#if DEBUG_UNIX - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "unix_real_send called without address, returning!\n"); -#endif + /* Can never send if we don't have an address */ + GNUNET_break (0); if (cont != NULL) cont (cont_cls, target, GNUNET_SYSERR); - return 0; /* Can never send if we don't have an address!! */ + return -1; } + /* Prepare address */ memset (&un, 0, sizeof (un)); un.sun_family = AF_UNIX; slen = strlen (addr) + 1; if (slen >= sizeof (un.sun_path)) slen = sizeof (un.sun_path) - 1; - sent = 0; GNUNET_assert (slen < sizeof (un.sun_path)); memcpy (un.sun_path, addr, slen); un.sun_path[slen] = '\0'; @@ -417,11 +536,17 @@ unix_real_send (void *cls, #endif sb = (struct sockaddr *) &un; sbs = slen; + + /* Send the data */ + sent = 0; retry = GNUNET_NO; sent = GNUNET_NETWORK_socket_sendto (send_handle, msgbuf, msgbuf_size, sb, sbs); if ((GNUNET_SYSERR == sent) && ((errno == EAGAIN) || (errno == ENOBUFS))) - retry = GNUNET_YES; + { + /* We have to retry later: retry */ + return 0; + } if ((GNUNET_SYSERR == sent) && (errno == EMSGSIZE)) { @@ -436,23 +561,38 @@ unix_real_send (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to increase socket buffer size from %i to %i for message size %i\n", - size, ((msgbuf_size / 1000) + 2) * 1000, msgbuf_size); + size, + ((msgbuf_size / 1000) + 2) * 1000, + msgbuf_size); size = ((msgbuf_size / 1000) + 2) * 1000; if (GNUNET_NETWORK_socket_setsockopt ((struct GNUNET_NETWORK_Handle *) send_handle, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) == GNUNET_OK) - retry = GNUNET_YES; + { + /* Increased buffer size, retry sending */ + return 0; + } else + { + /* Could not increase buffer size: error, no retry */ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt"); + return -1; + } + } + else + { + /* Buffer is bigger than message: error, no retry + * This should never happen!*/ + GNUNET_break (0); + return -1; } } -#if DEBUG_UNIX GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNIX transmit %u-byte message to %s (%d: %s)\n", (unsigned int) msgbuf_size, GNUNET_a2s (sb, sbs), (int) sent, (sent < 0) ? STRERROR (errno) : "ok"); -#endif + /* Calling continuation */ if (cont != NULL) { @@ -465,14 +605,20 @@ unix_real_send (void *cls, /* return number of bytes successfully sent */ if (sent > 0) return sent; + if (sent == 0) + { + /* That should never happen */ + GNUNET_break (0); + return -1; + } /* failed and retry: return 0 */ if ((GNUNET_SYSERR == sent) && (retry == GNUNET_YES)) return 0; /* failed and no retry: return -1 */ if ((GNUNET_SYSERR == sent) && (retry == GNUNET_NO)) return -1; - - return sent; + /* default */ + return -1; } struct gsi_ctx @@ -482,15 +628,14 @@ struct gsi_ctx struct Session *res; }; + static int get_session_it (void *cls, const GNUNET_HashCode * key, void *value) { struct gsi_ctx *gsi = cls; struct Session *s = value; -#if DEBUG_UNIX GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing session %s %s\n", gsi->address, s->addr); -#endif if ((gsi->addrlen == s->addrlen) && (0 == memcmp (gsi->address, s->addr, s->addrlen))) { @@ -527,27 +672,29 @@ unix_plugin_get_session (void *cls, GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &address->peer.hashPubKey, &get_session_it, &gsi); if (gsi.res != NULL) { -#if DEBUG_UNIX GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found existing session\n"); -#endif return gsi.res; } /* Create a new session */ - s = GNUNET_malloc (sizeof (struct Session) + address->address_length); s->addr = &s[1]; s->addrlen = address->address_length; + s->plugin = plugin; memcpy(s->addr, address->address, s->addrlen); memcpy(&s->target, &address->peer, sizeof (struct GNUNET_PeerIdentity)); + start_session_timeout (s); + GNUNET_CONTAINER_multihashmap_put (plugin->session_map, &address->peer.hashPubKey, s, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); -#if DEBUG_UNIX - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating new session\n"); -#endif + GNUNET_STATISTICS_set(plugin->env->stats, + "# UNIX sessions active", + GNUNET_CONTAINER_multihashmap_size(plugin->session_map), + GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating new session\n"); return s; } @@ -609,7 +756,11 @@ unix_plugin_send (void *cls, if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_contains_value(plugin->session_map, &session->target.hashPubKey, session)) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid session for peer `%s' `%s'\n", + GNUNET_i2s (&session->target), + (char *) session->addr); GNUNET_break (0); + return GNUNET_SYSERR; } @@ -621,6 +772,8 @@ unix_plugin_send (void *cls, sizeof (struct GNUNET_PeerIdentity)); memcpy (&message[1], msgbuf, msgbuf_size); + reschedule_session_timeout (session); + wrapper = GNUNET_malloc (sizeof (struct UNIXMessageWrapper)); wrapper->msg = message; wrapper->msgsize = ssize; @@ -632,24 +785,15 @@ unix_plugin_send (void *cls, GNUNET_CONTAINER_DLL_insert(plugin->msg_head, plugin->msg_tail, wrapper); -#if DEBUG_UNIX + plugin->bytes_in_queue += ssize; + GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes in send queue", + plugin->bytes_in_queue, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent %d bytes to `%s'\n", ssize, (char *) session->addr); -#endif - if (plugin->with_ws == GNUNET_NO) { - if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel(plugin->select_task); - - plugin->select_task = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, - GNUNET_TIME_UNIT_FOREVER_REL, - plugin->rs, - plugin->ws, - &unix_plugin_select, plugin); - plugin->with_ws = GNUNET_YES; + reschedule_select (plugin); } return ssize; } @@ -670,6 +814,8 @@ unix_demultiplexer (struct Plugin *plugin, struct GNUNET_PeerIdentity *sender, const struct sockaddr_un *un, size_t fromlen) { struct GNUNET_ATS_Information ats[2]; + struct Session *s = NULL; + struct GNUNET_HELLO_Address * addr; ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); ats[0].value = htonl (UNIX_DIRECT_DISTANCE); @@ -678,20 +824,30 @@ unix_demultiplexer (struct Plugin *plugin, struct GNUNET_PeerIdentity *sender, 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->bytes_in_recv += ntohs(currhdr->size); + GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes received", + plugin->bytes_in_recv, GNUNET_NO); + + addr = GNUNET_HELLO_address_allocate(sender, "unix", un->sun_path, strlen (un->sun_path) + 1); + s = lookup_session (plugin, sender, un); + if (NULL == s) + s = unix_plugin_get_session (plugin, addr); + reschedule_session_timeout (s); + plugin->env->receive (plugin->env->cls, sender, currhdr, (const struct GNUNET_ATS_Information *) &ats, 2, - NULL, un->sun_path, strlen (un->sun_path) + 1); + s, un->sun_path, strlen (un->sun_path) + 1); + GNUNET_free (addr); } static void unix_plugin_select_read (struct Plugin * plugin) { - char buf[65536]; + char buf[65536] GNUNET_ALIGN; struct UNIXMessage *msg; struct GNUNET_PeerIdentity sender; struct sockaddr_un un; @@ -723,10 +879,8 @@ unix_plugin_select_read (struct Plugin * plugin) #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)); @@ -752,14 +906,17 @@ unix_plugin_select_read (struct Plugin * plugin) GNUNET_break_op (0); break; } + unix_demultiplexer (plugin, &sender, currhdr, &un, sizeof (un)); offset += csize; } } + static void unix_plugin_select_write (struct Plugin * plugin) { + static int retry_counter; int sent = 0; struct UNIXMessageWrapper * msgw = plugin->msg_head; @@ -774,37 +931,69 @@ unix_plugin_select_write (struct Plugin * plugin) msgw->session->addrlen, msgw->cont, msgw->cont_cls); - /* successfully sent bytes */ - if (sent > 0) + if (sent == 0) + { + /* failed and retry */ + retry_counter++; + GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX retry attempt", + retry_counter, GNUNET_NO); + return; + } + + if (retry_counter > 0 ) + { + /* no retry: reset counter */ + retry_counter = 0; + GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX retry attempt", + retry_counter, GNUNET_NO); + } + + if (sent == -1) { + /* failed and no retry */ GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw); + + GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize); + plugin->bytes_in_queue -= msgw->msgsize; + GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes in send queue", + plugin->bytes_in_queue, GNUNET_NO); + plugin->bytes_discarded += msgw->msgsize; + GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes discarded", + plugin->bytes_discarded, GNUNET_NO); + GNUNET_free (msgw->msg); GNUNET_free (msgw); return; } - /* failed and no retry */ - if (sent == -1) + if (sent > 0) { + /* successfully sent bytes */ GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw); + + GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize); + plugin->bytes_in_queue -= msgw->msgsize; + GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes in send queue", + plugin->bytes_in_queue, GNUNET_NO); + plugin->bytes_in_sent += msgw->msgsize; + GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes sent", + plugin->bytes_in_sent, GNUNET_NO); + GNUNET_free (msgw->msg); GNUNET_free (msgw); return; } - /* failed and retry */ - if (sent == 0) - return; } -/* - * @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. * + * @param cls the plugin handle + * @param tc the scheduling context (for rescheduling this function again) */ static void unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) @@ -815,9 +1004,9 @@ unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; - plugin->with_ws = GNUNET_NO; if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) { + /* Ready to send data */ GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->unix_sock.desc)); if (plugin->msg_head != NULL) @@ -826,30 +1015,22 @@ unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0) { + /* Ready to receive data */ GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->unix_sock.desc)); unix_plugin_select_read (plugin); } - if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (plugin->select_task); - plugin->select_task = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, - GNUNET_TIME_UNIT_FOREVER_REL, - plugin->rs, - (plugin->msg_head != NULL) ? plugin->ws : NULL, - &unix_plugin_select, plugin); - if (plugin->msg_head != NULL) - plugin->with_ws = GNUNET_YES; + reschedule_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) { @@ -893,10 +1074,8 @@ unix_transport_server_start (void *cls) plugin->unix_sock.desc = NULL; return GNUNET_SYSERR; } -#if DEBUG_UNIX GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "unix", "Bound to `%s'\n", &un.sun_path[0]); -#endif plugin->rs = GNUNET_NETWORK_fdset_create (); plugin->ws = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_zero (plugin->rs); @@ -904,14 +1083,7 @@ unix_transport_server_start (void *cls) GNUNET_NETWORK_fdset_set (plugin->rs, plugin->unix_sock.desc); GNUNET_NETWORK_fdset_set (plugin->ws, 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); - plugin->with_ws = GNUNET_NO; + reschedule_select (plugin); return 1; } @@ -936,12 +1108,9 @@ unix_transport_server_start (void *cls) 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; } @@ -968,16 +1137,59 @@ unix_plugin_address_pretty_printer (void *cls, const char *type, GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls) { - if ((addr != NULL) && (addrlen > 0)) + if ((NULL != addr) && (addrlen > 0)) + { asc (asc_cls, (const char *) addr); + } else { GNUNET_break (0); - asc (asc_cls, "Invalid UNIX address"); + asc (asc_cls, "<invalid UNIX address>"); } + asc (asc_cls, NULL); +} + +/** + * Function called to convert a string address to + * a binary address. + * + * @param cls closure ('struct Plugin*') + * @param addr string address + * @param addrlen length of the address (strlen(addr) + '\0') + * @param buf location to store the buffer + * If the function returns GNUNET_SYSERR, its contents are undefined. + * @param added length of created address + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +static int +unix_string_to_address (void *cls, const char *addr, uint16_t addrlen, + void **buf, size_t *added) +{ + if ((NULL == addr) || (0 == addrlen)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if ('\0' != addr[addrlen - 1]) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (strlen (addr) != addrlen - 1) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + (*buf) = strdup (addr); + (*added) = strlen (addr) + 1; + return GNUNET_OK; } + /** * Function called for a quick conversion of the binary address to * a numeric address. Note that the caller must not free the @@ -994,10 +1206,10 @@ unix_address_to_string (void *cls, const void *addr, size_t addrlen) { if ((addr != NULL) && (addrlen > 0)) return (const char *) addr; - else - return NULL; + return NULL; } + /** * Notify transport service about address * @@ -1014,6 +1226,85 @@ address_notification (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) strlen (plugin->unix_socket_path) + 1); } + +/** + * Session was idle, so disconnect it + */ +static void +session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (NULL != cls); + struct Session *s = cls; + + s->timeout_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %p was idle for %llu, disconnecting\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + + /* call session destroy function */ + disconnect_session(s); + +} + +/** + * Start session timeout + */ +static void +start_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task); + + s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &session_timeout, + s); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p set to %llu\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); +} + +/** + * Increment session timeout due to activity + */ +static void +reschedule_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); + + GNUNET_SCHEDULER_cancel (s->timeout_task); + s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &session_timeout, + s); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p set to %llu\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); +} + +/** + * Cancel timeout + */ +static void +stop_session_timeout (struct Session *s) +{ + GNUNET_assert (NULL != s); + + if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) + { + GNUNET_SCHEDULER_cancel (s->timeout_task); + s->timeout_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p canceled\n", + s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p was not active\n", + s); + } +} + + /** * The exported method. Makes the core api available via a global and * returns the unix transport API. @@ -1027,6 +1318,19 @@ libgnunet_plugin_transport_unix_init (void *cls) struct Plugin *plugin; int sockets_created; + if (NULL == env->receive) + { + /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully + initialze the plugin or the API */ + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = NULL; + api->address_pretty_printer = &unix_plugin_address_pretty_printer; + api->address_to_string = &unix_address_to_string; + api->string_to_address = &unix_string_to_address; + return api; + } + GNUNET_assert( NULL != env->stats); + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-unix", "PORT", &port)) @@ -1046,6 +1350,7 @@ libgnunet_plugin_transport_unix_init (void *cls) api->address_pretty_printer = &unix_plugin_address_pretty_printer; api->address_to_string = &unix_address_to_string; api->check_address = &unix_check_address; + api->string_to_address = &unix_string_to_address; sockets_created = unix_transport_server_start (plugin); if (sockets_created == 0) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UNIX sockets\n")); @@ -1062,13 +1367,20 @@ libgnunet_plugin_transport_unix_done (void *cls) struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; + if (NULL == plugin) + { + GNUNET_free (api); + return NULL; + } unix_transport_server_stop (plugin); GNUNET_CONTAINER_multihashmap_iterate (plugin->session_map, &get_session_delete_it, plugin); GNUNET_CONTAINER_multihashmap_destroy (plugin->session_map); - GNUNET_NETWORK_fdset_destroy (plugin->rs); - GNUNET_NETWORK_fdset_destroy (plugin->ws); + if (NULL != plugin->rs) + GNUNET_NETWORK_fdset_destroy (plugin->rs); + if (NULL != plugin->ws) + GNUNET_NETWORK_fdset_destroy (plugin->ws); GNUNET_free (plugin->unix_socket_path); GNUNET_free (plugin); GNUNET_free (api); diff --git a/src/transport/plugin_transport_wlan.c b/src/transport/plugin_transport_wlan.c index 08f9c58..aed4b22 100644 --- a/src/transport/plugin_transport_wlan.c +++ b/src/transport/plugin_transport_wlan.c @@ -1,31 +1,29 @@ /* - This file is part of GNUnet - (C) 2010 2011 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. - */ + This file is part of GNUnet + (C) 2010, 2011, 2012 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_wlan.c * @brief transport plugin for wlan * @author David Brodski + * @author Christian Grothoff */ - -//TODO split rx and tx structures for better handling - #include "platform.h" #include "gnunet_hello_lib.h" #include "gnunet_protocols.h" @@ -39,1808 +37,756 @@ #include "gnunet_fragmentation_lib.h" #include "gnunet_constants.h" -/** - * DEBUG switch - */ -#define DEBUG_WLAN GNUNET_EXTRA_LOGGING - - -#define PROTOCOL_PREFIX "wlan" - -#define PLUGIN_LOG_NAME "wlan-plugin" +#define LOG(kind,...) GNUNET_log_from (kind, "transport-wlan",__VA_ARGS__) /** - * Max size of packet + * Max size of packet (that we give to the WLAN driver for transmission) */ #define WLAN_MTU 1430 /** - * time out of a session - */ -#define SESSION_TIMEOUT GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT - -/** * time out of a mac endpoint */ #define MACENDPOINT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2) /** - * scaling factor for hello beacon - */ -#define HELLO_BEACON_SCALING_FACTOR 30 - -/** - * scaling factor for restarting the helper - */ -#define HELPER_RESTART_SCALING_FACTOR 2 - -/** - * max size of fragment queue - */ -#define FRAGMENT_QUEUE_SIZE 10 -/** - * max messages in fragment queue per session/client + * We reduce the frequence of HELLO beacons in relation to + * the number of MAC addresses currently visible to us. + * This is the multiplication factor. */ -#define FRAGMENT_QUEUE_MESSAGES_OUT_PER_SESSION 1 +#define HELLO_BEACON_SCALING_FACTOR GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) /** - * max messages in fragment queue per MAC + * Maximum number of messages in defragmentation queue per MAC */ -#define FRAGMENT_QUEUE_MESSAGES_OUT_PER_MACENDPOINT 1 +#define MESSAGES_IN_DEFRAG_QUEUE_PER_MAC 2 /** - * max messages in in queue - */ -#define MESSAGES_IN_QUEUE_SIZE 10 -/** - * max messages in in queue per session/client - */ -#define MESSAGES_IN_DEFRAG_QUEUE_PER_MAC 1 - -/** - * LLC fields for better compatibility + * Link layer control fields for better compatibility + * (i.e. GNUnet over WLAN is not IP-over-WLAN). */ #define WLAN_LLC_DSAP_FIELD 0x1f #define WLAN_LLC_SSAP_FIELD 0x1f -#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ - -#define IEEE80211_FC0_VERSION_MASK 0x03 -#define IEEE80211_FC0_VERSION_SHIFT 0 -#define IEEE80211_FC0_VERSION_0 0x00 -#define IEEE80211_FC0_TYPE_MASK 0x0c -#define IEEE80211_FC0_TYPE_SHIFT 2 -#define IEEE80211_FC0_TYPE_MGT 0x00 -#define IEEE80211_FC0_TYPE_CTL 0x04 -#define IEEE80211_FC0_TYPE_DATA 0x08 - GNUNET_NETWORK_STRUCT_BEGIN - -/* - * generic definitions for IEEE 802.11 frames - */ -struct ieee80211_frame -{ - u_int8_t i_fc[2]; - u_int8_t i_dur[2]; - u_int8_t i_addr1[IEEE80211_ADDR_LEN]; - u_int8_t i_addr2[IEEE80211_ADDR_LEN]; - u_int8_t i_addr3[IEEE80211_ADDR_LEN]; - u_int8_t i_seq[2]; - u_int8_t llc[4]; -} GNUNET_PACKED; -GNUNET_NETWORK_STRUCT_END - /** - * Encapsulation of all of the state of the plugin. + * Header for messages which need fragmentation. This is the format of + * a message we obtain AFTER defragmentation. We then need to check + * the CRC and then tokenize the payload and pass it to the + * 'receive' callback. */ -struct Plugin +struct WlanHeader { - /** - * Our environment. - */ - struct GNUNET_TRANSPORT_PluginEnvironment *env; - - /** - * List of open connections. head - */ - struct MacEndpoint *mac_head; - - /** - * List of open connections. tail - */ - struct MacEndpoint *mac_tail; - - /** - * Number of connections - */ - unsigned int mac_count; - - /** - * encapsulation of data from the local wlan helper program - */ - struct GNUNET_SERVER_MessageStreamTokenizer *suid_tokenizer; /** - * encapsulation of packets received from the wlan helper + * Message type is GNUNET_MESSAGE_TYPE_WLAN_DATA. */ - struct GNUNET_SERVER_MessageStreamTokenizer *data_tokenizer; + struct GNUNET_MessageHeader header; /** - * stdout pipe handle for the gnunet-helper-transport-wlan process + * CRC32 checksum (only over the payload), in NBO. */ - struct GNUNET_DISK_PipeHandle *server_stdout; + uint32_t crc GNUNET_PACKED; /** - * stdout file handle for the gnunet-helper-transport-wlan process + * Sender of the message. */ - const struct GNUNET_DISK_FileHandle *server_stdout_handle; + struct GNUNET_PeerIdentity sender; /** - * stdin pipe handle for the gnunet-helper-transport-wlan process + * Target of the message. */ - struct GNUNET_DISK_PipeHandle *server_stdin; + struct GNUNET_PeerIdentity target; - /** - * stdin file handle for the gnunet-helper-transport-wlan process - */ - const struct GNUNET_DISK_FileHandle *server_stdin_handle; + /* followed by payload, possibly including + multiple messages! */ - /** - * ID of the gnunet-wlan-server std read task - */ - GNUNET_SCHEDULER_TaskIdentifier server_read_task; +}; +GNUNET_NETWORK_STRUCT_END - /** - * ID of the gnunet-wlan-server std read task - */ - GNUNET_SCHEDULER_TaskIdentifier server_write_task; +/** + * Information kept for each message that is yet to be fragmented and + * transmitted. + */ +struct PendingMessage +{ /** - * ID of the delay task for writing + * next entry in the DLL */ - GNUNET_SCHEDULER_TaskIdentifier server_write_delay_task; + struct PendingMessage *next; /** - * The process id of the wlan process + * previous entry in the DLL */ - struct GNUNET_OS_Process *server_proc; + struct PendingMessage *prev; /** - * The interface of the wlan card given to us by the user. + * The pending message */ - char *interface; + struct WlanHeader *msg; /** - * Mode of operation for the helper, 0 = normal, 1 = first loopback, 2 = second loopback + * Continuation function to call once the message + * has been sent. Can be NULL if there is no + * continuation to call. */ - long long unsigned int testmode; + GNUNET_TRANSPORT_TransmitContinuation transmit_cont; /** - * The mac_address of the wlan card given to us by the helper. + * Cls for transmit_cont */ - struct GNUNET_TRANSPORT_WLAN_MacAddress mac_address; + void *transmit_cont_cls; /** - * Sessions currently pending for transmission - * to a peer, if any. + * Timeout task (for this message). */ - struct Sessionqueue *pending_Sessions_head; + GNUNET_SCHEDULER_TaskIdentifier timeout_task; - /** - * Sessions currently pending for transmission - * to a peer (tail), if any. - */ - struct Sessionqueue *pending_Sessions_tail; +}; - /** - * number of pending sessions - */ - unsigned int pendingsessions; - /** - * Messages in the sending queues - */ - int pending_Fragment_Messages; +/** + * Session handle for connections with other peers. + */ +struct Session +{ /** - * messages ready for send, head - */ - struct FragmentMessage_queue *sending_messages_head; - /** - * messages ready for send, tail - */ - struct FragmentMessage_queue *sending_messages_tail; - /** - * time of the next "hello-beacon" + * API requirement (must be first). */ - struct GNUNET_TIME_Absolute beacon_time; + struct SessionHeader header; /** - * queue to send acks for received fragments (head) + * We keep all sessions in a DLL at their respective + * 'struct MACEndpoint'. */ - struct AckSendQueue *ack_send_queue_head; + struct Session *next; /** - * queue to send acks for received fragments (tail) + * We keep all sessions in a DLL at their respective + * 'struct MACEndpoint'. */ - struct AckSendQueue *ack_send_queue_tail; + struct Session *prev; /** - * Tracker for bandwidth limit + * MAC endpoint with the address of this peer. */ - struct GNUNET_BANDWIDTH_Tracker tracker; + struct MacEndpoint *mac; /** - * saves the current state of the helper process + * Head of messages currently pending for transmission to this peer. */ - int helper_is_running; -}; + struct PendingMessage *pending_message_head; -/** - * Struct to store data if file write did not accept the whole packet - */ -struct Finish_send -{ /** - * pointer to the global plugin struct + * Tail of messages currently pending for transmission to this peer. */ - struct Plugin *plugin; + struct PendingMessage *pending_message_tail; /** - * head of the next part to send to the helper + * To whom are we talking to (set to our identity + * if we are still waiting for the welcome message) */ - char *head_of_next_write; + struct GNUNET_PeerIdentity target; /** - * Start of the message to send, needed for free + * When should this session time out? */ - struct GNUNET_MessageHeader *msgstart; + struct GNUNET_TIME_Absolute timeout; /** - * rest size to send + * Timeout task (for the session). */ - ssize_t size; -}; - -/** - * Queue of sessions, for the general session queue and the pending session queue - */ -//TODO DOXIGEN -struct Sessionqueue -{ - struct Sessionqueue *next; - struct Sessionqueue *prev; - struct Session *content; -#if !HAVE_UNALIGNED_64_ACCESS - void *dummy; /* for alignment, see #1909 */ -#endif -}; - -/** - * Queue of fragmented messages, for the sending queue of the plugin - */ -//TODO DOXIGEN -struct FragmentMessage_queue -{ - struct FragmentMessage_queue *next; - struct FragmentMessage_queue *prev; - struct FragmentMessage *content; -}; - -/** - * Queue for the fragments received - */ -//TODO DOXIGEN -struct Receive_Fragment_Queue -{ - struct Receive_Fragment_Queue *next; - struct Receive_Fragment_Queue *prev; - uint16_t num; - const char *msg; - uint16_t size; - struct Radiotap_rx rxinfo; -}; - -//TODO DOXIGEN -struct MacEndpoint_id_fragment_triple -{ - struct MacEndpoint *endpoint; - uint32_t message_id; - struct FragmentMessage *fm; -}; + GNUNET_SCHEDULER_TaskIdentifier timeout_task; -//TODO DOXIGEN -struct Plugin_Session_pair -{ - struct Plugin *plugin; - struct Session *session; }; -GNUNET_NETWORK_STRUCT_BEGIN - /** - * Header for messages which need fragmentation + * Struct for messages that are being fragmented in a MAC's transmission queue. */ -struct WlanHeader +struct FragmentMessage { - struct GNUNET_MessageHeader header; - /** - * checksum/error correction + * This is a doubly-linked list. */ - uint32_t crc GNUNET_PACKED; + struct FragmentMessage *next; /** - * To whom are we talking to (set to our identity - * if we are still waiting for the welcome message) + * This is a doubly-linked list. */ - struct GNUNET_PeerIdentity target; + struct FragmentMessage *prev; /** - * Where the packet came from + * MAC endpoint this message belongs to */ - struct GNUNET_PeerIdentity source; - -// followed by payload - -}; -GNUNET_NETWORK_STRUCT_END + struct MacEndpoint *macendpoint; -/** - * Information kept for each message that is yet to - * be transmitted. - */ -struct PendingMessage -{ /** - * dll next + * Fragmentation context */ - struct PendingMessage *next; + struct GNUNET_FRAGMENT_Context *fragcontext; + /** - * dll prev + * Transmission handle to helper (to cancel if the frag context + * is destroyed early for some reason). */ - struct PendingMessage *prev; + struct GNUNET_HELPER_SendHandle *sh; /** - * The pending message + * Intended recipient. */ - struct WlanHeader *msg; + struct GNUNET_PeerIdentity target; /** - * Size of the message + * Timeout value for the message. */ - size_t message_size; + struct GNUNET_TIME_Absolute timeout; /** - * Continuation function to call once the message - * has been sent. Can be NULL if there is no - * continuation to call. + * Timeout task. */ - GNUNET_TRANSPORT_TransmitContinuation transmit_cont; + GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** - * Cls for transmit_cont + * Continuation to call when we're done with this message. */ - void *transmit_cont_cls; + GNUNET_TRANSPORT_TransmitContinuation cont; /** - * Timeout value for the pending message. + * Closure for 'cont' */ - struct GNUNET_TIME_Absolute timeout; + void *cont_cls; }; + /** - * Queue for acks to send for fragments recived + * Struct to represent one network card connection */ -struct AckSendQueue +struct MacEndpoint { /** - * next ack in the ack send queue + * We keep all MACs in a DLL in the plugin. */ - struct AckSendQueue *next; - /** - * previous ack in the ack send queue - */ - struct AckSendQueue *prev; - /** - * pointer to the session this ack belongs to - */ - struct MacEndpoint *endpoint; - /** - * ID of message, to distinguish between the messages, picked randomly. - */ - uint32_t message_id; + struct MacEndpoint *next; /** - * msg to send + * We keep all MACs in a DLL in the plugin. */ - struct GNUNET_MessageHeader *hdr; - /** - * pointer to the ieee wlan header - */ - struct ieee80211_frame *ieeewlanheader; + struct MacEndpoint *prev; + /** - * pointer to the radiotap header + * Pointer to the global plugin struct. */ - struct Radiotap_Send *radioHeader; -}; + struct Plugin *plugin; -/** - * Session infos gathered from a messages - */ -struct Session_light -{ /** - * the session this message belongs to + * Head of sessions that use this MAC. */ - struct Session *session; + struct Session *sessions_head; + /** - * peer mac address + * Tail of sessions that use this MAC. */ - struct GNUNET_TRANSPORT_WLAN_MacAddress addr; + struct Session *sessions_tail; /** - * mac endpoint + * Head of messages we are currently sending to this MAC. */ - struct MacEndpoint *macendpoint; -}; - -/** - * Session handle for connections. - */ -struct Session -{ + struct FragmentMessage *sending_messages_head; /** - * API requirement. + * Tail of messages we are currently sending to this MAC. */ - struct SessionHeader header; + struct FragmentMessage *sending_messages_tail; /** - * Message currently pending for transmission - * to this peer, if any. head + * Defrag context for this MAC */ - struct PendingMessage *pending_message_head; + struct GNUNET_DEFRAGMENT_Context *defrag; /** - * Message currently pending for transmission - * to this peer, if any. tail + * When should this endpoint time out? */ - struct PendingMessage *pending_message_tail; + struct GNUNET_TIME_Absolute timeout; /** - * To whom are we talking to (set to our identity - * if we are still waiting for the welcome message) + * Timeout task. */ - struct GNUNET_PeerIdentity target; + GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** - * Address of the other peer (either based on our 'connect' - * call or on our 'accept' call). + * count of messages in the fragment out queue for this mac endpoint */ - void *connect_addr; + unsigned int fragment_messages_out_count; /** - * Last activity on this connection. Used to select preferred - * connection and timeout + * peer mac address */ - struct GNUNET_TIME_Absolute last_activity; + struct GNUNET_TRANSPORT_WLAN_MacAddress addr; /** - * Timeout task. + * Desired transmission power for this MAC */ - GNUNET_SCHEDULER_TaskIdentifier timeout_task; + uint16_t tx_power; /** - * peer connection + * Desired transmission rate for this MAC */ - struct MacEndpoint *mac; + uint8_t rate; /** - * count of messages in the fragment out queue for this session + * Antenna we should use for this MAC */ - - int fragment_messages_out_count; + uint8_t antenna; }; + /** - * Struct to represent one network card connection + * Encapsulation of all of the state of the plugin. */ -struct MacEndpoint +struct Plugin { /** - * Pointer to the global plugin struct. - */ - struct Plugin *plugin; - /** - * Struct to hold the session reachable over this mac; head - */ - struct Sessionqueue *sessions_head; - /** - * Struct to hold the session reachable over this mac; tail - */ - struct Sessionqueue *sessions_tail; - /** - * Messages currently sending - * to a peer, if any. + * Our environment. */ - struct FragmentMessage *sending_messages_head; + struct GNUNET_TRANSPORT_PluginEnvironment *env; /** - * Messages currently sending - * to a peer (tail), if any. - */ - struct FragmentMessage *sending_messages_tail; - /** - * dll next - */ - struct MacEndpoint *next; - /** - * dll prev - */ - struct MacEndpoint *prev; + * Handle to helper process for priviledged operations. + */ + struct GNUNET_HELPER_Handle *suid_helper; /** - * peer mac address + * ARGV-vector for the helper (all helpers take only the binary + * name, one actual argument, plus the NULL terminator for 'argv'). */ - struct GNUNET_TRANSPORT_WLAN_MacAddress addr; + char * helper_argv[3]; /** - * Defrag context for this mac endpoint + * The interface of the wlan card given to us by the user. */ - struct GNUNET_DEFRAGMENT_Context *defrag; + char *interface; /** - * count of messages in the fragment out queue for this mac endpoint + * Tokenizer for demultiplexing of data packets resulting from defragmentation. */ - - int fragment_messages_out_count; - - //TODO DOXIGEN - uint8_t rate; - uint16_t tx_power; - uint8_t antenna; + struct GNUNET_SERVER_MessageStreamTokenizer *fragment_data_tokenizer; /** - * Duplicates received + * Tokenizer for demultiplexing of data packets received from the suid helper */ - int dups; + struct GNUNET_SERVER_MessageStreamTokenizer *helper_payload_tokenizer; /** - * Fragments received + * Tokenizer for demultiplexing of data packets that follow the WLAN Header */ - int fragc; + struct GNUNET_SERVER_MessageStreamTokenizer *wlan_header_payload_tokenizer; /** - * Acks received + * Head of list of open connections. */ - int acks; + struct MacEndpoint *mac_head; /** - * Last activity on this endpoint. Used to select preferred - * connection. + * Tail of list of open connections. */ - struct GNUNET_TIME_Absolute last_activity; + struct MacEndpoint *mac_tail; /** - * Timeout task. + * Number of connections */ - GNUNET_SCHEDULER_TaskIdentifier timeout_task; -}; - -/** - * Struct for Messages in the fragment queue - */ -struct FragmentMessage -{ + unsigned int mac_count; /** - * Session this message belongs to + * Task that periodically sends a HELLO beacon via the helper. */ - struct Session *session; + GNUNET_SCHEDULER_TaskIdentifier beacon_task; /** - * This is a doubly-linked list. + * Tracker for bandwidth limit */ - struct FragmentMessage *next; + struct GNUNET_BANDWIDTH_Tracker tracker; /** - * This is a doubly-linked list. + * The mac_address of the wlan card given to us by the helper. */ - struct FragmentMessage *prev; + struct GNUNET_TRANSPORT_WLAN_MacAddress mac_address; /** - * Fragmentation context + * Have we received a control message with our MAC address yet? */ - struct GNUNET_FRAGMENT_Context *fragcontext; + int have_mac; - /** - * Timeout value for the message. - */ - struct GNUNET_TIME_Absolute timeout; - /** - * Timeout task. - */ - GNUNET_SCHEDULER_TaskIdentifier timeout_task; +}; - /** - * Fragment to send - */ - char *frag; +/** + * Information associated with a message. Can contain + * the session or the MAC endpoint associated with the + * message (or both). + */ +struct MacAndSession +{ /** - * size of message + * NULL if the identity of the other peer is not known. */ - size_t size; + struct Session *session; /** - * pointer to the ieee wlan header + * MAC address of the other peer, NULL if not known. */ - struct ieee80211_frame *ieeewlanheader; - /** - * pointer to the radiotap header - */ - struct Radiotap_Send *radioHeader; + struct MacEndpoint *endpoint; }; -static void -do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - -static void -free_session (struct Plugin *plugin, struct Sessionqueue *queue, - int do_free_macendpoint); - -static struct MacEndpoint * -create_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr); - -static void -finish_sending (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** - * Generates a nice hexdump of a memory area. + * Print MAC addresses nicely. * - * \param mem pointer to memory to dump - * \param length how many bytes to dump - */ -static void -hexdump (const void *mem, unsigned length) -{ - char line[80]; - char *src = (char *) mem; - - printf ("dumping %u bytes from %p\r\n" - " 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF\r\n", - length, src); - unsigned i; - int j; - - for (i = 0; i < length; i += 16, src += 16) - { - char *t = line; - - t += sprintf (t, "%04x: ", i); - for (j = 0; j < 16; j++) - { - if (i + j < length) - t += sprintf (t, "%02X", src[j] & 0xff); - else - t += sprintf (t, " "); - - t += sprintf (t, (j % 2) ? " " : "-"); - } - - t += sprintf (t, " "); - for (j = 0; j < 16; j++) - { - if (i + j < length) - { - if (isprint ((unsigned char) src[j])) - t += sprintf (t, "%c", src[j]); - else - t += sprintf (t, "."); - } - else - { - t += sprintf (t, " "); - } - } - - t += sprintf (t, "\r\n"); - printf ("%s", line); - } -} - -/** - * Function to find a MacEndpoint with a specific mac addr - * @param plugin pointer to the plugin struct - * @param addr pointer to the mac address - * @param create_new GNUNET_YES if a new end point should be created - * @return + * @param mac the mac address + * @return string to a static buffer with the human-readable mac, will be overwritten during the next call to this function */ -static struct MacEndpoint * -get_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr, - int create_new) +static const char * +mac_to_string (const struct GNUNET_TRANSPORT_WLAN_MacAddress * mac) { - struct MacEndpoint *queue = plugin->mac_head; - - while (queue != NULL) - { - //GNUNET_assert (queue->sessions_head != NULL); - if (memcmp (addr, &queue->addr, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0) - return queue; /* session found */ - queue = queue->next; - } - - if (create_new == GNUNET_YES) - { - return create_macendpoint (plugin, addr); - } - else - { - return NULL; - } + static char macstr[20]; + GNUNET_snprintf (macstr, sizeof (macstr), "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", mac->mac[0], mac->mac[1], + mac->mac[2], mac->mac[3], mac->mac[4], mac->mac[5]); + return macstr; } -/** - * search for a session with the macendpoint and peer id - * - * @param plugin pointer to the plugin struct - * @param endpoint pointer to the mac endpoint of the peer - * @param peer pointer to the peerid - * @return returns the session - */ -static struct Session * -search_session (struct Plugin *plugin, const struct MacEndpoint *endpoint, - const struct GNUNET_PeerIdentity *peer) -{ - GNUNET_assert (endpoint != NULL); - struct Sessionqueue *queue = endpoint->sessions_head; - - while (queue != NULL) - { - GNUNET_assert (queue->content != NULL); - if (memcmp - (peer, &queue->content->target, - sizeof (struct GNUNET_PeerIdentity)) == 0) - return queue->content; /* session found */ - queue = queue->next; - } - return NULL; -} /** - * 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. + * Fill the radiotap header * - * @param cls closure - * @param addr binary address - * @param addrlen length of the address - * @return string representing the same address - */ -static const char * -wlan_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) -{ - static char ret[40]; - const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac; - - if (addrlen != sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) - { - GNUNET_break (0); - return NULL; - } - mac = addr; - GNUNET_snprintf (ret, sizeof (ret), "%s Mac-Address %X:%X:%X:%X:%X:%X", - PROTOCOL_PREFIX, mac->mac[0], mac->mac[1], mac->mac[2], - mac->mac[3], mac->mac[4], mac->mac[5]); - - return ret; -} - -/** - * Function for the scheduler if a session times out - * @param cls pointer to the Sessionqueue - * @param tc pointer to the GNUNET_SCHEDULER_TaskContext + * @param endpoint pointer to the endpoint, can be NULL + * @param header pointer to the radiotap header + * @param size total message size */ static void -session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +get_radiotap_header (struct MacEndpoint *endpoint, + struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header, + uint16_t size) { - struct Sessionqueue *queue = cls; - - GNUNET_assert (queue != NULL); - GNUNET_assert (queue->content != NULL); - queue->content->timeout_task = GNUNET_SCHEDULER_NO_TASK; - if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) + header->header.type = ntohs (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER); + header->header.size = ntohs (size); + if (NULL != endpoint) { - return; - } - if (GNUNET_TIME_absolute_get_remaining - (GNUNET_TIME_absolute_add - (queue->content->last_activity, SESSION_TIMEOUT)).rel_value == 0) - { - - GNUNET_assert (queue->content->mac != NULL); - GNUNET_assert (queue->content->mac->plugin != NULL); - GNUNET_STATISTICS_update (queue->content->mac->plugin->env->stats, - _("# wlan session timeouts"), 1, GNUNET_NO); - free_session (queue->content->mac->plugin, queue, GNUNET_YES); + header->rate = endpoint->rate; + header->tx_power = endpoint->tx_power; + header->antenna = endpoint->antenna; } else { - queue->content->timeout_task = - GNUNET_SCHEDULER_add_delayed (SESSION_TIMEOUT, &session_timeout, queue); + header->rate = 255; + header->tx_power = 0; + header->antenna = 0; } } -/** - * create a new session - * - * @param plugin pointer to the plugin struct - * @param endpoint pointer to the mac endpoint of the peer - * @param peer peer identity to use for this session - * @return returns the session - */ -static struct Session * -create_session (struct Plugin *plugin, struct MacEndpoint *endpoint, - const struct GNUNET_PeerIdentity *peer) -{ - GNUNET_assert (endpoint != NULL); - GNUNET_assert (plugin != NULL); - GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan session created"), 1, - GNUNET_NO); - struct Sessionqueue *queue = - GNUNET_malloc (sizeof (struct Sessionqueue) + sizeof (struct Session)); - - GNUNET_CONTAINER_DLL_insert_tail (endpoint->sessions_head, - endpoint->sessions_tail, queue); - - queue->content = (struct Session *) &queue[1]; - queue->content->mac = endpoint; - queue->content->target = *peer; - queue->content->last_activity = GNUNET_TIME_absolute_get (); - queue->content->timeout_task = - GNUNET_SCHEDULER_add_delayed (SESSION_TIMEOUT, &session_timeout, queue); - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "New session %p with endpoint %p: %s\n", queue->content, - endpoint, wlan_plugin_address_to_string (NULL, - endpoint->addr.mac, - 6)); - return queue->content; -} /** - * Get session from address, create if no session exists + * Generate the WLAN hardware header for one packet * - * @param plugin pointer to the plugin struct - * @param addr pointer to the mac address of the peer - * @param peer pointer to the peerid - * @return returns the session - */ -static struct Session * -get_session (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr, - const struct GNUNET_PeerIdentity *peer) -{ - struct MacEndpoint *mac; - - mac = get_macendpoint (plugin, addr, GNUNET_YES); - struct Session *session = search_session (plugin, mac, peer); - - if (session != NULL) - return session; - return create_session (plugin, mac, peer); -} - -/** - * Queue the session to send data - * checks if there is a message pending - * checks if this session is not allready in the queue - * @param plugin pointer to the plugin - * @param session pointer to the session to add + * @param plugin the plugin handle + * @param header address to write the header to + * @param to_mac_addr address of the recipient + * @param size size of the whole packet, needed to calculate the time to send the packet */ static void -queue_session (struct Plugin *plugin, struct Session *session) +get_wlan_header (struct Plugin *plugin, + struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *header, + const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr, + unsigned int size) { - struct Sessionqueue *queue = plugin->pending_Sessions_head; - - if (session->pending_message_head != NULL) - { - while (queue != NULL) - { - // content is never NULL - GNUNET_assert (queue->content != NULL); - // is session already in queue? - if (session == queue->content) - { - return; - } - // try next - queue = queue->next; - } - - // Session is not in the queue - - queue = GNUNET_malloc (sizeof (struct Sessionqueue)); - queue->content = session; - - //insert at the tail - GNUNET_CONTAINER_DLL_insert_tail (plugin->pending_Sessions_head, - plugin->pending_Sessions_tail, queue); - plugin->pendingsessions++; - GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), - plugin->pendingsessions, GNUNET_NO); - } + const int rate = 11000000; + header->frame_control = htons (IEEE80211_FC0_TYPE_DATA); + header->addr1 = *to_mac_addr; + header->addr2 = plugin->mac_address; + header->addr3 = mac_bssid_gnunet; + header->duration = GNUNET_htole16 ((size * 1000000) / rate + 290); + header->sequence_control = 0; // FIXME? + header->llc[0] = WLAN_LLC_DSAP_FIELD; + header->llc[1] = WLAN_LLC_SSAP_FIELD; + header->llc[2] = 0; // FIXME? + header->llc[3] = 0; // FIXME? } + /** - * Function to schedule the write task, executed after a delay - * @param cls pointer to the plugin struct - * @param tc GNUNET_SCHEDULER_TaskContext pointer + * Send an ACK for a fragment we received. + * + * @param cls the 'struct MacEndpoint' the ACK must be sent to + * @param msg_id id of the message + * @param hdr pointer to the hdr where the ack is stored */ static void -delay_fragment_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +send_ack (void *cls, uint32_t msg_id, + const struct GNUNET_MessageHeader *hdr) { - struct Plugin *plugin = cls; - - plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK; - - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; + struct MacEndpoint *endpoint = cls; + struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage* radio_header; + uint16_t msize = ntohs (hdr->size); + size_t size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + msize; + char buf[size]; - // GNUNET_TIME_UNIT_FOREVER_REL is needed to clean up old msg - if (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK) + if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { - plugin->server_write_task = - GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdin_handle, - &do_transmit, plugin); + GNUNET_break (0); + return; } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending ACK to helper\n"); + radio_header = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) buf; + get_radiotap_header (endpoint, radio_header, size); + get_wlan_header (endpoint->plugin, + &radio_header->frame, + &endpoint->addr, + size); + memcpy (&radio_header[1], hdr, msize); + if (NULL != + GNUNET_HELPER_send (endpoint->plugin->suid_helper, + &radio_header->header, + GNUNET_NO /* dropping ACKs is bad */, + NULL, NULL)) + GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN ACKs sent"), + 1, GNUNET_NO); } -/** - * Function to calculate the time of the next periodic "hello-beacon" - * @param plugin pointer to the plugin struct - */ -static void -set_next_beacon_time (struct Plugin *const plugin) -{ - //under 10 known peers: once a second - if (plugin->mac_count < 10) - { - plugin->beacon_time = - GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - HELLO_BEACON_SCALING_FACTOR)); - } - //under 30 known peers: every 10 seconds - else if (plugin->mac_count < 30) - { - plugin->beacon_time = - GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - 10 * HELLO_BEACON_SCALING_FACTOR)); - } - //over 30 known peers: once a minute - else - { - plugin->beacon_time = - GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MINUTES, - HELLO_BEACON_SCALING_FACTOR)); - } -} /** - * Function to set the timer for the next timeout of the fragment queue - * @param plugin the handle to the plugin struct + * Handles the data after all fragments are put together + * + * @param cls macendpoint this messages belongs to + * @param hdr pointer to the data */ static void -set_next_send (struct Plugin *const plugin) +wlan_data_message_handler (void *cls, const struct GNUNET_MessageHeader *hdr) { - struct GNUNET_TIME_Relative next_send; - - //abort if helper is not running - if (plugin->helper_is_running == GNUNET_NO) - { - return; - } - - //cancel old task - if (plugin->server_write_delay_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (plugin->server_write_delay_task); - plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK; - } - - //check if some acks are in the queue - if (plugin->ack_send_queue_head != NULL) - { - next_send = GNUNET_TIME_UNIT_ZERO; - } - - //check if there are some fragments in the queue - else if (plugin->sending_messages_head != NULL) - { - next_send = GNUNET_TIME_UNIT_ZERO; - } - else - { - next_send = GNUNET_TIME_absolute_get_remaining (plugin->beacon_time); - } + struct MacEndpoint *endpoint = cls; + struct Plugin *plugin = endpoint->plugin; + struct MacAndSession mas; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Next packet is send in: %u\n", next_send.rel_value); - if (next_send.rel_value == GNUNET_TIME_UNIT_ZERO.rel_value) - { - if (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK) - { - plugin->server_write_task = - GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdin_handle, - &do_transmit, plugin); - } - } - else - { - if (plugin->server_write_delay_task == GNUNET_SCHEDULER_NO_TASK) - { - plugin->server_write_delay_task = - GNUNET_SCHEDULER_add_delayed (next_send, &delay_fragment_task, - plugin); - } - } + GNUNET_STATISTICS_update (plugin->env->stats, + _("# WLAN messages defragmented"), 1, + GNUNET_NO); + mas.session = NULL; + mas.endpoint = endpoint; + (void) GNUNET_SERVER_mst_receive (plugin->fragment_data_tokenizer, + &mas, + (const char *) hdr, + ntohs (hdr->size), + GNUNET_YES, GNUNET_NO); } -/** - * Function to get the next queued Session, removes the session from the queue - * @param plugin pointer to the plugin struct - * @return pointer to the session found, returns NULL if there is now session in the queue - */ -static struct Session * -get_next_queue_session (struct Plugin *plugin) -{ - struct Session *session; - struct Sessionqueue *sessionqueue; - struct Sessionqueue *sessionqueue_alt; - struct PendingMessage *pm; - - sessionqueue = plugin->pending_Sessions_head; - - while (sessionqueue != NULL) - { - session = sessionqueue->content; - - GNUNET_assert (session != NULL); - pm = session->pending_message_head; - - if (pm == NULL) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, - "pending message is empty, should not happen. session %p\n", - session); - sessionqueue_alt = sessionqueue; - sessionqueue = sessionqueue->next; - plugin->pendingsessions--; - GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), - plugin->pendingsessions, GNUNET_NO); - GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head, - plugin->pending_Sessions_tail, - sessionqueue_alt); - - GNUNET_free (sessionqueue_alt); - continue; - - } - - //check for message timeout - if (GNUNET_TIME_absolute_get_remaining (pm->timeout).rel_value > 0) - { - //check if session has no message in the fragment queue - if ((session->mac->fragment_messages_out_count < - FRAGMENT_QUEUE_MESSAGES_OUT_PER_MACENDPOINT) && - (session->fragment_messages_out_count < - FRAGMENT_QUEUE_MESSAGES_OUT_PER_SESSION)) - { - plugin->pendingsessions--; - GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), - plugin->pendingsessions, GNUNET_NO); - GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head, - plugin->pending_Sessions_tail, - sessionqueue); - GNUNET_free (sessionqueue); - - return session; - } - else - { - sessionqueue = sessionqueue->next; - } - } - else - { - GNUNET_CONTAINER_DLL_remove (session->pending_message_head, - session->pending_message_tail, pm); - - //call the cont func that it did not work - if (pm->transmit_cont != NULL) - pm->transmit_cont (pm->transmit_cont_cls, &(session->target), - GNUNET_SYSERR); - GNUNET_free (pm->msg); - GNUNET_free (pm); - - if (session->pending_message_head == NULL) - { - sessionqueue_alt = sessionqueue; - sessionqueue = sessionqueue->next; - plugin->pendingsessions--; - GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), - plugin->pendingsessions, GNUNET_NO); - GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head, - plugin->pending_Sessions_tail, - sessionqueue_alt); - - GNUNET_free (sessionqueue_alt); - } - } - - } - return NULL; -} /** - * frees the space of a message in the fragment queue (send queue) - * @param plugin the plugin struct - * @param fm message to free + * Free a session + * + * @param session the session free */ static void -free_fragment_message (struct Plugin *plugin, struct FragmentMessage *fm) +free_session (struct Session *session) { - struct Session *session = fm->session; struct MacEndpoint *endpoint = session->mac; - struct FragmentMessage_queue *fmq; - struct FragmentMessage_queue *fmq_next; - - fmq = plugin->sending_messages_head; - while (fmq != NULL) - { - fmq_next = fmq->next; - if (fmq->content == fm) + struct PendingMessage *pm; + + endpoint->plugin->env->session_end (endpoint->plugin->env->cls, + &session->target, + session); + while (NULL != (pm = session->pending_message_head)) + { + GNUNET_CONTAINER_DLL_remove (session->pending_message_head, + session->pending_message_tail, pm); + if (GNUNET_SCHEDULER_NO_TASK != pm->timeout_task) { - GNUNET_CONTAINER_DLL_remove (plugin->sending_messages_head, - plugin->sending_messages_tail, fmq); - GNUNET_free (fmq); + GNUNET_SCHEDULER_cancel (pm->timeout_task); + pm->timeout_task = GNUNET_SCHEDULER_NO_TASK; } - fmq = fmq_next; - } - - (session->mac->fragment_messages_out_count)--; - session->fragment_messages_out_count--; - plugin->pending_Fragment_Messages--; - GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending fragments"), - plugin->pending_Fragment_Messages, GNUNET_NO); - GNUNET_CONTAINER_DLL_remove (endpoint->sending_messages_head, - endpoint->sending_messages_tail, fm); - GNUNET_FRAGMENT_context_destroy (fm->fragcontext); - if (fm->timeout_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (fm->timeout_task); - fm->timeout_task = GNUNET_SCHEDULER_NO_TASK; - } - - GNUNET_free (fm); - - queue_session (plugin, session); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Free pending fragment messages %p, session %p\n", fm, - session); -} - -/** - * function to fill the radiotap header - * @param plugin pointer to the plugin struct - * @param endpoint pointer to the endpoint - * @param header pointer to the radiotap header - * @return GNUNET_YES at success - */ -static int -getRadiotapHeader (struct Plugin *plugin, struct MacEndpoint *endpoint, - struct Radiotap_Send *header) -{ - - if (endpoint != NULL) - { - header->rate = endpoint->rate; - header->tx_power = endpoint->tx_power; - header->antenna = endpoint->antenna; + GNUNET_free (pm->msg); + GNUNET_free (pm); } - else + GNUNET_CONTAINER_DLL_remove (endpoint->sessions_head, + endpoint->sessions_tail, + session); + if (session->timeout_task != GNUNET_SCHEDULER_NO_TASK) { - header->rate = 255; - header->tx_power = 0; - header->antenna = 0; + GNUNET_SCHEDULER_cancel (session->timeout_task); + session->timeout_task = GNUNET_SCHEDULER_NO_TASK; } - - return GNUNET_YES; -} - -/** - * function to generate the wlan hardware header for one packet - * @param Header address to write the header to - * @param to_mac_addr address of the recipient - * @param plugin pointer to the plugin struct - * @param size size of the whole packet, needed to calculate the time to send the packet - * @return GNUNET_YES if there was no error - */ -static int -getWlanHeader (struct ieee80211_frame *Header, - const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr, struct Plugin *plugin, - unsigned int size) -{ - uint16_t *tmp16; - const int rate = 11000000; - - Header->i_fc[0] = IEEE80211_FC0_TYPE_DATA; - Header->i_fc[1] = 0x00; - memcpy (&Header->i_addr3, &mac_bssid_gnunet, sizeof (mac_bssid_gnunet)); - memcpy (&Header->i_addr2, plugin->mac_address.mac, - sizeof (plugin->mac_address)); - memcpy (&Header->i_addr1, to_mac_addr, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); - - tmp16 = (uint16_t *) Header->i_dur; - *tmp16 = (uint16_t) GNUNET_htole16 ((size * 1000000) / rate + 290); - Header->llc[0] = WLAN_LLC_DSAP_FIELD; - Header->llc[1] = WLAN_LLC_SSAP_FIELD; - - return GNUNET_YES; -} - - -/** - * function to add a fragment of a message to send - * @param cls FragmentMessage this message belongs to - * @param hdr pointer to the start of the message - */ -static void -add_message_for_send (void *cls, const struct GNUNET_MessageHeader *hdr) -{ - - struct FragmentMessage *fm = cls; - struct FragmentMessage_queue *fmqueue; - - GNUNET_assert (cls != NULL); - GNUNET_assert (fm->frag == NULL); - struct MacEndpoint *endpoint = fm->session->mac; - struct Plugin *plugin = endpoint->plugin; - struct GNUNET_MessageHeader *msgheader; - struct GNUNET_MessageHeader *msgheader2; - uint16_t size; - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Adding fragment of message %p to send, session %p, endpoint %p, type %u\n", - fm, fm->session, endpoint, hdr->type); - size = - sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) + - sizeof (struct ieee80211_frame) + ntohs (hdr->size); - fm->frag = GNUNET_malloc (size); - fm->size = size; - - msgheader = (struct GNUNET_MessageHeader *) fm->frag; - msgheader->size = htons (size); - msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); - - fm->radioHeader = (struct Radiotap_Send *) &msgheader[1]; - fm->ieeewlanheader = (struct ieee80211_frame *) &fm->radioHeader[1]; - msgheader2 = (struct GNUNET_MessageHeader *) &fm->ieeewlanheader[1]; - memcpy (msgheader2, hdr, ntohs (hdr->size)); - - fmqueue = GNUNET_malloc (sizeof (struct FragmentMessage_queue)); - fmqueue->content = fm; - - GNUNET_CONTAINER_DLL_insert_tail (plugin->sending_messages_head, - plugin->sending_messages_tail, fmqueue); - set_next_send (plugin); + GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN sessions allocated"), -1, + GNUNET_NO); + GNUNET_free (session); } /** - * We have been notified that gnunet-helper-transport-wlan has written something to stdout. - * Handle the output, then reschedule this function to be called again once - * more is available. + * A session is timing out. Clean up. * - * @param cls the plugin handle - * @param tc the scheduling context + * @param cls pointer to the Session + * @param tc pointer to the GNUNET_SCHEDULER_TaskContext */ static void -wlan_plugin_helper_read (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct Plugin *plugin = cls; - - plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK; + struct Session * session = cls; + struct GNUNET_TIME_Relative timeout; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - - char mybuf[WLAN_MTU + sizeof (struct GNUNET_MessageHeader)]; - ssize_t bytes; - - bytes = - GNUNET_DISK_file_read (plugin->server_stdout_handle, mybuf, - sizeof (mybuf)); - if (bytes <= 0) + session->timeout_task = GNUNET_SCHEDULER_NO_TASK; + timeout = GNUNET_TIME_absolute_get_remaining (session->timeout); + if (0 == timeout.rel_value) { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - _ - ("Finished reading from gnunet-helper-transport-wlan stdout with code: %d\n"), - bytes); + free_session (session); return; } - GNUNET_SERVER_mst_receive (plugin->suid_tokenizer, NULL, mybuf, bytes, - GNUNET_NO, GNUNET_NO); - - GNUNET_assert (plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK); - plugin->server_read_task = - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdout_handle, - &wlan_plugin_helper_read, plugin); + session->timeout_task = + GNUNET_SCHEDULER_add_delayed (timeout, &session_timeout, session); } + /** - * Start the gnunet-helper-transport-wlan process. + * Create a new session * - * @param plugin the transport plugin - * @return GNUNET_YES if process was started, GNUNET_SYSERR on error + * @param endpoint pointer to the mac endpoint of the peer + * @param peer peer identity to use for this session + * @return returns the session */ -static int -wlan_transport_start_wlan_helper (struct Plugin *plugin) +static struct Session * +create_session (struct MacEndpoint *endpoint, + const struct GNUNET_PeerIdentity *peer) { - const char *filenamehw = "gnunet-helper-transport-wlan"; - const char *filenameloopback = "gnunet-helper-transport-wlan-dummy"; - char *absolute_filename = NULL; - - if (plugin->helper_is_running == GNUNET_YES) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "wlan_transport_start_wlan_helper not needed, helper already running!"); - return GNUNET_YES; - } - - plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); - if (plugin->server_stdout == NULL) - return GNUNET_SYSERR; - - plugin->server_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); - if (plugin->server_stdin == NULL) - return GNUNET_SYSERR; - - if ((plugin->testmode == 1) || (plugin->testmode == 2)) - { - if (GNUNET_OS_check_helper_binary (filenameloopback) == GNUNET_YES) - { - absolute_filename = GNUNET_strdup (filenameloopback); - } - else - { - char cwd[FILENAME_MAX]; - - GNUNET_assert (getcwd (cwd, sizeof (cwd)) != NULL); - - GNUNET_asprintf (&absolute_filename, "%s%s%s", cwd, DIR_SEPARATOR_STR, - filenameloopback); - - if (GNUNET_DISK_file_test (filenameloopback) != GNUNET_YES) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, - "Helper `%s' not found! %i\n", absolute_filename); - GNUNET_break (0); - } - } - } - - /* Start the server process */ - - if (plugin->testmode == 0) - { - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Starting gnunet-helper-transport-wlan process cmd: %s %s %i\n", - filenamehw, plugin->interface, plugin->testmode); - if (GNUNET_OS_check_helper_binary (filenamehw) == GNUNET_YES) - { - plugin->server_proc = - GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout, - filenamehw, filenamehw, plugin->interface, - NULL); - } - else if (GNUNET_OS_check_helper_binary (filenamehw) == GNUNET_NO) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, - "gnunet-helper-transport-wlan is not suid, please change it or look at the doku\n"); - GNUNET_break (0); - } - else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, - "gnunet-helper-transport-wlan not found, please look if it exists and is the $PATH variable!\n"); - GNUNET_break (0); - } - - } - else if (plugin->testmode == 1) - { + struct Session *session; - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME, - "Starting gnunet-helper-transport-wlan-dummy loopback 1 process cmd: %s %s %i\n", - absolute_filename, plugin->interface, plugin->testmode); - plugin->server_proc = - GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout, - absolute_filename, absolute_filename, "1", - NULL); - if (plugin->server_proc == NULL) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, - "`%s' not found, please look if it exists and is in the $PATH variable!\n", - absolute_filename); - GNUNET_break (0); - } - } - else if (plugin->testmode == 2) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME, - "Starting gnunet-helper-transport-wlan-dummy loopback 2 process cmd: %s %s %i\n", - absolute_filename, plugin->interface, plugin->testmode); - plugin->server_proc = - GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout, - absolute_filename, absolute_filename, "2", - NULL); - if (plugin->server_proc == NULL) + for (session = endpoint->sessions_head; NULL != session; session = session->next) + if (0 == memcmp (peer, &session->target, + sizeof (struct GNUNET_PeerIdentity))) { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, - "`%s' not found, please look if it exists and is in the $PATH variable!\n", - absolute_filename); - GNUNET_break (0); + session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + return session; } - } - if (absolute_filename != NULL) - GNUNET_free (absolute_filename); - if (plugin->server_proc == NULL) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Failed to start gnunet-helper-transport-wlan process\n"); - return GNUNET_SYSERR; - } - - - - /* Close the write end of the read pipe */ - GNUNET_DISK_pipe_close_end (plugin->server_stdout, - GNUNET_DISK_PIPE_END_WRITE); - - /* Close the read end of the write pipe */ - GNUNET_DISK_pipe_close_end (plugin->server_stdin, GNUNET_DISK_PIPE_END_READ); - - plugin->server_stdout_handle = - GNUNET_DISK_pipe_handle (plugin->server_stdout, - GNUNET_DISK_PIPE_END_READ); - plugin->server_stdin_handle = - GNUNET_DISK_pipe_handle (plugin->server_stdin, - GNUNET_DISK_PIPE_END_WRITE); - - GNUNET_assert (plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK); - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Adding server_read_task for the gnunet-helper-transport-wlan\n"); - plugin->server_read_task = - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdout_handle, - &wlan_plugin_helper_read, plugin); - - plugin->helper_is_running = GNUNET_YES; - return GNUNET_YES; + GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN sessions allocated"), 1, + GNUNET_NO); + session = GNUNET_malloc (sizeof (struct Session)); + GNUNET_CONTAINER_DLL_insert_tail (endpoint->sessions_head, + endpoint->sessions_tail, + session); + session->mac = endpoint; + session->target = *peer; + session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + session->timeout_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, session); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Created new session for peer `%s' with endpoint %s\n", + GNUNET_i2s (peer), + mac_to_string (&endpoint->addr)); + return session; } -/** - * Stops the gnunet-helper-transport-wlan process. - * - * @param plugin the transport plugin - * @return GNUNET_YES if process was started, GNUNET_SYSERR on error - */ -static int -wlan_transport_stop_wlan_helper (struct Plugin *plugin) -{ - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Stoping WLAN helper process\n"); - - if (plugin->helper_is_running == GNUNET_NO) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "wlan_transport_stop_wlan_helper not needed, helper already stopped!"); - return GNUNET_YES; - } - - if (plugin->server_write_delay_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (plugin->server_write_delay_task); - plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK; - } - - if (plugin->server_write_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (plugin->server_write_task); - plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK; - } - - if (plugin->server_read_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (plugin->server_read_task); - plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK; - } - - GNUNET_DISK_pipe_close (plugin->server_stdout); - GNUNET_DISK_pipe_close (plugin->server_stdin); - GNUNET_OS_process_kill (plugin->server_proc, SIGKILL); - GNUNET_OS_process_wait (plugin->server_proc); - GNUNET_OS_process_close (plugin->server_proc); - - plugin->helper_is_running = GNUNET_NO; - - return GNUNET_YES; -} /** - * function for delayed restart of the helper process - * @param cls Finish_send struct if message should be finished - * @param tc TaskContext + * Function called once we have successfully given the fragment + * message to the SUID helper process and we are thus ready for + * the next fragment. + * + * @param cls the 'struct FragmentMessage' + * @param result result of the operation (GNUNET_OK on success, GNUNET_NO if the helper died, GNUNET_SYSERR + * if the helper was stopped) */ static void -delay_restart_helper (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +fragment_transmission_done (void *cls, + int result) { - struct Finish_send *finish = cls; - struct Plugin *plugin; - - plugin = finish->plugin; - - plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) - { - GNUNET_free_non_null (finish->msgstart); - GNUNET_free (finish); - return; - } - - wlan_transport_start_wlan_helper (plugin); - - if (finish->size != 0) - { - plugin->server_write_task = - GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdin_handle, - &finish_sending, finish); - } - else - { - set_next_send (plugin); - GNUNET_free_non_null (finish->msgstart); - GNUNET_free (finish); - } + struct FragmentMessage *fm = cls; + fm->sh = NULL; + GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext); } -/** - * Function to restart the helper - * @param plugin pointer to the global plugin struct - * @param finish pointer to the Finish_send struct to finish - */ -static void -restart_helper (struct Plugin *plugin, struct Finish_send *finish) -{ - static struct GNUNET_TIME_Relative next_try = { 1000 }; - GNUNET_assert (finish != NULL); - - wlan_transport_stop_wlan_helper (plugin); - plugin->server_write_task = - GNUNET_SCHEDULER_add_delayed (next_try, &delay_restart_helper, finish); - GNUNET_TIME_relative_multiply (next_try, HELPER_RESTART_SCALING_FACTOR); - -} /** - * function to finish a sending if not all could have been writen befor - * @param cls pointer to the Finish_send struct - * @param tc TaskContext + * Transmit a fragment of a message. + * + * @param cls 'struct FragmentMessage' this fragment message belongs to + * @param hdr pointer to the start of the fragment message */ static void -finish_sending (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +transmit_fragment (void *cls, + const struct GNUNET_MessageHeader *hdr) { - struct Finish_send *finish = cls; - struct Plugin *plugin; - ssize_t bytes; - - plugin = finish->plugin; - plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK; - - if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) - { - GNUNET_free (finish->msgstart); - GNUNET_free (finish); - return; - } - bytes = - GNUNET_DISK_file_write (plugin->server_stdin_handle, - finish->head_of_next_write, finish->size); - - if (bytes != finish->size) - { - if (bytes != GNUNET_SYSERR) - { - finish->head_of_next_write += bytes; - finish->size -= bytes; - plugin->server_write_task = - GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdin_handle, - &finish_sending, finish); - } + struct FragmentMessage *fm = cls; + struct MacEndpoint *endpoint = fm->macendpoint; + size_t size; + uint16_t msize; + + msize = ntohs (hdr->size); + size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + msize; + { + char buf[size]; + struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radio_header; + + radio_header = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) buf; + get_radiotap_header (endpoint, radio_header, size); + get_wlan_header (endpoint->plugin, + &radio_header->frame, + &endpoint->addr, + size); + memcpy (&radio_header[1], hdr, msize); + GNUNET_assert (NULL == fm->sh); + fm->sh = GNUNET_HELPER_send (endpoint->plugin->suid_helper, + &radio_header->header, + GNUNET_NO, + &fragment_transmission_done, fm); + if (NULL != fm->sh) + GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN message fragments sent"), + 1, GNUNET_NO); else - { - restart_helper (plugin, finish); - } - } - else - { - GNUNET_free (finish->msgstart); - GNUNET_free (finish); - set_next_send (plugin); + GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext); } } + /** - * function to send a hello beacon - * @param plugin pointer to the plugin struct + * Frees the space of a message in the fragment queue (send queue) + * + * @param fm message to free */ static void -send_hello_beacon (struct Plugin *plugin) +free_fragment_message (struct FragmentMessage *fm) { - uint16_t size; - ssize_t bytes; - uint16_t hello_size; - struct GNUNET_MessageHeader *msgheader; - struct ieee80211_frame *ieeewlanheader; - struct Radiotap_Send *radioHeader; - struct GNUNET_MessageHeader *msgheader2; - const struct GNUNET_MessageHeader *hello; - struct Finish_send *finish; - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Sending hello beacon\n"); - - GNUNET_assert (plugin != NULL); + struct MacEndpoint *endpoint = fm->macendpoint; - GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan hello beacons send"), - 1, GNUNET_NO); - - hello = plugin->env->get_our_hello (); - hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello); - GNUNET_assert (sizeof (struct WlanHeader) + hello_size <= WLAN_MTU); - size = - sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) + - sizeof (struct ieee80211_frame) + hello_size; - - msgheader = GNUNET_malloc (size); - msgheader->size = htons (size); - msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); - - radioHeader = (struct Radiotap_Send *) &msgheader[1]; - getRadiotapHeader (plugin, NULL, radioHeader); - ieeewlanheader = (struct ieee80211_frame *) &radioHeader[1]; - getWlanHeader (ieeewlanheader, &bc_all_mac, plugin, size); - - msgheader2 = (struct GNUNET_MessageHeader *) &ieeewlanheader[1]; - /*msgheader2->size = - * htons (GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello) + - * sizeof (struct GNUNET_MessageHeader)); - * - * msgheader2->type = htons (GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT); */ - memcpy (msgheader2, hello, hello_size); - - bytes = GNUNET_DISK_file_write (plugin->server_stdin_handle, msgheader, size); - - if (bytes == GNUNET_SYSERR) + GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN messages pending (with fragmentation)"), + -1, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (endpoint->sending_messages_head, + endpoint->sending_messages_tail, fm); + if (NULL != fm->sh) { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, - _ - ("Error writing to wlan helper. errno == %d, ERROR: %s\n"), - errno, strerror (errno)); - finish = GNUNET_malloc (sizeof (struct Finish_send)); - finish->plugin = plugin; - finish->head_of_next_write = NULL; - finish->size = 0; - finish->msgstart = NULL; - restart_helper (plugin, finish); - - set_next_beacon_time (plugin); - + GNUNET_HELPER_send_cancel (fm->sh); + fm->sh = NULL; } - else + GNUNET_FRAGMENT_context_destroy (fm->fragcontext); + if (fm->timeout_task != GNUNET_SCHEDULER_NO_TASK) { - GNUNET_assert (bytes == size); - set_next_beacon_time (plugin); - set_next_send (plugin); + GNUNET_SCHEDULER_cancel (fm->timeout_task); + fm->timeout_task = GNUNET_SCHEDULER_NO_TASK; } - GNUNET_free (msgheader); - - + GNUNET_free (fm); } -/** - * function to add an ack to send it for a received fragment - * @param cls MacEndpoint this ack belongs to - * @param msg_id id of the message - * @param hdr pointer to the hdr where the ack is stored - * - */ -static void -add_ack_for_send (void *cls, uint32_t msg_id, - const struct GNUNET_MessageHeader *hdr) -{ - - struct AckSendQueue *ack; - - GNUNET_assert (cls != NULL); - struct MacEndpoint *endpoint = cls; - struct Plugin *plugin = endpoint->plugin; - struct GNUNET_MessageHeader *msgheader; - struct GNUNET_MessageHeader *msgheader2; - uint16_t size; - - size = - sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) + - sizeof (struct ieee80211_frame) + ntohs (hdr->size) + - sizeof (struct AckSendQueue); - - ack = GNUNET_malloc (size); - ack->message_id = msg_id; - ack->endpoint = endpoint; - - size = - sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) + - sizeof (struct ieee80211_frame) + ntohs (hdr->size); - - msgheader = (struct GNUNET_MessageHeader *) &ack[1]; - ack->hdr = (struct GNUNET_MessageHeader *) &ack[1]; - msgheader->size = htons (size); - msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); - - ack->radioHeader = (struct Radiotap_Send *) &msgheader[1]; - ack->ieeewlanheader = (struct ieee80211_frame *) &(ack->radioHeader)[1]; - msgheader2 = (struct GNUNET_MessageHeader *) &(ack->ieeewlanheader)[1]; - memcpy (msgheader2, hdr, ntohs (hdr->size)); - - GNUNET_CONTAINER_DLL_insert_tail (plugin->ack_send_queue_head, - plugin->ack_send_queue_tail, ack); - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Adding ack with message id %u to send, AckSendQueue %p, endpoint %p\n", - msg_id, ack, endpoint); - set_next_send (plugin); -} /** - * Function for the scheduler if a FragmentMessage times out - * @param cls pointer to the FragmentMessage + * A FragmentMessage has timed out. Remove it. + * + * @param cls pointer to the 'struct FragmentMessage' * @param tc pointer to the GNUNET_SCHEDULER_TaskContext */ static void @@ -1849,284 +795,162 @@ fragmentmessage_timeout (void *cls, { struct FragmentMessage *fm = cls; - GNUNET_assert (fm != NULL); fm->timeout_task = GNUNET_SCHEDULER_NO_TASK; - if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) + if (NULL != fm->cont) { - return; + fm->cont (fm->cont_cls, &fm->target, GNUNET_SYSERR); + fm->cont = NULL; } - free_fragment_message (fm->session->mac->plugin, fm); + free_fragment_message (fm); } + /** - * Function to check if there is some space in the fragment queue - * inserts a message if space is available - * @param plugin the plugin struct + * Transmit a message to the given destination with fragmentation. + * + * @param endpoint desired destination + * @param timeout how long can the message wait? + * @param target peer that should receive the message + * @param msg message to transmit + * @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...); can be NULL + * @param cont_cls closure for cont */ - static void -check_fragment_queue (struct Plugin *plugin) +send_with_fragmentation (struct MacEndpoint *endpoint, + struct GNUNET_TIME_Relative timeout, + const struct GNUNET_PeerIdentity *target, + const struct GNUNET_MessageHeader *msg, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) + { - struct Session *session; struct FragmentMessage *fm; - struct GNUNET_PeerIdentity pid; - - struct PendingMessage *pm; - - if (plugin->pending_Fragment_Messages < FRAGMENT_QUEUE_SIZE) - { - session = get_next_queue_session (plugin); - if (session != NULL) - { - pm = session->pending_message_head; - GNUNET_assert (pm != NULL); - GNUNET_CONTAINER_DLL_remove (session->pending_message_head, - session->pending_message_tail, pm); - session->mac->fragment_messages_out_count++; - session->fragment_messages_out_count++; - plugin->pending_Fragment_Messages++; - GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending fragments"), - plugin->pending_Fragment_Messages, GNUNET_NO); - - fm = GNUNET_malloc (sizeof (struct FragmentMessage)); - fm->session = session; - fm->timeout.abs_value = pm->timeout.abs_value; - fm->frag = NULL; - fm->fragcontext = - GNUNET_FRAGMENT_context_create (plugin->env->stats, WLAN_MTU, - &plugin->tracker, - GNUNET_TIME_UNIT_SECONDS, - &(pm->msg->header), - &add_message_for_send, fm); - fm->timeout_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining - (fm->timeout), fragmentmessage_timeout, - fm); - GNUNET_CONTAINER_DLL_insert_tail (session->mac->sending_messages_head, - session->mac->sending_messages_tail, - fm); - - if (pm->transmit_cont != NULL) - { - pid = session->target; - pm->transmit_cont (pm->transmit_cont_cls, &pid, GNUNET_OK); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "called pm->transmit_cont for %p\n", session); - } - else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "no pm->transmit_cont for %p\n", session); - } - GNUNET_free (pm); - - if (session->pending_message_head != NULL) - { - //requeue session - queue_session (plugin, session); - } - - } - } + struct Plugin *plugin; - //check if timeout changed - set_next_send (plugin); + plugin = endpoint->plugin; + fm = GNUNET_malloc (sizeof (struct FragmentMessage)); + fm->macendpoint = endpoint; + fm->target = *target; + fm->timeout = GNUNET_TIME_relative_to_absolute (timeout); + fm->cont = cont; + fm->cont_cls = cont_cls; + fm->fragcontext = + GNUNET_FRAGMENT_context_create (plugin->env->stats, WLAN_MTU, + &plugin->tracker, + GNUNET_TIME_UNIT_SECONDS, + msg, + &transmit_fragment, fm); + fm->timeout_task = + GNUNET_SCHEDULER_add_delayed (timeout, + &fragmentmessage_timeout, fm); + GNUNET_CONTAINER_DLL_insert_tail (endpoint->sending_messages_head, + endpoint->sending_messages_tail, + fm); } + /** - * Function to send an ack, does not free the ack - * @param plugin pointer to the plugin + * Free a MAC endpoint. + * + * @param endpoint pointer to the MacEndpoint to free */ static void -send_ack (struct Plugin *plugin) +free_macendpoint (struct MacEndpoint *endpoint) { + struct Plugin *plugin = endpoint->plugin; + struct FragmentMessage *fm; + struct Session *session; - ssize_t bytes; - struct AckSendQueue *ack; - struct Finish_send *finish; - - ack = plugin->ack_send_queue_head; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Sending ack for message_id %u for mac endpoint %p, size %u\n", - ack->message_id, ack->endpoint, - ntohs (ack->hdr->size) - sizeof (struct Radiotap_Send)); - GNUNET_assert (plugin != NULL); - GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan acks send"), 1, - GNUNET_NO); - - getRadiotapHeader (plugin, ack->endpoint, ack->radioHeader); - getWlanHeader (ack->ieeewlanheader, &ack->endpoint->addr, plugin, - ntohs (ack->hdr->size)); + GNUNET_STATISTICS_update (plugin->env->stats, + _("# WLAN MAC endpoints allocated"), -1, GNUNET_NO); + while (NULL != (session = endpoint->sessions_head)) + free_session (session); + while (NULL != (fm = endpoint->sending_messages_head)) + free_fragment_message (fm); + GNUNET_CONTAINER_DLL_remove (plugin->mac_head, + plugin->mac_tail, + endpoint); - bytes = - GNUNET_DISK_file_write (plugin->server_stdin_handle, ack->hdr, - ntohs (ack->hdr->size)); - if (bytes == GNUNET_SYSERR) + if (NULL != endpoint->defrag) { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, - _ - ("Error writing to wlan helper. errno == %d, ERROR: %s\n"), - errno, strerror (errno)); - finish = GNUNET_malloc (sizeof (struct Finish_send)); - finish->plugin = plugin; - finish->head_of_next_write = NULL; - finish->size = 0; - finish->msgstart = NULL; - restart_helper (plugin, finish); + GNUNET_DEFRAGMENT_context_destroy(endpoint->defrag); + endpoint->defrag = NULL; } - else + + plugin->mac_count--; + if (GNUNET_SCHEDULER_NO_TASK != endpoint->timeout_task) { - GNUNET_assert (bytes == ntohs (ack->hdr->size)); - GNUNET_CONTAINER_DLL_remove (plugin->ack_send_queue_head, - plugin->ack_send_queue_tail, ack); - GNUNET_free (ack); - set_next_send (plugin); + GNUNET_SCHEDULER_cancel (endpoint->timeout_task); + endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK; } + GNUNET_free (endpoint); } + /** - * Function called when wlan helper is ready to get some data + * A MAC endpoint is timing out. Clean up. * - * @param cls closure - * @param tc GNUNET_SCHEDULER_TaskContext + * @param cls pointer to the MacEndpoint + * @param tc pointer to the GNUNET_SCHEDULER_TaskContext */ static void -do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +macendpoint_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct Plugin *plugin = cls; - - GNUNET_assert (plugin != NULL); - - plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - - struct Session *session; - struct FragmentMessage *fm; - struct Finish_send *finish; - struct FragmentMessage_queue *fmq; - ssize_t bytes; - - if (plugin->ack_send_queue_head != NULL) - { - send_ack (plugin); - return; - } + struct MacEndpoint *endpoint = cls; + struct GNUNET_TIME_Relative timeout; - //test if a "hello-beacon" has to be send - if (GNUNET_TIME_absolute_get_remaining (plugin->beacon_time).rel_value == 0) + endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK; + timeout = GNUNET_TIME_absolute_get_remaining (endpoint->timeout); + if (0 == timeout.rel_value) { - send_hello_beacon (plugin); + free_macendpoint (endpoint); return; } - - if (plugin->sending_messages_head != NULL) - { - GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan fragments send"), 1, - GNUNET_NO); - - fmq = plugin->sending_messages_head; - fm = fmq->content; - GNUNET_CONTAINER_DLL_remove (plugin->sending_messages_head, - plugin->sending_messages_tail, fmq); - GNUNET_free (fmq); - - session = fm->session; - GNUNET_assert (session != NULL); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Sending GNUNET_MESSAGE_TYPE_WLAN_FRAGMENT for fragment message %p, size: %u\n", - fm, fm->size); - getRadiotapHeader (plugin, session->mac, fm->radioHeader); - getWlanHeader (fm->ieeewlanheader, &(fm->session->mac->addr), plugin, - fm->size); - - bytes = - GNUNET_DISK_file_write (plugin->server_stdin_handle, fm->frag, - fm->size); - - - if (bytes != fm->size) - { - finish = GNUNET_malloc (sizeof (struct Finish_send)); - finish->plugin = plugin; - finish->msgstart = (struct GNUNET_MessageHeader *) fm->frag; - GNUNET_assert (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK); - - if (bytes == GNUNET_SYSERR) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, - _ - ("Error writing to wlan helper. errno == %d, ERROR: %s\n"), - errno, strerror (errno)); - - finish->head_of_next_write = fm->frag; - finish->size = fm->size; - restart_helper (plugin, finish); - } - else - { - finish->head_of_next_write = fm->frag + bytes; - finish->size = fm->size - bytes; - plugin->server_write_task = - GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdin_handle, - &finish_sending, finish); - } - - fm->frag = NULL; - } - else - { - GNUNET_free (fm->frag); - fm->frag = NULL; - set_next_send (plugin); - } - GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext); - return; - } - -#if 1 - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "do_transmit did nothing, should not happen!\n"); -#endif - set_next_send (plugin); + endpoint->timeout_task = + GNUNET_SCHEDULER_add_delayed (timeout, &macendpoint_timeout, + endpoint); } + /** - * Another peer has suggested an address for this - * peer and transport plugin. Check that this could be a valid - * address. If so, consider adding it to the list - * of addresses. + * Find (or create) a MacEndpoint with a specific MAC address * - * @param cls closure - * @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 + * @param plugin pointer to the plugin struct + * @param addr the MAC address of the endpoint + * @return handle to our data structure for this MAC */ -static int -wlan_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) +static struct MacEndpoint * +create_macendpoint (struct Plugin *plugin, + const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr) { - //struct Plugin *plugin = cls; - - /* check if the address is plausible; if so, - * add it to our list! */ - - GNUNET_assert (cls != NULL); - //FIXME mitm is not checked - //Mac Address has 6 bytes - if (addrlen == 6) - { - /* TODO check for bad addresses like multicast, broadcast, etc */ - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "wlan_plugin_address_suggested got good address, size %u!\n", - addrlen); - return GNUNET_OK; - } - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "wlan_plugin_address_suggested got bad address, size %u!\n", - addrlen); - return GNUNET_SYSERR; + struct MacEndpoint *pos; + + for (pos = plugin->mac_head; NULL != pos; pos = pos->next) + if (0 == memcmp (addr, &pos->addr, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) + return pos; + pos = GNUNET_malloc (sizeof (struct MacEndpoint)); + pos->addr = *addr; + pos->plugin = plugin; + pos->defrag = + GNUNET_DEFRAGMENT_context_create (plugin->env->stats, WLAN_MTU, + MESSAGES_IN_DEFRAG_QUEUE_PER_MAC, + pos, + &wlan_data_message_handler, + &send_ack); + pos->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT); + pos->timeout_task = + GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout, + pos); + GNUNET_CONTAINER_DLL_insert (plugin->mac_head, plugin->mac_tail, pos); + plugin->mac_count++; + GNUNET_STATISTICS_update (plugin->env->stats, _("# WLAN MAC endpoints allocated"), + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "New MAC endpoint `%s'\n", + mac_to_string (addr)); + return pos; } @@ -2138,33 +962,55 @@ wlan_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) * @param address the address * @return the session or NULL of max connections exceeded */ - static struct Session * wlan_plugin_get_session (void *cls, - const struct GNUNET_HELLO_Address *address) + const struct GNUNET_HELLO_Address *address) { struct Plugin *plugin = cls; - struct Session * s = NULL; - - GNUNET_assert (plugin != NULL); - GNUNET_assert (address != NULL); + struct MacEndpoint *endpoint; - if (GNUNET_OK == wlan_plugin_address_suggested (plugin, - address->address, - address->address_length)) - { - s = get_session (plugin, address->address, &address->peer); - } - else + if (NULL == address) + return NULL; + if (sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress) != address->address_length) { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, - _("Wlan Address len %d is wrong\n"), address->address_length); - return s; + GNUNET_break (0); + return NULL; } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Service asked to create session for peer `%s' with MAC `%s'\n", + GNUNET_i2s (&address->peer), + mac_to_string (address->address)); + endpoint = create_macendpoint (plugin, address->address); + return create_session (endpoint, &address->peer); +} + + +/** + * Function that can be used to force the plugin to disconnect + * from the given peer and cancel all previous transmissions + * (and their continuation). + * + * @param cls closure + * @param target peer from which to disconnect + */ +static void +wlan_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) +{ + struct Plugin *plugin = cls; + struct Session *session; + struct MacEndpoint *endpoint; - return s; + for (endpoint = plugin->mac_head; NULL != endpoint; endpoint = endpoint->next) + for (session = endpoint->sessions_head; NULL != session; session = session->next) + if (0 == memcmp (target, &session->target, + sizeof (struct GNUNET_PeerIdentity))) + { + free_session (session); + break; /* inner-loop only (in case peer has another MAC as well!) */ + } } + /** * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a @@ -2201,925 +1047,586 @@ wlan_plugin_send (void *cls, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct Plugin *plugin = cls; - struct PendingMessage *newmsg; struct WlanHeader *wlanheader; - - GNUNET_assert (plugin != NULL); - GNUNET_assert (session != NULL); - GNUNET_assert (msgbuf_size > 0); - - //queue message: - - //queue message in session - //test if there is no other message in the "queue" - //FIXME: to many send requests - if (session->pending_message_head != NULL) - { - newmsg = session->pending_message_head; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "wlan_plugin_send: a pending message is already in the queue for this client\n remaining time to send this message is %u, queued fragment messages for this mac connection %u\n", - GNUNET_TIME_absolute_get_remaining (newmsg-> - timeout).rel_value, - session->mac->fragment_messages_out_count); - } - - newmsg = GNUNET_malloc (sizeof (struct PendingMessage)); - newmsg->msg = GNUNET_malloc (msgbuf_size + sizeof (struct WlanHeader)); - wlanheader = newmsg->msg; - //copy msg to buffer, not fragmented / segmented yet, but with message header + size_t size = msgbuf_size + sizeof (struct WlanHeader); + char buf[size] GNUNET_ALIGN; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting %u bytes of payload to peer `%s' (starting with %u byte message of type %u)\n", + msgbuf_size, + GNUNET_i2s (&session->target), + (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->size), + (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->type)); + wlanheader = (struct WlanHeader *) buf; wlanheader->header.size = htons (msgbuf_size + sizeof (struct WlanHeader)); wlanheader->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA); - memcpy (&(wlanheader->target), &session->target, sizeof (struct GNUNET_PeerIdentity)); - memcpy (&(wlanheader->source), plugin->env->my_identity, - sizeof (struct GNUNET_PeerIdentity)); - wlanheader->crc = 0; + wlanheader->sender = *plugin->env->my_identity; + wlanheader->target = session->target; + wlanheader->crc = htonl (GNUNET_CRYPTO_crc32_n (msgbuf, msgbuf_size)); memcpy (&wlanheader[1], msgbuf, msgbuf_size); - wlanheader->crc = - htonl (GNUNET_CRYPTO_crc32_n - ((char *) wlanheader, msgbuf_size + sizeof (struct WlanHeader))); - - newmsg->transmit_cont = cont; - newmsg->transmit_cont_cls = cont_cls; - newmsg->timeout = GNUNET_TIME_relative_to_absolute (to); - - newmsg->timeout.abs_value = newmsg->timeout.abs_value - 500; - - newmsg->message_size = msgbuf_size + sizeof (struct WlanHeader); - - GNUNET_CONTAINER_DLL_insert_tail (session->pending_message_head, - session->pending_message_tail, newmsg); - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "New message for %p with size (incl wlan header) %u added\n", - session, newmsg->message_size); -#if DEBUG_WLAN > 1 - hexdump (msgbuf, GNUNET_MIN (msgbuf_size, 256)); -#endif - //queue session - queue_session (plugin, session); - - check_fragment_queue (plugin); - //FIXME not the correct size - return msgbuf_size; + send_with_fragmentation (session->mac, + to, + &session->target, + &wlanheader->header, + cont, cont_cls); + return size; } /** - * function to free a mac endpoint - * @param plugin pointer to the plugin struct - * @param endpoint pointer to the MacEndpoint to free - */ -static void -free_macendpoint (struct Plugin *plugin, struct MacEndpoint *endpoint) -{ - struct Sessionqueue *sessions; - struct Sessionqueue *sessions_next; - - GNUNET_assert (endpoint != NULL); - - sessions = endpoint->sessions_head; - while (sessions != NULL) - { - sessions_next = sessions->next; - free_session (plugin, sessions, GNUNET_NO); - sessions = sessions_next; - } - - GNUNET_CONTAINER_DLL_remove (plugin->mac_head, plugin->mac_tail, endpoint); - if (endpoint->timeout_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (endpoint->timeout_task); - endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK; - } - plugin->mac_count--; - GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"), - plugin->mac_count, GNUNET_NO); - GNUNET_free (endpoint); - -} - -/** - * function to free a session - * @param plugin pointer to the plugin - * @param queue pointer to the sessionqueue element to free - * @param do_free_macendpoint if GNUNET_YES and mac endpoint would be empty, free mac endpoint - */ -static void -free_session (struct Plugin *plugin, struct Sessionqueue *queue, - int do_free_macendpoint) -{ - struct Sessionqueue *pendingsession; - struct Sessionqueue *pendingsession_tmp; - struct PendingMessage *pm; - struct MacEndpoint *endpoint; - struct FragmentMessage *fm; - struct FragmentMessage *fmnext; - int check = 0; - - GNUNET_assert (plugin != NULL); - GNUNET_assert (queue != NULL); - GNUNET_assert (queue->content != NULL); - - //session found - //is this session pending for send - pendingsession = plugin->pending_Sessions_head; - while (pendingsession != NULL) - { - pendingsession_tmp = pendingsession; - pendingsession = pendingsession->next; - GNUNET_assert (pendingsession_tmp->content != NULL); - if (pendingsession_tmp->content == queue->content) - { - plugin->pendingsessions--; - GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), - plugin->pendingsessions, GNUNET_NO); - GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head, - plugin->pending_Sessions_tail, - pendingsession_tmp); - GNUNET_free (pendingsession_tmp); - - GNUNET_assert (check == 0); - check = 1; - } - } - - endpoint = queue->content->mac; - fm = endpoint->sending_messages_head; - while (fm != NULL) - { - fmnext = fm->next; - if (fm->session == queue->content) - { - free_fragment_message (plugin, fm); - } - fm = fmnext; - } - - // remove PendingMessage - pm = queue->content->pending_message_head; - while (pm != NULL) - { - GNUNET_CONTAINER_DLL_remove (queue->content->pending_message_head, - queue->content->pending_message_tail, pm); - GNUNET_free (pm->msg); - GNUNET_free (pm); - pm = queue->content->pending_message_head; - } - - GNUNET_CONTAINER_DLL_remove (endpoint->sessions_head, endpoint->sessions_tail, - queue); - //Check that no ohter session on this endpoint for this session exits - GNUNET_assert (search_session (plugin, endpoint, &queue->content->target) == - NULL); - if (endpoint->sessions_head == NULL && do_free_macendpoint == GNUNET_YES) - { - free_macendpoint (plugin, endpoint); - //check if no endpoint with the same address exists - GNUNET_assert (get_macendpoint (plugin, &endpoint->addr, GNUNET_NO) == - NULL); - } - - if (queue->content->timeout_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (queue->content->timeout_task); - queue->content->timeout_task = GNUNET_SCHEDULER_NO_TASK; - } - GNUNET_free (queue); - - check_fragment_queue (plugin); -} - -/** - * Function that can be used to force the plugin to disconnect - * from the given peer and cancel all previous transmissions - * (and their continuation). + * We have received data from the WLAN via some session. Process depending + * on the message type (HELLO, DATA, FRAGMENTATION or FRAGMENTATION-ACK). * - * @param cls closure - * @param target peer from which to disconnect + * @param cls pointer to the plugin + * @param client pointer to the session this message belongs to + * @param hdr start of the message */ -static void -wlan_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) +static int +process_data (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) { struct Plugin *plugin = cls; - struct Sessionqueue *queue; - struct Sessionqueue *queue_next; - struct MacEndpoint *endpoint = plugin->mac_head; - struct MacEndpoint *endpoint_next; + struct MacAndSession *mas = client; + struct MacAndSession xmas; +#define NUM_ATS 2 + struct GNUNET_ATS_Information ats[NUM_ATS]; /* FIXME: do better here */ + struct FragmentMessage *fm; + struct GNUNET_PeerIdentity tmpsource; + const struct WlanHeader *wlanheader; + int ret; + uint16_t msize; - // just look at all the session for the needed one - while (endpoint != NULL) + ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); + ats[0].value = htonl (1); + ats[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); + ats[1].value = htonl (GNUNET_ATS_NET_WLAN); + msize = ntohs (hdr->size); + switch (ntohs (hdr->type)) { - queue = endpoint->sessions_head; - endpoint_next = endpoint->next; - while (queue != NULL) + case GNUNET_MESSAGE_TYPE_HELLO: + if (GNUNET_OK != + GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hdr, &tmpsource)) { - // content is never NULL - GNUNET_assert (queue->content != NULL); - queue_next = queue->next; - if (memcmp - (target, &(queue->content->target), - sizeof (struct GNUNET_PeerIdentity)) == 0) - { - free_session (plugin, queue, GNUNET_YES); - } - // try next - queue = queue_next; + GNUNET_break_op (0); + break; } - endpoint = endpoint_next; - } -} - -/** - * 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 -wlan_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) -{ - char *ret; - const unsigned char *input; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing %u bytes of HELLO from peer `%s' at MAC %s\n", + (unsigned int) msize, + GNUNET_i2s (&tmpsource), + mac_to_string (&mas->endpoint->addr)); - //GNUNET_assert(cls !=NULL); - if (addrlen != sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) - { - /* invalid address (MAC addresses have 6 bytes) */ - //GNUNET_break (0); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Func wlan_plugin_address_pretty_printer got size: %u, worng size!\n", - addrlen); - asc (asc_cls, NULL); - return; - } - input = (const unsigned char *) addr; - GNUNET_asprintf (&ret, - "Transport %s: %s Mac-Address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X", - type, PROTOCOL_PREFIX, input[0], input[1], input[2], - input[3], input[4], input[5]); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Func wlan_plugin_address_pretty_printer got size: %u, nummeric %u, type %s; made string: %s\n", - addrlen, numeric, type, ret); - asc (asc_cls, ret); - //only one mac address per plugin - asc (asc_cls, NULL); -} - - - -/** - * handels the data after all fragments are put together - * @param cls macendpoint this messages belongs to - * @param hdr pointer to the data - */ -static void -wlan_data_message_handler (void *cls, const struct GNUNET_MessageHeader *hdr) -{ - struct MacEndpoint *endpoint = (struct MacEndpoint *) cls; - struct Plugin *plugin = endpoint->plugin; - struct WlanHeader *wlanheader; - struct Session *session; - - const struct GNUNET_MessageHeader *temp_hdr; - struct GNUNET_PeerIdentity tmpsource; - int crc; - - GNUNET_assert (plugin != NULL); - - if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_WLAN_DATA) - { - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Func wlan_data_message_handler got GNUNET_MESSAGE_TYPE_WLAN_DATA size: %u\n", - ntohs (hdr->size)); - - if (ntohs (hdr->size) < - sizeof (struct WlanHeader) + sizeof (struct GNUNET_MessageHeader)) + GNUNET_STATISTICS_update (plugin->env->stats, + _("# HELLO messages received via WLAN"), 1, + GNUNET_NO); + plugin->env->receive (plugin->env->cls, + &tmpsource, + hdr, + ats, NUM_ATS, + mas->session, + (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr, + (mas->endpoint == NULL) ? 0 : sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); + break; + case GNUNET_MESSAGE_TYPE_FRAGMENT: + if (NULL == mas->endpoint) { - //packet not big enought - return; + GNUNET_break (0); + break; } - + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing %u bytes of FRAGMENT from MAC %s\n", + (unsigned int) msize, + mac_to_string (&mas->endpoint->addr)); GNUNET_STATISTICS_update (plugin->env->stats, - _("# wlan whole messages received"), 1, - GNUNET_NO); - wlanheader = (struct WlanHeader *) hdr; - - session = search_session (plugin, endpoint, &wlanheader->source); - - temp_hdr = (const struct GNUNET_MessageHeader *) &wlanheader[1]; - crc = ntohl (wlanheader->crc); - wlanheader->crc = 0; - if (GNUNET_CRYPTO_crc32_n - ((char *) wlanheader, ntohs (wlanheader->header.size)) != crc) + _("# fragments received via WLAN"), 1, GNUNET_NO); + (void) GNUNET_DEFRAGMENT_process_fragment (mas->endpoint->defrag, + hdr); + break; + case GNUNET_MESSAGE_TYPE_FRAGMENT_ACK: + if (NULL == mas->endpoint) { - //wrong crc, dispose message - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME, - "Wlan message header crc was wrong: %u != %u\n", - GNUNET_CRYPTO_crc32_n ((char *) wlanheader, - ntohs (wlanheader->header.size)), - crc); - hexdump ((void *) hdr, ntohs (hdr->size)); - return; + GNUNET_break (0); + break; } - - //if not in session list - if (session == NULL) + GNUNET_STATISTICS_update (plugin->env->stats, _("# ACKs received via WLAN"), + 1, GNUNET_NO); + for (fm = mas->endpoint->sending_messages_head; NULL != fm; fm = fm->next) { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "WLAN client not in session list: packet size = %u, inner size = %u, header size = %u\n", - ntohs (wlanheader->header.size), ntohs (temp_hdr->size), - sizeof (struct WlanHeader)); - //try if it is a hello message - if (ntohs (wlanheader->header.size) >= - ntohs (temp_hdr->size) + sizeof (struct WlanHeader)) + ret = GNUNET_FRAGMENT_process_ack (fm->fragcontext, hdr); + if (GNUNET_OK == ret) { - if (ntohs (temp_hdr->type) == GNUNET_MESSAGE_TYPE_HELLO) - { - if (GNUNET_HELLO_get_id - ((const struct GNUNET_HELLO_Message *) temp_hdr, - &tmpsource) == GNUNET_OK) - { - session = create_session (plugin, endpoint, &tmpsource); - } - else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME, - "WLAN client not in session list and hello message is not okay\n"); - return; - } - - } - else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME, - "WLAN client not in session list and not a hello message\n"); - return; - } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got last ACK, finished message transmission to `%s' (%p)\n", + mac_to_string (&mas->endpoint->addr), + fm); + mas->endpoint->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT); + if (NULL != fm->cont) + { + fm->cont (fm->cont_cls, &fm->target, GNUNET_OK); + fm->cont = NULL; + } + free_fragment_message (fm); + break; } - else + if (GNUNET_NO == ret) { - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME, - "WLAN client not in session list and message size in does not fit\npacket size = %u, inner size = %u, header size = %u\n", - ntohs (wlanheader->header.size), - ntohs (temp_hdr->size), sizeof (struct WlanHeader)); - return; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got an ACK, message transmission to `%s' not yet finished\n", + mac_to_string (&mas->endpoint->addr)); + break; } } - - //"receive" the message - - if (memcmp - (&wlanheader->source, &session->target, - sizeof (struct GNUNET_PeerIdentity)) != 0) + LOG (GNUNET_ERROR_TYPE_DEBUG, + "ACK not matched against any active fragmentation with MAC `%s'\n", + mac_to_string (&mas->endpoint->addr)); + break; + case GNUNET_MESSAGE_TYPE_WLAN_DATA: + if (NULL == mas->endpoint) { - //wrong peer id - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "WLAN peer source id doesn't match packet peer source id: session %p\n", - session); - return; + GNUNET_break (0); + break; } - - if (memcmp - (&wlanheader->target, plugin->env->my_identity, - sizeof (struct GNUNET_PeerIdentity)) != 0) + if (msize < sizeof (struct WlanHeader)) { - //wrong peer id - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "WLAN peer target id doesn't match our peer id: session %p\n", - session); - return; + GNUNET_break (0); + break; + } + wlanheader = (const struct WlanHeader *) hdr; + if (0 != memcmp (&wlanheader->target, + plugin->env->my_identity, + sizeof (struct GNUNET_PeerIdentity))) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "WLAN data for `%s', not for me, ignoring\n", + GNUNET_i2s (&wlanheader->target)); + break; } - - GNUNET_SERVER_mst_receive (plugin->data_tokenizer, session, - (const char *) temp_hdr, - ntohs (hdr->size) - sizeof (struct WlanHeader), - GNUNET_YES, GNUNET_NO); - - return; - } - else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME, - "wlan_data_message_handler got wrong message type: %u\n", - ntohs (hdr->size)); - return; + if (ntohl (wlanheader->crc) != + GNUNET_CRYPTO_crc32_n (&wlanheader[1], msize - sizeof (struct WlanHeader))) + { + GNUNET_STATISTICS_update (plugin->env->stats, + _("# WLAN DATA messages discarded due to CRC32 error"), 1, + GNUNET_NO); + break; + } + xmas.endpoint = mas->endpoint; + xmas.session = create_session (mas->endpoint, &wlanheader->sender); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing %u bytes of WLAN DATA from peer `%s'\n", + (unsigned int) msize, + GNUNET_i2s (&wlanheader->sender)); + (void) GNUNET_SERVER_mst_receive (plugin->wlan_header_payload_tokenizer, + &xmas, + (const char *) &wlanheader[1], + msize - sizeof (struct WlanHeader), + GNUNET_YES, GNUNET_NO); + break; + default: + if (NULL == mas->endpoint) + { + GNUNET_break (0); + break; + } + if (NULL == mas->session) + { + GNUNET_break (0); + break; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received packet with %u bytes of type %u from peer %s\n", + (unsigned int) msize, + (unsigned int) ntohs (hdr->type), + GNUNET_i2s (&mas->session->target)); + plugin->env->receive (plugin->env->cls, + &mas->session->target, + hdr, + ats, NUM_ATS, + mas->session, + (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr, + (mas->endpoint == NULL) ? 0 : sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); + break; } + return GNUNET_OK; } +#undef NUM_ATS -/** - * function to process the a message, give it to the higher layer - * @param cls pointer to the plugin - * @param client pointer to the session this message belongs to - * @param hdr start of the message - */ -//TODO ATS informations -static void -process_data (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) -{ - - GNUNET_assert (client != NULL); - GNUNET_assert (cls != NULL); - struct Session *session = (struct Session *) client; - struct Plugin *plugin = (struct Plugin *) cls; - struct GNUNET_ATS_Information ats[2]; - - ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); - ats[0].value = htonl (1); - ats[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); - ats[1].value = htonl (GNUNET_ATS_NET_WLAN); - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Calling plugin->env->receive for session %p; %s; size: %u\n", - session, wlan_plugin_address_to_string (NULL, - session->mac-> - addr.mac, 6), - htons (hdr->size)); - plugin->env->receive (plugin->env->cls, &(session->target), hdr, - (const struct GNUNET_ATS_Information *) &ats, 2, - session, (const char *) &session->mac->addr, - sizeof (session->mac->addr)); -} /** - * Function used for to process the data received from the wlan interface + * Function used for to process the data from the suid process * * @param cls the plugin handle - * @param session_light pointer to the struct holding known informations - * @param hdr hdr of the GNUNET_MessageHeader - * @param rxinfo pointer to the radiotap informations got with this packet FIXME: give ATS for info + * @param client client that send the data (not used) + * @param hdr header of the GNUNET_MessageHeader */ -static void -wlan_data_helper (void *cls, struct Session_light *session_light, - const struct GNUNET_MessageHeader *hdr, - const struct Radiotap_rx *rxinfo) +static int +handle_helper_message (void *cls, void *client, + const struct GNUNET_MessageHeader *hdr) { struct Plugin *plugin = cls; - struct FragmentMessage *fm; - struct FragmentMessage *fm2; - struct GNUNET_PeerIdentity tmpsource; + const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rxinfo; + const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *cm; + struct MacAndSession mas; + uint16_t msize; - GNUNET_assert (plugin != NULL); - - //ADVERTISEMENT - if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_HELLO) + msize = ntohs (hdr->size); + switch (ntohs (hdr->type)) { - - //TODO better DOS protection, error handling - //TODO test first than create session - GNUNET_assert (session_light != NULL); - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_HELLO size: %u; %s\n", - ntohs (hdr->size), wlan_plugin_address_to_string (NULL, - session_light->addr. - mac, 6)); - if (session_light->macendpoint == NULL) - { - session_light->macendpoint = - get_macendpoint (plugin, &session_light->addr, GNUNET_YES); - } - - - if (GNUNET_HELLO_get_id - ((const struct GNUNET_HELLO_Message *) hdr, &tmpsource) == GNUNET_OK) - { - session_light->session = - search_session (plugin, session_light->macendpoint, &tmpsource); - if (session_light->session == NULL) - { - session_light->session = - create_session (plugin, session_light->macendpoint, &tmpsource); - } - GNUNET_STATISTICS_update (plugin->env->stats, - _("# wlan hello messages received"), 1, - GNUNET_NO); - plugin->env->receive (plugin->env->cls, &session_light->session->target, - hdr, NULL, 0, session_light->session, - (const char *) &session_light->session->mac->addr, - sizeof (session_light->session->mac->addr)); - } - else + case GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL: + if (msize != sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage)) { - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME, - "WLAN client not in session list and hello message is not okay\n"); - return; + GNUNET_break (0); + break; } - } - - //FRAGMENT - - else if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_FRAGMENT) - { - - GNUNET_assert (session_light != NULL); - if (session_light->macendpoint == NULL) + cm = (const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *) hdr; + if (GNUNET_YES == plugin->have_mac) { - session_light->macendpoint = - get_macendpoint (plugin, &session_light->addr, GNUNET_YES); + if (0 == memcmp (&plugin->mac_address, + &cm->mac, + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) + break; /* no change */ + /* remove old address */ + plugin->env->notify_address (plugin->env->cls, GNUNET_NO, + &plugin->mac_address, + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); } - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_FRAGMENT with size: %u; mac endpoint %p: %s\n", - ntohs (hdr->size), session_light->macendpoint, - wlan_plugin_address_to_string (NULL, - session_light->addr.mac, - 6)); + plugin->mac_address = cm->mac; + plugin->have_mac = GNUNET_YES; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received WLAN_HELPER_CONTROL message with MAC address `%s' for peer `%s'\n", + mac_to_string (&cm->mac), + GNUNET_i2s (plugin->env->my_identity)); + plugin->env->notify_address (plugin->env->cls, GNUNET_YES, + &plugin->mac_address, + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); + break; + case GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER: + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got data message from helper with %u bytes\n", + msize); GNUNET_STATISTICS_update (plugin->env->stats, - _("# wlan fragments received"), 1, GNUNET_NO); - int ret = - GNUNET_DEFRAGMENT_process_fragment (session_light->macendpoint->defrag, - hdr); - - if (ret == GNUNET_NO) - { - session_light->macendpoint->dups++; - } - else if (ret == GNUNET_OK) + _("# DATA messages received via WLAN"), 1, + GNUNET_NO); + if (msize < sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)) { - session_light->macendpoint->fragc++; + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Size of packet is too small (%u bytes)\n", + msize); + break; } - set_next_send (plugin); - - } + rxinfo = (const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) hdr; - //ACK - - else if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_FRAGMENT_ACK) - { - GNUNET_assert (session_light != NULL); - if (session_light->macendpoint == NULL) + /* check if message is actually for us */ + if (0 != memcmp (&rxinfo->frame.addr3, &mac_bssid_gnunet, + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) { - session_light->macendpoint = - get_macendpoint (plugin, &session_light->addr, GNUNET_NO); + /* Not the GNUnet BSSID */ + break; } - - if (session_light->macendpoint == NULL) + if ( (0 != memcmp (&rxinfo->frame.addr1, &bc_all_mac, + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) && + (0 != memcmp (&rxinfo->frame.addr1, &plugin->mac_address, + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) ) { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Macendpoint does not exist for this GNUNET_MESSAGE_TYPE_FRAGMENT_ACK size: %u; %s\n", - ntohs (hdr->size), wlan_plugin_address_to_string (NULL, - session_light->addr.mac, - 6)); - return; + /* Neither broadcast nor specifically for us */ + break; } - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_FRAGMENT_ACK size: %u; mac endpoint: %p; %s\n", - ntohs (hdr->size), session_light->macendpoint, - wlan_plugin_address_to_string (NULL, - session_light->addr.mac, - 6)); - fm = session_light->macendpoint->sending_messages_head; - while (fm != NULL) + if (0 == memcmp (&rxinfo->frame.addr2, &plugin->mac_address, + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) { - fm2 = fm->next; - GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan acks received"), - 1, GNUNET_NO); - int ret = GNUNET_FRAGMENT_process_ack (fm->fragcontext, hdr); - - if (ret == GNUNET_OK) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Got last ack, finished fragment message %p\n", fm); - session_light->macendpoint->acks++; - fm->session->last_activity = GNUNET_TIME_absolute_get (); - session_light->macendpoint->last_activity = fm->session->last_activity; - free_fragment_message (plugin, fm); - check_fragment_queue (plugin); - return; - } - if (ret == GNUNET_NO) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Got ack for: %p\n", fm); - session_light->macendpoint->acks++; - return; - } - if (ret == GNUNET_SYSERR) - { - - } - - fm = fm2; + /* packet is FROM us, thus not FOR us */ + break; } - - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "WLAN fragment not in fragment list\n"); - return; - - } - else - { - // TODO Wrong data? - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME, - "WLAN packet inside the WLAN helper packet has not the right type: %u size: %u\n", - ntohs (hdr->type), ntohs (hdr->size)); + + GNUNET_STATISTICS_update (plugin->env->stats, + _("# WLAN DATA messages processed"), + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Receiving %u bytes of data from MAC `%s'\n", + (unsigned int) (msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)), + mac_to_string (&rxinfo->frame.addr2)); + mas.endpoint = create_macendpoint (plugin, &rxinfo->frame.addr2); + mas.session = NULL; + (void) GNUNET_SERVER_mst_receive (plugin->helper_payload_tokenizer, + &mas, + (const char*) &rxinfo[1], + msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage), + GNUNET_YES, GNUNET_NO); + break; + default: GNUNET_break (0); - return; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Unexpected message of type %u (%u bytes)", + ntohs (hdr->type), ntohs (hdr->size)); + break; } + return GNUNET_OK; +} -#if 0 - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Helper finished\n"); -#endif -} /** - * Function to print mac addresses nice * - * @param pointer to 6 byte with the mac address - * @return pointer to the chars which hold the print out + * Task to (periodically) send a HELLO beacon + * + * @param cls pointer to the plugin struct + * @param tc scheduler context */ -static const char * -macprinter (const u_int8_t * mac) +static void +send_hello_beacon (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { - static char macstr[20]; + struct Plugin *plugin = cls; + uint16_t size; + uint16_t hello_size; + struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radioHeader; + const struct GNUNET_MessageHeader *hello; + + hello = plugin->env->get_our_hello (); + hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello); + GNUNET_assert (sizeof (struct WlanHeader) + hello_size <= WLAN_MTU); + size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + hello_size; + { + char buf[size] GNUNET_ALIGN; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending %u byte HELLO beacon\n", + (unsigned int) size); + radioHeader = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage*) buf; + get_radiotap_header (NULL, radioHeader, size); + get_wlan_header (plugin, &radioHeader->frame, &bc_all_mac, size); + memcpy (&radioHeader[1], hello, hello_size); + if (NULL != + GNUNET_HELPER_send (plugin->suid_helper, + &radioHeader->header, + GNUNET_YES /* can drop */, + NULL, NULL)) + GNUNET_STATISTICS_update (plugin->env->stats, _("# HELLO beacons sent via WLAN"), + 1, GNUNET_NO); + } + plugin->beacon_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (HELLO_BEACON_SCALING_FACTOR, + plugin->mac_count + 1), + &send_hello_beacon, + plugin); - GNUNET_snprintf (macstr, sizeof (macstr), "%X:%X:%X:%X:%X:%X", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5]); - return macstr; } + /** - * Function for the scheduler if a mac endpoint times out - * @param cls pointer to the MacEndpoint - * @param tc pointer to the GNUNET_SCHEDULER_TaskContext + * Another peer has suggested an address for this + * peer and transport plugin. Check that this could be a valid + * address. If so, consider adding it to the list + * of addresses. + * + * @param cls closure + * @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 */ -static void -macendpoint_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +static int +wlan_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) { - struct MacEndpoint *endpoint = cls; + struct Plugin *plugin = cls; - GNUNET_assert (endpoint != NULL); - endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK; - if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) - { - return; + if (addrlen != sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; } - if (GNUNET_TIME_absolute_get_remaining - (GNUNET_TIME_absolute_add - (endpoint->last_activity, MACENDPOINT_TIMEOUT)).rel_value == 0) + if (GNUNET_YES != plugin->have_mac) { - GNUNET_assert (endpoint->plugin != NULL); - GNUNET_STATISTICS_update (endpoint->plugin->env->stats, - _("# wlan mac endpoints timeouts"), 1, GNUNET_NO); - free_macendpoint (endpoint->plugin, endpoint); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Rejecting MAC `%s': I don't know my MAC!\n", + mac_to_string (addr)); + return GNUNET_NO; /* don't know my MAC */ } - else + if (0 != memcmp (addr, + &plugin->mac_address, + addrlen)) { - endpoint->timeout_task = - GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout, - endpoint); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Rejecting MAC `%s': not my MAC!\n", + mac_to_string (addr)); + return GNUNET_NO; /* not my MAC */ } + return GNUNET_OK; } + /** - * function to create an macendpoint - * @param plugin pointer to the plugin struct - * @param addr pointer to the macaddress - * @return returns a macendpoint + * 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 struct MacEndpoint * -create_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr) +static const char * +wlan_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) { - struct MacEndpoint *newend = GNUNET_malloc (sizeof (struct MacEndpoint)); - - GNUNET_assert (plugin != NULL); - GNUNET_STATISTICS_update (plugin->env->stats, - _("# wlan mac endpoints created"), 1, GNUNET_NO); - newend->addr = *addr; - newend->plugin = plugin; - newend->addr = *addr; - newend->fragment_messages_out_count = 0; - newend->defrag = - GNUNET_DEFRAGMENT_context_create (plugin->env->stats, WLAN_MTU, - MESSAGES_IN_DEFRAG_QUEUE_PER_MAC, - newend, &wlan_data_message_handler, - &add_ack_for_send); - newend->last_activity = GNUNET_TIME_absolute_get (); - newend->timeout_task = - GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout, - newend); + const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac; - plugin->mac_count++; - GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"), - plugin->mac_count, GNUNET_NO); - GNUNET_CONTAINER_DLL_insert_tail (plugin->mac_head, plugin->mac_tail, newend); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "New Mac Endpoint %p: %s\n", newend, - wlan_plugin_address_to_string (NULL, newend->addr.mac, 6)); - return newend; + if (sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress) != addrlen) + { + GNUNET_break (0); + return NULL; + } + mac = addr; + return GNUNET_strdup (mac_to_string (mac)); } + /** - * Function used for to process the data from the suid process + * Convert the transports address to a nice, human-readable format. * - * @param cls the plugin handle - * @param client client that send the data (not used) - * @param hdr header of the GNUNET_MessageHeader + * @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 -wlan_process_helper (void *cls, void *client, - const struct GNUNET_MessageHeader *hdr) +wlan_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 ieee80211_frame *wlanIeeeHeader = NULL; - struct Session_light *session_light = NULL; - struct Radiotap_rx *rxinfo; - const struct GNUNET_MessageHeader *temp_hdr = NULL; - - int datasize = 0; - int pos; + const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac; + char *ret; - GNUNET_assert (plugin != NULL); - switch (ntohs (hdr->type)) + if (sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress) != addrlen) { - case GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA: - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Func wlan_process_helper got GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA size: %u\n", - ntohs (hdr->size)); - GNUNET_STATISTICS_update (plugin->env->stats, - _("# wlan WLAN_HELPER_DATA received"), 1, - GNUNET_NO); - //call wlan_process_helper with the message inside, later with wlan: analyze signal - if (ntohs (hdr->size) < - sizeof (struct ieee80211_frame) + - 2 * sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_rx)) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Size of packet is too small; size: %u min size: %u\n", - ntohs (hdr->size), - sizeof (struct ieee80211_frame) + - sizeof (struct GNUNET_MessageHeader)); - //GNUNET_break (0); - /* FIXME: restart SUID process */ - return; - } - - rxinfo = (struct Radiotap_rx *) &hdr[1]; - wlanIeeeHeader = (struct ieee80211_frame *) &rxinfo[1]; - - //process only if it is an broadcast or for this computer both with the gnunet bssid - - //check for bssid - if (memcmp - (&(wlanIeeeHeader->i_addr3), &mac_bssid_gnunet, - sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0) - { - //check for broadcast or mac - if ((memcmp - (&(wlanIeeeHeader->i_addr1), &bc_all_mac, - sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0) || - (memcmp - (&(wlanIeeeHeader->i_addr1), &(plugin->mac_address), - sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)) - { - //if packet is from us return - if ((memcmp - (&(wlanIeeeHeader->i_addr2), &(plugin->mac_address), - sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)) - { - return; - } - // process the inner data - - - datasize = - ntohs (hdr->size) - sizeof (struct ieee80211_frame) - - sizeof (struct GNUNET_MessageHeader) - sizeof (struct Radiotap_rx); - - session_light = GNUNET_malloc (sizeof (struct Session_light)); - memcpy (&session_light->addr, &(wlanIeeeHeader->i_addr2), - sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); - //session_light->session = search_session(plugin,session_light->addr); - GNUNET_STATISTICS_update (plugin->env->stats, - _("# wlan messages for this client received"), - 1, GNUNET_NO); - - pos = 0; - while (pos < datasize) - { - temp_hdr = (struct GNUNET_MessageHeader *) &wlanIeeeHeader[1] + pos; - if (ntohs (temp_hdr->size) <= datasize + pos) - { - GNUNET_STATISTICS_update (plugin->env->stats, - _ - ("# wlan messages inside WLAN_HELPER_DATA received"), - 1, GNUNET_NO); - wlan_data_helper (plugin, session_light, temp_hdr, rxinfo); - } - else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Size of packet is too small; size: %u > size of packet: %u\n", - ntohs (temp_hdr->size), datasize + pos); - } - pos += ntohs (temp_hdr->size); - - } - - //clean up - GNUNET_free (session_light); - } - else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Func wlan_process_helper got wrong MAC: %s\n", - macprinter (wlanIeeeHeader->i_addr1)); - } - } - else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Func wlan_process_helper got wrong BSSID: %s\n", - macprinter (wlanIeeeHeader->i_addr2)); - } - break; - case GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL: - //TODO more control messages - if (ntohs (hdr->size) != sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage)) - { - GNUNET_break (0); - /* FIXME: restart SUID process */ - return; - } - memcpy (&plugin->mac_address, &hdr[1], sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Received WLAN_HELPER_CONTROL message with transport of address %s\n", - wlan_plugin_address_to_string (cls, &plugin->mac_address, - sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))); - plugin->env->notify_address (plugin->env->cls, GNUNET_YES, - &plugin->mac_address, - sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); - break; - default: - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "Func wlan_process_helper got unknown message with number %u, size %u\n", - ntohs (hdr->type), ntohs (hdr->size)); - -#if DEBUG_WLAN > 1 - hexdump (hdr, GNUNET_MIN (ntohs (hdr->size), 256)); -#endif - GNUNET_break (0); + /* invalid address */ + LOG (GNUNET_ERROR_TYPE_WARNING, + _("WLAN address with invalid size encountered\n")); + asc (asc_cls, NULL); return; } + mac = addr; + ret = GNUNET_strdup (mac_to_string (mac)); + asc (asc_cls, ret); + GNUNET_free (ret); + asc (asc_cls, NULL); } + /** - * Exit point from the plugin. + * Exit point from the plugin. + * * @param cls pointer to the api struct */ - -//FIXME cleanup void * libgnunet_plugin_transport_wlan_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; - struct MacEndpoint *endpoint = plugin->mac_head; + struct MacEndpoint *endpoint; struct MacEndpoint *endpoint_next; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "libgnunet_plugin_transport_wlan_done started\n"); - wlan_transport_stop_wlan_helper (plugin); - - GNUNET_assert (cls != NULL); - //free sessions - while (endpoint != NULL) + if (NULL == plugin) + { + GNUNET_free (api); + return NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != plugin->beacon_task) + { + GNUNET_SCHEDULER_cancel (plugin->beacon_task); + plugin->beacon_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != plugin->suid_helper) + { + GNUNET_HELPER_stop (plugin->suid_helper); + plugin->suid_helper = NULL; + } + endpoint_next = plugin->mac_head; + while (NULL != (endpoint = endpoint_next)) { endpoint_next = endpoint->next; - free_macendpoint (plugin, endpoint); - endpoint = endpoint_next; - + free_macendpoint (endpoint); + } + if (NULL != plugin->fragment_data_tokenizer) + { + GNUNET_SERVER_mst_destroy (plugin->fragment_data_tokenizer); + plugin->fragment_data_tokenizer = NULL; + } + if (NULL != plugin->wlan_header_payload_tokenizer) + { + GNUNET_SERVER_mst_destroy (plugin->wlan_header_payload_tokenizer); + plugin->wlan_header_payload_tokenizer = NULL; + } + if (NULL != plugin->helper_payload_tokenizer) + { + GNUNET_SERVER_mst_destroy (plugin->helper_payload_tokenizer); + plugin->helper_payload_tokenizer = NULL; } - - - if (plugin->suid_tokenizer != NULL) - GNUNET_SERVER_mst_destroy (plugin->suid_tokenizer); - - if (plugin->data_tokenizer != NULL) - GNUNET_SERVER_mst_destroy (plugin->data_tokenizer); - GNUNET_free_non_null (plugin->interface); GNUNET_free (plugin); GNUNET_free (api); return NULL; } + +/** + * Function called to convert a string address to + * a binary address. + * + * @param cls closure ('struct Plugin*') + * @param addr string address + * @param addrlen length of the address + * @param buf location to store the buffer + * @param added location to store the number of bytes in the buffer. + * If the function returns GNUNET_SYSERR, its contents are undefined. + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +static int +wlan_string_to_address (void *cls, const char *addr, uint16_t addrlen, + void **buf, size_t *added) +{ + struct GNUNET_TRANSPORT_WLAN_MacAddress *mac; + unsigned int a[6]; + unsigned int i; + + if ((NULL == addr) || (addrlen == 0)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if ('\0' != addr[addrlen - 1]) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (strlen (addr) != addrlen - 1) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (6 != SSCANF (addr, + "%X:%X:%X:%X:%X:%X", + &a[0], &a[1], &a[2], &a[3], &a[4], &a[5])) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + mac = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); + for (i=0;i<6;i++) + mac->mac[i] = a[i]; + *buf = mac; + *added = sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress); + return GNUNET_OK; +} + + /** * Entry point for the plugin. * @@ -3129,35 +1636,107 @@ libgnunet_plugin_transport_wlan_done (void *cls) void * libgnunet_plugin_transport_wlan_init (void *cls) { - //struct GNUNET_SERVICE_Context *service; struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; struct GNUNET_TRANSPORT_PluginFunctions *api; struct Plugin *plugin; - - GNUNET_assert (cls != NULL); + char *interface; + unsigned long long testmode; + + /* check for 'special' mode */ + if (NULL == env->receive) + { + /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully + initialze the plugin or the API */ + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = NULL; + api->address_pretty_printer = &wlan_plugin_address_pretty_printer; + api->address_to_string = &wlan_plugin_address_to_string; + api->string_to_address = &wlan_string_to_address; + return api; + } + + testmode = 0; + /* check configuration */ + if ( (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "TESTMODE")) && + ( (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-wlan", + "TESTMODE", &testmode)) || + (testmode > 2) ) ) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Invalid configuration option `%s' in section `%s'\n"), + "TESTMODE", + "transport-wlan"); + return NULL; + } + if ( (0 == testmode) && + (GNUNET_YES != GNUNET_OS_check_helper_binary ("gnunet-helper-transport-wlan")) ) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Helper binary `%s' not SUID, cannot run WLAN transport\n"), + "gnunet-helper-transport-wlan"); + return NULL; + } + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string + (env->cfg, "transport-wlan", "INTERFACE", + &interface)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Missing configuration option `%s' in section `%s'\n"), + "INTERFACE", + "transport-wlan"); + return NULL; + } plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->interface = interface; plugin->env = env; - plugin->pendingsessions = 0; - GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), - plugin->pendingsessions, GNUNET_NO); - plugin->mac_count = 0; - GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"), - plugin->mac_count, GNUNET_NO); - plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK; - plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK; - plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_STATISTICS_set (plugin->env->stats, _("# WLAN sessions allocated"), + 0, GNUNET_NO); + GNUNET_STATISTICS_set (plugin->env->stats, _("# WLAN MAC endpoints allocated"), + 0, 0); GNUNET_BANDWIDTH_tracker_init (&plugin->tracker, GNUNET_BANDWIDTH_value_init (100 * 1024 * 1024 / 8), 100); - - plugin->suid_tokenizer = - GNUNET_SERVER_mst_create (&wlan_process_helper, plugin); - - plugin->data_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin); - - //plugin->sessions = GNUNET_malloc (sizeof (struct Sessionqueue)); - //plugin->pending_Sessions_head = GNUNET_malloc (sizeof (struct Sessionqueue)); + plugin->fragment_data_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin); + plugin->wlan_header_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin); + plugin->helper_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin); + plugin->beacon_task = GNUNET_SCHEDULER_add_now (&send_hello_beacon, + plugin); + switch (testmode) + { + case 0: /* normal */ + plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan"; + plugin->helper_argv[1] = interface; + plugin->helper_argv[2] = NULL; + plugin->suid_helper = GNUNET_HELPER_start ("gnunet-helper-transport-wlan", + plugin->helper_argv, + &handle_helper_message, + plugin); + break; + case 1: /* testmode, peer 1 */ + plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan-dummy"; + plugin->helper_argv[1] = (char *) "1"; + plugin->helper_argv[2] = NULL; + plugin->suid_helper = GNUNET_HELPER_start ("gnunet-helper-transport-wlan-dummy", + plugin->helper_argv, + &handle_helper_message, + plugin); + break; + case 2: /* testmode, peer 2 */ + plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan-dummy"; + plugin->helper_argv[1] = (char *) "2"; + plugin->helper_argv[2] = NULL; + plugin->suid_helper = GNUNET_HELPER_start ("gnunet-helper-transport-wlan-dummy", + plugin->helper_argv, + &handle_helper_message, + plugin); + break; + default: + GNUNET_assert (0); + } api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = plugin; @@ -3167,35 +1746,9 @@ libgnunet_plugin_transport_wlan_init (void *cls) api->address_pretty_printer = &wlan_plugin_address_pretty_printer; api->check_address = &wlan_plugin_address_suggested; api->address_to_string = &wlan_plugin_address_to_string; - - //read config - - if (GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "TESTMODE")) - { - if (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-wlan", - "TESTMODE", &(plugin->testmode))) - plugin->testmode = 0; //default value - } - - if (GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "INTERFACE")) - { - if (GNUNET_CONFIGURATION_get_value_string - (env->cfg, "transport-wlan", "INTERFACE", - &(plugin->interface)) != GNUNET_YES) - { - libgnunet_plugin_transport_wlan_done (api); - return NULL; - } - } - - //start the plugin - wlan_transport_start_wlan_helper (plugin); - set_next_beacon_time (plugin); - set_next_send (plugin); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, - "wlan init finished\n"); + api->string_to_address = &wlan_string_to_address; return api; } + /* end of plugin_transport_wlan.c */ diff --git a/src/transport/plugin_transport_wlan.h b/src/transport/plugin_transport_wlan.h index 9e1bc4f..2b70fc0 100644 --- a/src/transport/plugin_transport_wlan.h +++ b/src/transport/plugin_transport_wlan.h @@ -34,7 +34,27 @@ */ #define MAC_ADDR_SIZE 6 +/** + * Value for "Management" in the 'frame_control' field of the + * struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame. + */ +#define IEEE80211_FC0_TYPE_MGT 0x00 + +/** + * Value for "Control" in the 'frame_control' field of the + * struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame. + */ +#define IEEE80211_FC0_TYPE_CTL 0x04 + +/** + * Value for DATA in the 'frame_control' field of the + * struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame. + */ +#define IEEE80211_FC0_TYPE_DATA 0x08 + + GNUNET_NETWORK_STRUCT_BEGIN + /** * A MAC Address. */ @@ -59,26 +79,73 @@ struct GNUNET_TRANSPORT_WLAN_HelperControlMessage */ struct GNUNET_TRANSPORT_WLAN_MacAddress mac; }; -GNUNET_NETWORK_STRUCT_END + /** - * GNUnet bssid + * generic definitions for IEEE 802.11 frames */ -static const struct GNUNET_TRANSPORT_WLAN_MacAddress mac_bssid_gnunet = { - {0x13, 0x22, 0x33, 0x44, 0x55, 0x66} -}; +struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame +{ + /** + * 802.11 Frame Control field. A bitmask. The overall field is a + * 16-bit mask of the respecitve fields. The lowest two bits should + * be 0, then comes the "type" (2 bits, see IEEE80211_FC0_TYPE_* + * constants), followed by 4-bit subtype (all zeros for ad-hoc), + * followed by various flags (to DS, from DS, more frag, retry, + * power management, more data, WEP, strict), all of which we also + * keep at zero. + */ + uint16_t frame_control GNUNET_PACKED; + + /** + * Microseconds to reserve link (duration), 0 by default + */ + uint16_t duration GNUNET_PACKED; + + /** + * Address 1: destination address in ad-hoc mode or AP, BSSID if station, + */ + struct GNUNET_TRANSPORT_WLAN_MacAddress addr1; + + /** + * Address 2: source address if in ad-hoc-mode or station, BSSID if AP + */ + struct GNUNET_TRANSPORT_WLAN_MacAddress addr2; + + /** + * Address 3: BSSID in ad-hoc mode, Destination if station, source if AP + */ + struct GNUNET_TRANSPORT_WLAN_MacAddress addr3; + + /** + * 802.11 sequence control field; contains fragment number an sequence + * number (we set this to all zeros). + */ + uint16_t sequence_control GNUNET_PACKED; + + /** + * Link layer control (LLC). Set to a GNUnet-specific value. + */ + u_int8_t llc[4]; + + /* payload */ + +} GNUNET_PACKED; + /** - * Broadcast MAC + * Message from the plugin to the WLAN helper: send the given message with the + * given connection parameters. */ -static const struct GNUNET_TRANSPORT_WLAN_MacAddress bc_all_mac = { - {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} -}; +struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage +{ + /** + * Type is 'GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER'. + */ + struct GNUNET_MessageHeader header; -struct Radiotap_Send -{ /** * wlan send rate */ @@ -93,60 +160,100 @@ struct Radiotap_Send * Transmit power expressed as unitless distance from max power set at factory calibration. * 0 is max power. Monotonically nondecreasing with lower power levels. */ - uint16_t tx_power; + uint16_t tx_power GNUNET_PACKED; + + /** + * IEEE Frame to transmit (the sender MAC address will be overwritten by the helper as it does not + * trust the plugin to set it correctly). + */ + struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame frame; + + /* actual payload follows */ }; /** + * Message from the WLAN helper to the plugin: we have received the given message with the + * given performance characteristics. + */ +/** * struct to represent infos gathered form the radiotap fields, see RadiotapHeader for more Infos */ -struct Radiotap_rx +struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage { + + /** + * Type is 'GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER'. + */ + struct GNUNET_MessageHeader header; + /** - * FIXME: not initialized properly so far. (supposed to contain - * information about which of the fields below are actually valid). + * Information about which of the fields below are actually valid. + * 0 for none. FIXME: not properly initialized so far (always zero). */ - uint32_t ri_present; + uint32_t ri_present GNUNET_PACKED; /** - * IEEE80211_RADIOTAP_TSFT + * IEEE80211_RADIOTAP_TSFT, 0 if unknown. */ - uint64_t ri_mactime; + uint64_t ri_mactime GNUNET_PACKED; /** * from radiotap * either IEEE80211_RADIOTAP_DBM_ANTSIGNAL - * or IEEE80211_RADIOTAP_DB_ANTSIGNAL + * or IEEE80211_RADIOTAP_DB_ANTSIGNAL, 0 if unknown. */ - int32_t ri_power; + int32_t ri_power GNUNET_PACKED; /** * either IEEE80211_RADIOTAP_DBM_ANTNOISE - * or IEEE80211_RADIOTAP_DB_ANTNOISE + * or IEEE80211_RADIOTAP_DB_ANTNOISE, 0 if unknown. */ - int32_t ri_noise; + int32_t ri_noise GNUNET_PACKED; /** - * IEEE80211_RADIOTAP_CHANNEL + * IEEE80211_RADIOTAP_CHANNEL, 0 if unknown. */ - uint32_t ri_channel; + uint32_t ri_channel GNUNET_PACKED; /** - * Frequency we use. FIXME: not properly initialized so far! + * Frequency we use. 0 if unknown. */ - uint32_t ri_freq; + uint32_t ri_freq GNUNET_PACKED; /** - * IEEE80211_RADIOTAP_RATE * 50000 + * IEEE80211_RADIOTAP_RATE * 50000, 0 if unknown. */ - uint32_t ri_rate; + uint32_t ri_rate GNUNET_PACKED; /** - * IEEE80211_RADIOTAP_ANTENNA + * IEEE80211_RADIOTAP_ANTENNA, 0 if unknown. */ - uint32_t ri_antenna; + uint32_t ri_antenna GNUNET_PACKED; + + /** + * IEEE Frame. + */ + struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame frame; + + /* followed by payload */ }; +GNUNET_NETWORK_STRUCT_END +/** + * GNUnet bssid + */ +static const struct GNUNET_TRANSPORT_WLAN_MacAddress mac_bssid_gnunet = { + {0x13, 0x22, 0x33, 0x44, 0x55, 0x66} +}; + + +/** + * Broadcast MAC + */ +static const struct GNUNET_TRANSPORT_WLAN_MacAddress bc_all_mac = { + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} +}; #endif diff --git a/src/transport/template_cfg_peer1.conf b/src/transport/template_cfg_peer1.conf index ba05e93..2b8e9b2 100644 --- a/src/transport/template_cfg_peer1.conf +++ b/src/transport/template_cfg_peer1.conf @@ -17,6 +17,9 @@ TIMEOUT = 5 s [transport-udp] BROADCAST = NO +[transport-unix] +PORT = 12007 + [arm] PORT = 12005 DEFAULTSERVICES = transport diff --git a/src/transport/template_cfg_peer2.conf b/src/transport/template_cfg_peer2.conf index 0a0e74a..3b86137 100644 --- a/src/transport/template_cfg_peer2.conf +++ b/src/transport/template_cfg_peer2.conf @@ -17,6 +17,9 @@ TIMEOUT = 5 s [transport-udp] BROADCAST = NO +[transport-unix] +PORT = 12017 + [arm] PORT = 12014 DEFAULTSERVICES = transport diff --git a/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf b/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf index a7bac62..8a1dad5 100644 --- a/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf +++ b/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf @@ -27,6 +27,7 @@ UNIXPATH = /tmp/test_quota_compliance_tcp_peerinfo_peer1.sock [transport] PORT = 4091 +PLUGINS = tcp UNIXPATH = /tmp/test_quota_compliance_tcp_transport_peer1.sock diff --git a/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf b/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf index 75a4fe9..bbfa8ec 100644 --- a/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf +++ b/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf @@ -26,5 +26,6 @@ UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock diff --git a/src/transport/test_quota_compliance_tcp_peer1.conf b/src/transport/test_quota_compliance_tcp_peer1.conf index ff63514..29e56fe 100644 --- a/src/transport/test_quota_compliance_tcp_peer1.conf +++ b/src/transport/test_quota_compliance_tcp_peer1.conf @@ -27,6 +27,7 @@ UNIXPATH = /tmp/test_quota_compliance_tcp_peerinfo_peer1.sock [transport] PORT = 4091 +PLUGINS = tcp UNIXPATH = /tmp/test_quota_compliance_tcp_transport_peer1.sock diff --git a/src/transport/test_quota_compliance_tcp_peer2.conf b/src/transport/test_quota_compliance_tcp_peer2.conf index 18b199c..5da60d0 100644 --- a/src/transport/test_quota_compliance_tcp_peer2.conf +++ b/src/transport/test_quota_compliance_tcp_peer2.conf @@ -26,5 +26,6 @@ UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock diff --git a/src/transport/test_transport_api.c b/src/transport/test_transport_api.c index 5fb81e1..f944fac 100644 --- a/src/transport/test_transport_api.c +++ b/src/transport/test_transport_api.c @@ -37,8 +37,6 @@ #include "transport.h" #include "transport-testing.h" -#define VERBOSE GNUNET_NO -#define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES @@ -52,9 +50,9 @@ */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) -#define MSIZE 2600 +#define TEST_MESSAGE_SIZE 2600 -#define MTYPE 12345 +#define TEST_MESSAGE_TYPE 12345 static char *test_source; @@ -65,32 +63,29 @@ static char *test_name; static int ok; static int s_started; + static int s_connected; + static int s_sending; static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier send_task; -struct PeerContext *p1; +static struct PeerContext *p1; -struct PeerContext *p2; +static struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; -struct GNUNET_TRANSPORT_TransmitHandle *th; +static struct GNUNET_TRANSPORT_TransmitHandle *th; -struct GNUNET_TRANSPORT_TESTING_handle *tth; +static struct GNUNET_TRANSPORT_TESTING_handle *tth; -char *cfg_file_p1; +static char *cfg_file_p1; -char *cfg_file_p2; +static char *cfg_file_p2; -#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 static void end () @@ -135,9 +130,9 @@ end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not ready to send data\n")); if (s_started == GNUNET_NO) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were not started n")); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were not started \n")); else - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were started n")); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were started \n")); if (s_connected == GNUNET_NO) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not connected\n")); @@ -186,8 +181,8 @@ notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, GNUNET_i2s (&t->id)); GNUNET_free (ps); - if ((MTYPE == ntohs (message->type)) && - (MSIZE == ntohs (message->size))) + if ((TEST_MESSAGE_TYPE == ntohs (message->type)) && + (TEST_MESSAGE_SIZE == ntohs (message->size))) { ok = 0; end (); @@ -220,13 +215,13 @@ notify_ready (void *cls, size_t size, void *buf) return 0; } - GNUNET_assert (size >= MSIZE); - + GNUNET_assert (size >= TEST_MESSAGE_SIZE); if (buf != NULL) { + memset (buf, '\0', TEST_MESSAGE_SIZE); hdr = buf; - hdr->size = htons (MSIZE); - hdr->type = htons (MTYPE); + hdr->size = htons (TEST_MESSAGE_SIZE); + hdr->type = htons (TEST_MESSAGE_TYPE); } char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); @@ -236,7 +231,7 @@ notify_ready (void *cls, size_t size, void *buf) GNUNET_i2s (&p->id)); GNUNET_free (ps); - return MSIZE; + return TEST_MESSAGE_SIZE; } @@ -254,7 +249,7 @@ sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); GNUNET_free (receiver_s); s_sending = GNUNET_YES; - th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, MSIZE, 0, + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, TEST_MESSAGE_SIZE, 0, TIMEOUT_TRANSMIT, ¬ify_ready, p1); } @@ -302,6 +297,7 @@ notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) th = NULL; } + static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { @@ -317,8 +313,7 @@ testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) } - -void +static void start_cb (struct PeerContext *p, void *cls) { static int started; @@ -344,6 +339,7 @@ start_cb (struct PeerContext *p, void *cls) } + static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) @@ -381,9 +377,6 @@ check () static char *const argv[] = { "test-transport-api", "-c", "test_transport_api_data.conf", -#if VERBOSE - "-L", "DEBUG", -#endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { @@ -413,13 +406,8 @@ main (int argc, char *argv[]) &test_plugin); GNUNET_log_setup (test_name, -#if VERBOSE - "DEBUG", -#else "WARNING", -#endif NULL); - tth = GNUNET_TRANSPORT_TESTING_init (); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); diff --git a/src/transport/test_transport_api_bidirectional_connect.c b/src/transport/test_transport_api_bidirectional_connect.c index 604554c..2c4eeab 100644 --- a/src/transport/test_transport_api_bidirectional_connect.c +++ b/src/transport/test_transport_api_bidirectional_connect.c @@ -35,10 +35,6 @@ #include "transport.h" #include "transport-testing.h" -#define VERBOSE GNUNET_NO -#define VERBOSE_ARM GNUNET_NO - -#define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? @@ -64,26 +60,20 @@ static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier send_task; -struct PeerContext *p1; +static struct PeerContext *p1; -struct PeerContext *p2; +static struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc1; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc2; -struct GNUNET_TRANSPORT_TransmitHandle *th; - -struct GNUNET_TRANSPORT_TESTING_handle *tth; +static struct GNUNET_TRANSPORT_TransmitHandle *th; -char *cfg_file_p1; +static struct GNUNET_TRANSPORT_TESTING_handle *tth; -char *cfg_file_p2; +static char *cfg_file_p1; -#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 +static char *cfg_file_p2; static void @@ -97,9 +87,11 @@ end () if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); - if (th != NULL) + if (NULL != th) + { GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); - th = NULL; + th = NULL; + } GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); @@ -109,24 +101,27 @@ static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); - - if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); - if (cc2 != NULL) + if (NULL != cc2) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc2); cc2 = NULL; } - - if (th != NULL) + if (NULL != cc1) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc1); + cc1 = NULL; + } + if (NULL != th) + { GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); - th = NULL; - + th = NULL; + } if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) @@ -270,6 +265,7 @@ notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) th = NULL; } + static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { @@ -293,7 +289,8 @@ testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); } -void + +static void start_cb (struct PeerContext *p, void *cls) { static int started; @@ -353,9 +350,6 @@ check () static char *const argv[] = { "test-transport-api", "-c", "test_transport_api_data.conf", -#if VERBOSE - "-L", "DEBUG", -#endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { @@ -382,11 +376,7 @@ main (int argc, char *argv[]) GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, -#if VERBOSE - "DEBUG", -#else "WARNING", -#endif NULL); GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); diff --git a/src/transport/test_transport_api_bidirectional_connect_peer1.conf b/src/transport/test_transport_api_bidirectional_connect_peer1.conf index 21591b5..49fc662 100644 --- a/src/transport/test_transport_api_bidirectional_connect_peer1.conf +++ b/src/transport/test_transport_api_bidirectional_connect_peer1.conf @@ -3,29 +3,44 @@ SERVICEHOME = /tmp/test-transport/api-tcp-p1/ DEFAULTCONFIG = test_transport_api_bidirectional_connect_peer1.conf -[transport-tcp] -PORT = 12000 -TIMEOUT = 5 s - [arm] -PORT = 12005 +PORT = 12000 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] -PORT = 12004 +PORT = 12001 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] -PORT = 12003 +PORT = 12002 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] -PORT = 12002 +PORT = 12003 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] -PORT = 12001 +PORT = 12004 UNIXPATH = /tmp/gnunet-p1-service-transport.sock #DEBUG = YES +[transport-tcp] +PORT = 12005 +TIMEOUT = 5 s + +[transport-udp] +PORT = 12006 +TIMEOUT = 5 s + +[transport-unix] +PORT = 12007 +TIMEOUT = 5 s + +[transport-http] +PORT = 12008 +TIMEOUT = 5 s + +[transport-https] +PORT = 12009 +TIMEOUT = 5 s
\ No newline at end of file diff --git a/src/transport/test_transport_api_bidirectional_connect_peer2.conf b/src/transport/test_transport_api_bidirectional_connect_peer2.conf index db3ba8c..2d64351 100644 --- a/src/transport/test_transport_api_bidirectional_connect_peer2.conf +++ b/src/transport/test_transport_api_bidirectional_connect_peer2.conf @@ -3,17 +3,13 @@ SERVICEHOME = /tmp/test-transport/api-tcp-p2/ DEFAULTCONFIG = test_transport_api_bidirectional_connect_peer2.conf -[transport-tcp] -PORT = 12015 -TIMEOUT = 5 s - [arm] -PORT = 12014 +PORT = 12010 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] -PORT = 12013 +PORT = 12011 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] @@ -21,10 +17,29 @@ PORT = 12012 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] -PORT = 12011 +PORT = 12013 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] -PORT = 12010 +PORT = 12014 UNIXPATH = /tmp/gnunet-p2-service-transport.sock +[transport-tcp] +PORT = 12015 +TIMEOUT = 5 s + +[transport-udp] +PORT = 12016 +TIMEOUT = 5 s + +[transport-unix] +PORT = 12017 +TIMEOUT = 5 s + +[transport-http] +PORT = 12018 +TIMEOUT = 5 s + +[transport-https] +PORT = 12019 +TIMEOUT = 5 s
\ No newline at end of file diff --git a/src/transport/test_transport_api_blacklisting.c b/src/transport/test_transport_api_blacklisting.c index f8f6040..909ea57 100644 --- a/src/transport/test_transport_api_blacklisting.c +++ b/src/transport/test_transport_api_blacklisting.c @@ -61,9 +61,9 @@ struct GNUNET_TRANSPORT_TESTING_handle *tth; */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) -#define MSIZE 2600 +#define TEST_MESSAGE_SIZE 2600 -#define MTYPE 12345 +#define TEST_MESSAGE_TYPE 12345 static int ok; @@ -212,8 +212,8 @@ notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, GNUNET_i2s (&t->id)); GNUNET_free (ps); - if ((MTYPE == ntohs (message->type)) && - (MSIZE == ntohs (message->size))) + if ((TEST_MESSAGE_TYPE == ntohs (message->type)) && + (TEST_MESSAGE_SIZE == ntohs (message->size))) { ok = 0; shutdown_task = GNUNET_SCHEDULER_add_now(&end, NULL); @@ -249,13 +249,13 @@ notify_ready (void *cls, size_t size, void *buf) return 0; } - GNUNET_assert (size >= MSIZE); + GNUNET_assert (size >= TEST_MESSAGE_SIZE); if (buf != NULL) { hdr = buf; - hdr->size = htons (MSIZE); - hdr->type = htons (MTYPE); + hdr->size = htons (TEST_MESSAGE_SIZE); + hdr->type = htons (TEST_MESSAGE_TYPE); } char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); @@ -265,7 +265,7 @@ notify_ready (void *cls, size_t size, void *buf) GNUNET_i2s (&p->id)); GNUNET_free (ps); - return MSIZE; + return TEST_MESSAGE_SIZE; } static void @@ -282,7 +282,7 @@ sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); GNUNET_free (receiver_s); - th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, MSIZE, 0, + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, TEST_MESSAGE_SIZE, 0, TIMEOUT_TRANSMIT, ¬ify_ready, p1); } diff --git a/src/transport/test_transport_api_disconnect_tcp_peer1.conf b/src/transport/test_transport_api_disconnect_tcp_peer1.conf index 8bfa374..ebb4fd4 100644 --- a/src/transport/test_transport_api_disconnect_tcp_peer1.conf +++ b/src/transport/test_transport_api_disconnect_tcp_peer1.conf @@ -26,6 +26,7 @@ UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12001 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock #DEBUG = YES diff --git a/src/transport/test_transport_api_disconnect_tcp_peer2.conf b/src/transport/test_transport_api_disconnect_tcp_peer2.conf index 6bb7fad..fe6d19b 100644 --- a/src/transport/test_transport_api_disconnect_tcp_peer2.conf +++ b/src/transport/test_transport_api_disconnect_tcp_peer2.conf @@ -26,5 +26,6 @@ UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock diff --git a/src/transport/test_transport_api_limited_sockets.c b/src/transport/test_transport_api_limited_sockets.c index 8b8cdc0..e6ad84a 100644 --- a/src/transport/test_transport_api_limited_sockets.c +++ b/src/transport/test_transport_api_limited_sockets.c @@ -18,7 +18,7 @@ Boston, MA 02111-1307, USA. */ /** - * @file transport/test_transport_api.c + * @file transport/test_transport_api_limited_sockets.c * @brief base test case for transport implementations * * This test case serves as a base for tcp, udp, and udp-nat @@ -69,19 +69,19 @@ static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier send_task; -struct PeerContext *p1; +static struct PeerContext *p1; -struct PeerContext *p2; +static struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; -struct GNUNET_TRANSPORT_TransmitHandle *th; +static struct GNUNET_TRANSPORT_TransmitHandle *th; -struct GNUNET_TRANSPORT_TESTING_handle *tth; +static struct GNUNET_TRANSPORT_TESTING_handle *tth; -char *cfg_file_p1; +static char *cfg_file_p1; -char *cfg_file_p2; +static char *cfg_file_p2; #if VERBOSE #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) @@ -228,7 +228,7 @@ testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &sendtask, NULL); } -void +static void start_cb (struct PeerContext *p, void *cls) { static int started; @@ -334,11 +334,10 @@ main (int argc, char *argv[]) int res; res = getrlimit (RLIMIT_NOFILE, &r_file_old); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Maximum number of open files was: %u/%u\n", r_file_old.rlim_cur, r_file_old.rlim_max); - - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting maximum number of open files to: %u\n", MAX_FILES); r_file_new.rlim_cur = MAX_FILES; r_file_new.rlim_max = r_file_old.rlim_max; @@ -367,7 +366,7 @@ main (int argc, char *argv[]) GNUNET_free (test_name); #if HAVE_SETRLIMIT - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restoring previous value maximum number of open files\n"); res = setrlimit (RLIMIT_NOFILE, &r_file_old); if (res != 0) @@ -376,8 +375,7 @@ main (int argc, char *argv[]) return 0; } #endif - return ret; } -/* end of test_transport_api.c */ +/* end of test_transport_api_limited_sockets.c */ diff --git a/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf b/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf index dee44f6..d29b946 100644 --- a/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf +++ b/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf @@ -26,6 +26,7 @@ UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12001 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock diff --git a/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf b/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf index 04324f4..3c0e496 100644 --- a/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf +++ b/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf @@ -26,5 +26,6 @@ UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock diff --git a/src/transport/test_transport_api_reliability.c b/src/transport/test_transport_api_reliability.c index f719a42..759241c 100644 --- a/src/transport/test_transport_api_reliability.c +++ b/src/transport/test_transport_api_reliability.c @@ -243,7 +243,7 @@ notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, 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", n, + "Expected message %u with bits %u, but body did not match at position %u\n", n, (unsigned char) n); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); diff --git a/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf b/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf index 2f0b3ba..ffd3d2f 100644 --- a/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf +++ b/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf @@ -31,6 +31,7 @@ UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 29542 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock diff --git a/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf b/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf index 20ca7a0..c6020ff 100644 --- a/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf +++ b/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf @@ -30,6 +30,7 @@ UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 45923 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock diff --git a/src/transport/test_transport_api_reliability_tcp_peer1.conf b/src/transport/test_transport_api_reliability_tcp_peer1.conf index a05165a..3be982d 100644 --- a/src/transport/test_transport_api_reliability_tcp_peer1.conf +++ b/src/transport/test_transport_api_reliability_tcp_peer1.conf @@ -26,5 +26,6 @@ UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12001 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock diff --git a/src/transport/test_transport_api_reliability_tcp_peer2.conf b/src/transport/test_transport_api_reliability_tcp_peer2.conf index 2ceff2c..62575a9 100644 --- a/src/transport/test_transport_api_reliability_tcp_peer2.conf +++ b/src/transport/test_transport_api_reliability_tcp_peer2.conf @@ -26,5 +26,6 @@ UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock #DEBUG = YES diff --git a/src/transport/test_transport_api_restart_1peer.c b/src/transport/test_transport_api_restart_1peer.c index b414805..b7fc7ab 100644 --- a/src/transport/test_transport_api_restart_1peer.c +++ b/src/transport/test_transport_api_restart_1peer.c @@ -36,8 +36,6 @@ #include "transport.h" #include "transport-testing.h" -#define VERBOSE GNUNET_NO -#define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES @@ -63,32 +61,26 @@ static GNUNET_SCHEDULER_TaskIdentifier send_task; static GNUNET_SCHEDULER_TaskIdentifier reconnect_task; -struct PeerContext *p1; +static struct PeerContext *p1; -int p1_connected; +static int p1_connected; -struct PeerContext *p2; +static struct PeerContext *p2; -int p2_connected; +static int p2_connected; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; -struct GNUNET_TRANSPORT_TransmitHandle *th; +static struct GNUNET_TRANSPORT_TransmitHandle *th; -struct GNUNET_TRANSPORT_TESTING_handle *tth; +static struct GNUNET_TRANSPORT_TESTING_handle *tth; -char *cfg_file_p1; +static char *cfg_file_p1; -char *cfg_file_p2; +static char *cfg_file_p2; static int restarted; -#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 - static void end () @@ -112,7 +104,9 @@ end () th = NULL; GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + p1 = NULL; GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + p2 = NULL; } static void @@ -338,16 +332,16 @@ notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *p = cls; - if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + if ( (NULL != p1) && + (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))) { p1_connected = GNUNET_NO; } - if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + if ( (NULL != p2) && + (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))) { p2_connected = GNUNET_NO; } - - char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -358,6 +352,9 @@ notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; + if (GNUNET_SCHEDULER_NO_TASK != send_task) + GNUNET_SCHEDULER_cancel (send_task); + send_task = GNUNET_SCHEDULER_NO_TASK; } static void @@ -375,7 +372,7 @@ testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) -void +static void start_cb (struct PeerContext *p, void *cls) { static int started; @@ -434,9 +431,6 @@ check () static char *const argv[] = { "test-transport-api", "-c", "test_transport_api_data.conf", -#if VERBOSE - "-L", "DEBUG", -#endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { @@ -461,30 +455,17 @@ main (int argc, char *argv[]) int ret; GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); - - GNUNET_log_setup (test_name, -#if VERBOSE - "DEBUG", -#else "WARNING", -#endif NULL); - tth = GNUNET_TRANSPORT_TESTING_init (); - GNUNET_asprintf (&cfg_file_p1, "test_transport_api_tcp_peer1.conf"); GNUNET_asprintf (&cfg_file_p2, "test_transport_api_tcp_peer2.conf"); - ret = check (); - GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); - GNUNET_free (test_name); - GNUNET_TRANSPORT_TESTING_done (tth); - return ret; } diff --git a/src/transport/test_transport_api_restart_2peers.c b/src/transport/test_transport_api_restart_2peers.c index 86758df..1d7790c 100644 --- a/src/transport/test_transport_api_restart_2peers.c +++ b/src/transport/test_transport_api_restart_2peers.c @@ -36,20 +36,17 @@ #include "transport.h" #include "transport-testing.h" -#define VERBOSE GNUNET_NO -#define VERBOSE_ARM GNUNET_NO - #define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90) /** * How long until we give up on transmitting the message? */ -#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) #define MTYPE 12345 @@ -63,34 +60,27 @@ static GNUNET_SCHEDULER_TaskIdentifier send_task; static GNUNET_SCHEDULER_TaskIdentifier reconnect_task; -struct PeerContext *p1; +static struct PeerContext *p1; -struct PeerContext *p2; +static struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; -struct GNUNET_TRANSPORT_TransmitHandle *th; +static struct GNUNET_TRANSPORT_TransmitHandle *th; -struct GNUNET_TRANSPORT_TESTING_handle *tth; +static struct GNUNET_TRANSPORT_TESTING_handle *tth; -char *cfg_file_p1; +static char *cfg_file_p1; -char *cfg_file_p2; +static char *cfg_file_p2; static int restarted; -#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 - static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); - if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); send_task = GNUNET_SCHEDULER_NO_TASK; @@ -111,18 +101,17 @@ end () GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); } + static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); - if (restarted == GNUNET_YES) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was restarted\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was restarted, but communication did not resume\n"); if (restarted == GNUNET_NO) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was NOT restarted\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was NOT (even) restarted\n"); if (reconnect_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (reconnect_task); @@ -151,35 +140,34 @@ end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) ok = GNUNET_SYSERR; } + static void reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerContext *p = cls; reconnect_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_TRANSPORT_try_connect (p1->th, &p2->id); reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, p); } + static void restart_cb (struct PeerContext *p, void *cls) { static int c; c++; - if (c != 2) return; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarted peer %u (`%4s'), issuing reconnect\n", p->no, GNUNET_i2s (&p->id)); - reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, p); } + static void restart (struct PeerContext *p, char *cfg_file) { @@ -187,9 +175,9 @@ restart (struct PeerContext *p, char *cfg_file) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarting peer %u (`%4s')\n", p->no, GNUNET_i2s (&p->id)); GNUNET_TRANSPORT_TESTING_restart_peer (tth, p, cfg_file, &restart_cb, p); - return; } + static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, @@ -248,7 +236,6 @@ notify_ready (void *cls, size_t size, void *buf) struct GNUNET_MessageHeader *hdr; th = NULL; - if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -345,8 +332,12 @@ notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; + if (GNUNET_SCHEDULER_NO_TASK != send_task) + GNUNET_SCHEDULER_cancel (send_task); + send_task = GNUNET_SCHEDULER_NO_TASK; } + static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { @@ -361,8 +352,7 @@ testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) } - -void +static void start_cb (struct PeerContext *p, void *cls) { static int started; @@ -387,6 +377,7 @@ start_cb (struct PeerContext *p, void *cls) } + static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) @@ -420,9 +411,6 @@ check () static char *const argv[] = { "test-transport-api", "-c", "test_transport_api_data.conf", -#if VERBOSE - "-L", "DEBUG", -#endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { @@ -436,41 +424,29 @@ check () ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, - "nohelp", options, &run, &ok); + "nohelp", options, &run, NULL); return ok; } + int main (int argc, char *argv[]) { int ret; GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); - - GNUNET_log_setup (test_name, -#if VERBOSE - "DEBUG", -#else "WARNING", -#endif NULL); - tth = GNUNET_TRANSPORT_TESTING_init (); - GNUNET_asprintf (&cfg_file_p1, "test_transport_api_tcp_peer1.conf"); GNUNET_asprintf (&cfg_file_p2, "test_transport_api_tcp_peer2.conf"); - ret = check (); - GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); - GNUNET_free (test_name); - GNUNET_TRANSPORT_TESTING_done (tth); - return ret; } diff --git a/src/transport/test_transport_api_tcp_nat_peer1.conf b/src/transport/test_transport_api_tcp_nat_peer1.conf index 78afb3d..73f36f3 100644 --- a/src/transport/test_transport_api_tcp_nat_peer1.conf +++ b/src/transport/test_transport_api_tcp_nat_peer1.conf @@ -31,6 +31,7 @@ UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 29542 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock #DEBUG = YES diff --git a/src/transport/test_transport_api_tcp_nat_peer2.conf b/src/transport/test_transport_api_tcp_nat_peer2.conf index d94ebb1..0bf50fd 100644 --- a/src/transport/test_transport_api_tcp_nat_peer2.conf +++ b/src/transport/test_transport_api_tcp_nat_peer2.conf @@ -30,5 +30,6 @@ UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 45923 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock #DEBUG = YES diff --git a/src/transport/test_transport_api_tcp_peer1.conf b/src/transport/test_transport_api_tcp_peer1.conf index 8bfa374..9532b73 100644 --- a/src/transport/test_transport_api_tcp_peer1.conf +++ b/src/transport/test_transport_api_tcp_peer1.conf @@ -27,5 +27,6 @@ UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12001 UNIXPATH = /tmp/gnunet-p1-service-transport.sock +PLUGINS = tcp #DEBUG = YES diff --git a/src/transport/test_transport_api_tcp_peer2.conf b/src/transport/test_transport_api_tcp_peer2.conf index 6bb7fad..fe6d19b 100644 --- a/src/transport/test_transport_api_tcp_peer2.conf +++ b/src/transport/test_transport_api_tcp_peer2.conf @@ -26,5 +26,6 @@ UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock diff --git a/src/transport/test_transport_api_timeout.c b/src/transport/test_transport_api_timeout.c index 9ce701a..8b92dce 100644 --- a/src/transport/test_transport_api_timeout.c +++ b/src/transport/test_transport_api_timeout.c @@ -40,8 +40,6 @@ #define VERBOSE GNUNET_NO -#define VERBOSE_ARM GNUNET_NO - #define START_ARM GNUNET_YES /** @@ -65,19 +63,19 @@ static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier timer_task; -struct GNUNET_TRANSPORT_TESTING_handle *tth; +static struct GNUNET_TRANSPORT_TESTING_handle *tth; -struct PeerContext *p1; +static struct PeerContext *p1; -struct PeerContext *p2; +static struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; -struct GNUNET_TRANSPORT_TransmitHandle *th; +static struct GNUNET_TRANSPORT_TransmitHandle *th; -char *cfg_file_p1; +static char *cfg_file_p1; -char *cfg_file_p2; +static char *cfg_file_p2; static struct GNUNET_TIME_Relative time_running; @@ -192,6 +190,7 @@ notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) th = NULL; } + static void timer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { @@ -235,7 +234,7 @@ testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) shutdown_flag = GNUNET_NO; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Waiting for %llu seconds\n", (WAIT.rel_value) / 1000); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Waiting for %llu seconds\n", (WAIT.rel_value) / 1000); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); @@ -244,7 +243,8 @@ testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) timer_task = GNUNET_SCHEDULER_add_now (&timer, NULL); } -void + +static void start_cb (struct PeerContext *p, void *cls) { static int started; @@ -299,9 +299,6 @@ check () static char *const argv[] = { "test-transport-api-timeout", "-c", "test_transport_api_data.conf", -#if VERBOSE - "-L", "DEBUG", -#endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { @@ -329,11 +326,7 @@ main (int argc, char *argv[]) GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, -#if VERBOSE - "DEBUG", -#else "WARNING", -#endif NULL); GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); diff --git a/src/transport/test_transport_api_timeout_tcp_peer1.conf b/src/transport/test_transport_api_timeout_tcp_peer1.conf index 89beecb..ecb599f 100644 --- a/src/transport/test_transport_api_timeout_tcp_peer1.conf +++ b/src/transport/test_transport_api_timeout_tcp_peer1.conf @@ -26,6 +26,7 @@ UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12001 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock diff --git a/src/transport/test_transport_api_timeout_tcp_peer2.conf b/src/transport/test_transport_api_timeout_tcp_peer2.conf index a21c4f5..ba2e27e 100644 --- a/src/transport/test_transport_api_timeout_tcp_peer2.conf +++ b/src/transport/test_transport_api_timeout_tcp_peer2.conf @@ -28,6 +28,7 @@ UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 +PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock diff --git a/src/transport/test_transport_defaults.conf b/src/transport/test_transport_defaults.conf index f553377..0939a79 100644 --- a/src/transport/test_transport_defaults.conf +++ b/src/transport/test_transport_defaults.conf @@ -41,9 +41,15 @@ AUTOSTART = NO [chat] AUTOSTART = NO +[namestore] +AUTOSTART = NO + [vpn] AUTOSTART = NO +[lockmanager] +AUTOSTART = NO + [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 diff --git a/src/transport/transport-testing.c b/src/transport/transport-testing.c index 752106b..695c048 100644 --- a/src/transport/transport-testing.c +++ b/src/transport/transport-testing.c @@ -52,6 +52,7 @@ get_host_key (struct GNUNET_TRANSPORT_TESTING_handle *tth) return NULL; } + static struct PeerContext * find_peer_context (struct GNUNET_TRANSPORT_TESTING_handle *tth, const struct GNUNET_PeerIdentity *peer) @@ -69,7 +70,8 @@ find_peer_context (struct GNUNET_TRANSPORT_TESTING_handle *tth, return t; } -struct ConnectingContext * + +static struct ConnectingContext * find_connecting_context (struct GNUNET_TRANSPORT_TESTING_handle *tth, struct PeerContext *p1, struct PeerContext *p2) { @@ -88,6 +90,7 @@ find_connecting_context (struct GNUNET_TRANSPORT_TESTING_handle *tth, return cc; } + static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) @@ -134,6 +137,7 @@ notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, } } + static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { @@ -167,6 +171,7 @@ notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) p->nd (p->cb_cls, peer); } + static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, @@ -180,6 +185,7 @@ notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, p->rec (p->cb_cls, peer, message, ats, ats_count); } + static void get_hello (void *cb_cls, const struct GNUNET_MessageHeader *message) { @@ -307,11 +313,7 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, -#if VERBOSE_PEERS - "-L", "DEBUG", -#else "-L", "ERROR", -#endif NULL); p->no = peer_id; @@ -361,10 +363,8 @@ GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle GNUNET_assert (p->servicehome != NULL); /* shutdown */ -#if VERBOSE GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Stopping peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id)); -#endif if (p->ghh != NULL) GNUNET_TRANSPORT_get_hello_cancel (p->ghh); p->ghh = NULL; @@ -377,7 +377,7 @@ GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle 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); + GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } if (p->hello != NULL) @@ -390,11 +390,8 @@ GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle /* start */ -#if VERBOSE GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Restarting peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id)); -#endif - sleep (5); // YUCK! if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO) @@ -424,11 +421,7 @@ GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, -#if VERBOSE_PEERS - "-L", "DEBUG", -#else "-L", "ERROR", -#endif NULL); p->th = @@ -451,6 +444,7 @@ fail: return GNUNET_SYSERR; } + /** * shutdown the given peer * @param tth testing handle @@ -461,53 +455,49 @@ GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth, struct PeerContext *p) { GNUNET_assert (p != NULL); - if (p->ghh != NULL) + { GNUNET_TRANSPORT_get_hello_cancel (p->ghh); - p->ghh = NULL; - + p->ghh = NULL; + } if (p->th != NULL) GNUNET_TRANSPORT_disconnect (p->th); - if (NULL != p->arm_proc) { 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); + GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } - if (p->hostkeyfile != NULL) { GNUNET_DISK_directory_remove (p->hostkeyfile); GNUNET_free (p->hostkeyfile); } - if (p->servicehome != NULL) { GNUNET_DISK_directory_remove (p->servicehome); GNUNET_free (p->servicehome); } - if (p->hello != NULL) + { GNUNET_free (p->hello); - p->hello = NULL; - + p->hello = NULL; + } if (p->cfg != NULL) + { GNUNET_CONFIGURATION_destroy (p->cfg); - p->cfg = NULL; - + p->cfg = NULL; + } GNUNET_CONTAINER_DLL_remove (tth->p_head, tth->p_tail, p); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Peer %u (`%s') stopped \n", p->no, GNUNET_i2s (&p->id)); - GNUNET_free (p); - p = NULL; } + /** * Connect the given peers and call the callback when both peers report the * inbound connection. Remarks: start_peer's notify_connect callback can be called @@ -534,24 +524,18 @@ GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle * GNUNET_assert (p1 != NULL); GNUNET_assert (p2 != NULL); - cc->p1 = p1; cc->p2 = p2; - cc->cb = cb; if (cls != NULL) cc->cb_cls = cls; else cc->cb_cls = cc; - cc->th_p1 = p1->th; cc->th_p2 = p2->th; - GNUNET_assert (cc->th_p1 != NULL); GNUNET_assert (cc->th_p2 != NULL); - GNUNET_CONTAINER_DLL_insert (tth->cc_head, tth->cc_tail, cc); - cc->tct = GNUNET_SCHEDULER_add_now (&try_connect, cc); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "New connect request %X\n", cc); @@ -559,6 +543,7 @@ GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle * return cc; } + /** * Cancel the request to connect two peers * Tou MUST cancel the request if you stop the peers before the peers connected succesfully @@ -627,6 +612,7 @@ GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_handle *tth) tth = NULL; } + /** * Initialize the transport testing * @return transport testing handle @@ -661,7 +647,7 @@ GNUNET_TRANSPORT_TESTING_init () return NULL; } - if (GNUNET_YES != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES)) + if (GNUNET_OK != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES, GNUNET_YES)) fs = 0; if (0 != (fs % HOSTKEYFILESIZE)) @@ -722,6 +708,7 @@ extract_filename (const char *file) return res; } + /** * Extracts the test filename from an absolute file name and removes the extension * @param file absolute file name @@ -781,7 +768,8 @@ GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file, char **dest) /** - * Extracts the plugin anme from an absolute file name and the test name + * Extracts the plugin name from an absolute file name and the test name + * * @param file absolute file name * @param test test name * @param dest where to store result @@ -790,43 +778,39 @@ void GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file, const char *test, char **dest) { + char *filename; + char *dotexe; char *e = extract_filename (file); char *t = extract_filename (test); - char *filename = NULL; - char *dotexe; - - if (e == NULL) + if (NULL == e) goto fail; - /* remove "lt-" */ filename = strstr (e, "tes"); - if (filename == NULL) + if (NULL == filename) goto fail; - /* remove ".exe" */ if (NULL != (dotexe = strstr (filename, ".exe"))) dotexe[0] = '\0'; /* find last _ */ filename = strstr (filename, t); - if (filename == NULL) + if (NULL == filename) goto fail; - /* copy plugin */ filename += strlen (t); - filename++; + if ('\0' != *filename) + filename++; GNUNET_asprintf (dest, "%s", filename); goto suc; - fail: (*dest) = NULL; suc: GNUNET_free (t); GNUNET_free (e); - } + /** * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and * if existing ".exe"-prefix and adds the peer-number @@ -843,30 +827,23 @@ GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, char **dest, char *backup = filename; char *dotexe; - if (filename == NULL) + if (NULL == filename) goto fail; - /* remove "lt-" */ filename = strstr (filename, "tes"); - if (filename == NULL) + if (NULL == filename) goto fail; - /* remove ".exe" */ if (NULL != (dotexe = strstr (filename, ".exe"))) dotexe[0] = '\0'; - - goto suc; - + GNUNET_asprintf (dest, "%s_peer%u.conf", filename, count); + GNUNET_free (backup); + return; fail: (*dest) = NULL; - return; - -suc: - /* create cfg filename */ - GNUNET_asprintf (dest, "%s_peer%u.conf", filename, count); GNUNET_free (backup); } -/* end of transport_testing.h */ +/* end of transport-testing.c */ diff --git a/src/transport/transport.conf.in b/src/transport/transport.conf.in index ff81ff0..9a6f5d9 100644 --- a/src/transport/transport.conf.in +++ b/src/transport/transport.conf.in @@ -9,7 +9,7 @@ BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; -PLUGINS = tcp +PLUGINS = tcp udp UNIXPATH = /tmp/gnunet-service-transport.sock BLACKLIST_FILE = $SERVICEHOME/blacklist # This could possibly be relaxed @@ -25,6 +25,8 @@ UNIX_MATCH_GID = YES # REJECT_FROM6 = # PREFIX = valgrind --leak-check=full +[transport-unix] +PORT = 22086 [transport-tcp] # Use 0 to ONLY advertise as a peer behind NAT (no port binding) diff --git a/src/transport/transport.h b/src/transport/transport.h index ff68188..e0b8819 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -33,11 +33,6 @@ #define DEBUG_TRANSPORT GNUNET_EXTRA_LOGGING -#define DEBUG_TRANSPORT_TIMEOUT GNUNET_EXTRA_LOGGING - -#define DEBUG_TRANSPORT_DISCONNECT GNUNET_EXTRA_LOGGING - -#define DEBUG_TRANSPORT_API GNUNET_EXTRA_LOGGING /** * For how long do we allow unused bandwidth @@ -289,7 +284,7 @@ struct AddressLookupMessage { /** - * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING */ struct GNUNET_MessageHeader header; diff --git a/src/transport/transport_api.c b/src/transport/transport_api.c index 9ff5cec..b97a245 100644 --- a/src/transport/transport_api.c +++ b/src/transport/transport_api.c @@ -342,10 +342,8 @@ neighbour_add (struct GNUNET_TRANSPORT_Handle *h, { struct Neighbour *n; -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating entry for neighbour `%4s'.\n", GNUNET_i2s (pid)); -#endif n = GNUNET_malloc (sizeof (struct Neighbour)); n->id = *pid; n->h = h; @@ -416,10 +414,8 @@ demultiplexer (void *cls, const struct GNUNET_MessageHeader *msg) GNUNET_assert (h->client != NULL); if (msg == NULL) { -#if DEBUG_TRANSPORT_API - LOG (GNUNET_ERROR_TYPE_INFO, + LOG (GNUNET_ERROR_TYPE_DEBUG, "Error receiving from transport service, disconnecting temporarily.\n"); -#endif disconnect_and_schedule_reconnect (h); return; } @@ -435,11 +431,9 @@ demultiplexer (void *cls, const struct GNUNET_MessageHeader *msg) GNUNET_break (0); break; } -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving (my own) `%s' message, I am `%4s'.\n", "HELLO", GNUNET_i2s (&me)); -#endif GNUNET_free_non_null (h->my_hello); h->my_hello = NULL; if (size < sizeof (struct GNUNET_MessageHeader)) @@ -474,10 +468,8 @@ demultiplexer (void *cls, const struct GNUNET_MessageHeader *msg) break; } ats = (const struct GNUNET_ATS_Information *) &cim[1]; -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message for `%4s'.\n", "CONNECT", GNUNET_i2s (&cim->id)); -#endif n = neighbour_find (h, &cim->id); if (n != NULL) { @@ -496,10 +488,8 @@ demultiplexer (void *cls, const struct GNUNET_MessageHeader *msg) } dim = (const struct DisconnectInfoMessage *) msg; GNUNET_break (ntohl (dim->reserved) == 0); -#if DEBUG_TRANSPORT_API_DISCONNECT LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message for `%4s'.\n", "DISCONNECT", GNUNET_i2s (&dim->peer)); -#endif n = neighbour_find (h, &dim->peer); if (n == NULL) { @@ -515,10 +505,8 @@ demultiplexer (void *cls, const struct GNUNET_MessageHeader *msg) break; } okm = (const struct SendOkMessage *) msg; -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message, transmission %s.\n", "SEND_OK", ntohl (okm->success) == GNUNET_OK ? "succeeded" : "failed"); -#endif n = neighbour_find (h, &okm->peer); if (n == NULL) break; @@ -536,9 +524,7 @@ demultiplexer (void *cls, const struct GNUNET_MessageHeader *msg) } break; case GNUNET_MESSAGE_TYPE_TRANSPORT_RECV: -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message.\n", "RECV"); -#endif if (size < sizeof (struct InboundMessage) + sizeof (struct GNUNET_MessageHeader)) { @@ -555,10 +541,8 @@ demultiplexer (void *cls, const struct GNUNET_MessageHeader *msg) GNUNET_break (0); break; } -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u from `%4s'.\n", ntohs (imm->type), GNUNET_i2s (&im->peer)); -#endif n = neighbour_find (h, &im->peer); if (n == NULL) { @@ -569,9 +553,7 @@ demultiplexer (void *cls, const struct GNUNET_MessageHeader *msg) h->rec (h->cls, &im->peer, imm, ats, ats_count); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA: -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message.\n", "SET_QUOTA"); -#endif if (size != sizeof (struct QuotaSetMessage)) { GNUNET_break (0); @@ -653,10 +635,8 @@ transport_notify_ready (void *cls, size_t size, void *buf) { GNUNET_CONTAINER_DLL_remove (h->control_head, h->control_tail, th); nret = th->notify (th->notify_cls, size, &cbuf[ret]); -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Added %u bytes of control message at %u\n", nret, ret); -#endif GNUNET_free (th); ret += nret; size -= nret; @@ -714,10 +694,8 @@ transport_notify_ready (void *cls, size_t size, void *buf) } /* if there are more pending messages, try to schedule those */ schedule_transmission (h); -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u bytes to transport service\n", ret); -#endif return ret; } @@ -750,11 +728,9 @@ schedule_transmission_task (void *cls, n->th = NULL; GNUNET_assert (n == GNUNET_CONTAINER_heap_remove_root (h->ready_heap)); n->hn = NULL; -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Signalling timeout for transmission to peer %s due to congestion\n", GNUNET_i2s (&n->id)); -#endif GNUNET_assert (0 == th->notify (th->notify_cls, 0, NULL)); GNUNET_free (th); } @@ -771,9 +747,7 @@ schedule_transmission_task (void *cls, return; /* no pending messages */ size = n->th->notify_size + sizeof (struct OutboundMessage); } -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Calling notify_transmit_ready\n"); -#endif h->cth = GNUNET_CLIENT_notify_transmit_ready (h->client, size, GNUNET_TIME_UNIT_FOREVER_REL, @@ -809,11 +783,9 @@ schedule_transmission (struct GNUNET_TRANSPORT_Handle *h) n->th->notify_size); else return; /* no work to be done */ -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduling next transmission to service in %llu ms\n", (unsigned long long) delay.rel_value); -#endif h->quota_task = GNUNET_SCHEDULER_add_delayed (delay, &schedule_transmission_task, h); } @@ -835,10 +807,8 @@ schedule_control_transmit (struct GNUNET_TRANSPORT_Handle *h, size_t size, { struct GNUNET_TRANSPORT_TransmitHandle *th; -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Control transmit of %u bytes requested\n", size); -#endif th = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TransmitHandle)); th->notify = notify; th->notify_cls = notify_cls; @@ -866,15 +836,11 @@ send_start (void *cls, size_t size, void *buf) if (buf == NULL) { /* Can only be shutdown, just give up */ -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutdown while trying to transmit `%s' request.\n", "START"); -#endif return 0; } -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "START"); -#endif GNUNET_assert (size >= sizeof (struct StartMessage)); s.header.size = htons (sizeof (struct StartMessage)); s.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_START); @@ -909,9 +875,7 @@ reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) /* shutdown, just give up */ return; } -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service.\n"); -#endif GNUNET_assert (h->client == NULL); GNUNET_assert (h->control_head == NULL); GNUNET_assert (h->control_tail == NULL); @@ -940,7 +904,7 @@ disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_Handle *h) } if (NULL != h->client) { - GNUNET_CLIENT_disconnect (h->client, GNUNET_YES); + GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } /* Forget about all neighbours that we used to be connected to */ @@ -956,11 +920,9 @@ disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_Handle *h) th->notify (th->notify_cls, 0, NULL); GNUNET_free (th); } -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduling task to reconnect to transport service in %llu ms.\n", h->reconnect_delay.rel_value); -#endif h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h); if (h->reconnect_delay.rel_value == 0) @@ -995,11 +957,9 @@ send_try_connect (void *cls, size_t size, void *buf) GNUNET_free (pid); return 0; } -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request with respect to `%4s'.\n", "REQUEST_CONNECT", GNUNET_i2s (pid)); -#endif GNUNET_assert (size >= sizeof (struct TransportRequestConnectMessage)); msg.header.size = htons (sizeof (struct TransportRequestConnectMessage)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT); @@ -1050,16 +1010,12 @@ send_hello (void *cls, size_t size, void *buf) if (buf == NULL) { -#if DEBUG_TRANSPORT_TIMEOUT LOG (GNUNET_ERROR_TYPE_DEBUG, "Timeout while trying to transmit `%s' request.\n", "HELLO"); -#endif GNUNET_free (msg); return 0; } -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "HELLO"); -#endif ssize = ntohs (msg->size); GNUNET_assert (size >= ssize); memcpy (buf, msg, ssize); @@ -1101,11 +1057,9 @@ GNUNET_TRANSPORT_offer_hello (struct GNUNET_TRANSPORT_Handle *handle, } msg = GNUNET_malloc (size); memcpy (msg, hello, size); -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Offering `%s' message of `%4s' to transport for validation.\n", "HELLO", GNUNET_i2s (&peer)); -#endif schedule_control_transmit (handle, size, &send_hello, msg); } @@ -1204,9 +1158,7 @@ GNUNET_TRANSPORT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle) { -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n"); -#endif /* this disconnects all neighbours... */ if (handle->reconnect_task == GNUNET_SCHEDULER_NO_TASK) disconnect_and_schedule_reconnect (handle); @@ -1291,11 +1243,9 @@ GNUNET_TRANSPORT_notify_transmit_ready (struct GNUNET_TRANSPORT_Handle *handle, delay = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, size); if (delay.rel_value > timeout.rel_value) delay.rel_value = 0; /* notify immediately (with failure) */ -#if DEBUG_TRANSPORT_API LOG (GNUNET_ERROR_TYPE_DEBUG, "Bandwidth tracker allows next transmission to peer %s in %llu ms\n", GNUNET_i2s (target), (unsigned long long) delay.rel_value); -#endif n->hn = GNUNET_CONTAINER_heap_insert (handle->ready_heap, n, delay.rel_value); schedule_transmission (handle); return th; diff --git a/src/transport/transport_api_address_lookup.c b/src/transport/transport_api_address_lookup.c index 6e03945..655be83 100644 --- a/src/transport/transport_api_address_lookup.c +++ b/src/transport/transport_api_address_lookup.c @@ -155,7 +155,7 @@ static void reconnect (struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx) { GNUNET_assert (GNUNET_NO == pal_ctx->one_shot); - GNUNET_CLIENT_disconnect (pal_ctx->client, GNUNET_NO); + GNUNET_CLIENT_disconnect (pal_ctx->client); pal_ctx->client = NULL; pal_ctx->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (pal_ctx->backoff, 2), @@ -294,17 +294,17 @@ peer_address_response_processor (void *cls, /** * Return all the known addresses for a specific peer or all peers. - * Returns continously all address if one_shot is set to GNUNET_NO + * Returns continuously all address if one_shot is set to GNUNET_NO * * CHANGE: Returns the address(es) that we are currently using for this * peer. Upon completion, the 'AddressLookUpCallback' is called one more * time with 'NULL' for the address and the peer. After this, the operation must no - * longer be explicitly cancelled. + * longer be explicitly canceled. * * @param cfg configuration to use * @param peer peer identity to look up the addresses of, CHANGE: allow NULL for all (connected) peers * @param one_shot GNUNET_YES to return the current state and then end (with NULL+NULL), - * GNUNET_NO to monitor the set of addresses used (continuously, must be explicitly cancelled) + * GNUNET_NO to monitor the set of addresses used (continuously, must be explicitly canceled) * @param timeout how long is the lookup allowed to take at most (irrelevant if one_shot is set to GNUNET_NO) * @param peer_address_callback function to call with the results * @param peer_address_callback_cls closure for peer_address_callback @@ -354,7 +354,7 @@ GNUNET_TRANSPORT_peer_get_active_addresses_cancel (struct { if (NULL != alc->client) { - GNUNET_CLIENT_disconnect (alc->client, GNUNET_NO); + GNUNET_CLIENT_disconnect (alc->client); alc->client = NULL; } if (GNUNET_SCHEDULER_NO_TASK != alc->reconnect_task) diff --git a/src/transport/transport_api_address_to_string.c b/src/transport/transport_api_address_to_string.c index 4d80953..152e573 100644 --- a/src/transport/transport_api_address_to_string.c +++ b/src/transport/transport_api_address_to_string.c @@ -71,7 +71,7 @@ address_response_processor (void *cls, const struct GNUNET_MessageHeader *msg) if (msg == NULL) { alucb->cb (alucb->cb_cls, NULL); - GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); + GNUNET_CLIENT_disconnect (alucb->client); GNUNET_free (alucb); return; } @@ -82,7 +82,7 @@ address_response_processor (void *cls, const struct GNUNET_MessageHeader *msg) { /* done! */ alucb->cb (alucb->cb_cls, NULL); - GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); + GNUNET_CLIENT_disconnect (alucb->client); GNUNET_free (alucb); return; } @@ -92,7 +92,7 @@ address_response_processor (void *cls, const struct GNUNET_MessageHeader *msg) /* invalid reply */ GNUNET_break (0); alucb->cb (alucb->cb_cls, NULL); - GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); + GNUNET_CLIENT_disconnect (alucb->client); GNUNET_free (alucb); return; } @@ -141,13 +141,9 @@ GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle GNUNET_break (0); return NULL; } - client = GNUNET_CLIENT_connect ("transport", cfg); - if (client == NULL) + if (NULL == client) return NULL; -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_TRANSPORT_address_to_string\n"); -#endif msg = GNUNET_malloc (len); msg->header.size = htons (len); msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING); @@ -183,7 +179,7 @@ GNUNET_TRANSPORT_address_to_string_cancel (struct GNUNET_TRANSPORT_AddressToStringContext *alc) { - GNUNET_CLIENT_disconnect (alc->client, GNUNET_NO); + GNUNET_CLIENT_disconnect (alc->client); GNUNET_free (alc); } diff --git a/src/transport/transport_api_blacklist.c b/src/transport/transport_api_blacklist.c index be52623..0464620 100644 --- a/src/transport/transport_api_blacklist.c +++ b/src/transport/transport_api_blacklist.c @@ -168,7 +168,7 @@ static void reconnect (struct GNUNET_TRANSPORT_Blacklist *br) { if (br->client != NULL) - GNUNET_CLIENT_disconnect (br->client, GNUNET_NO); + GNUNET_CLIENT_disconnect (br->client); br->client = GNUNET_CLIENT_connect ("transport", br->cfg); GNUNET_assert (br->client != NULL); br->th = @@ -288,7 +288,7 @@ GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_Blacklist *br) GNUNET_CLIENT_notify_transmit_ready_cancel (br->th); br->th = NULL; } - GNUNET_CLIENT_disconnect (br->client, GNUNET_NO); + GNUNET_CLIENT_disconnect (br->client); GNUNET_free (br); } |