gnunet

Main GNUnet Logic
Log | Files | Refs | Submodules | README | LICENSE

testing_core_cmd_recv.c (8727B)


      1 /*
      2       This file is part of GNUnet
      3       Copyright (C) 2024 GNUnet e.V.
      4 
      5       GNUnet is free software: you can redistribute it and/or modify it
      6       under the terms of the GNU Affero General Public License as published
      7       by the Free Software Foundation, either version 3 of the License,
      8       or (at your option) any later version.
      9 
     10       GNUnet is distributed in the hope that it will be useful, but
     11       WITHOUT ANY WARRANTY; without even the implied warranty of
     12       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13       Affero General Public License for more details.
     14 
     15       You should have received a copy of the GNU Affero General Public License
     16       along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18      SPDX-License-Identifier: AGPL3.0-or-later
     19  */
     20 
     21 /**
     22  * @file src/service/core/testing_core_recv.c
     23  * @brief a function to receive messages from another peer
     24  * @author ch3
     25  */
     26 
     27 #include "platform.h"
     28 #include "gnunet_util_lib.h"
     29 #include "gnunet_testing_lib.h"
     30 #include "gnunet_core_service.h"
     31 #include "gnunet_testing_core_lib.h"
     32 
     33 
     34 /**
     35  * @brief Generic logging shortcut
     36  */
     37 #define LOG(kind, ...) \
     38         GNUNET_log_from (kind, "testing-core-recv", __VA_ARGS__)
     39 
     40 
     41 struct RecvState;
     42 
     43 
     44 struct ChannelCount
     45 {
     46   struct GNUNET_TESTING_CORE_Channel *channel;
     47   struct RecvState *rs;
     48   uint64_t num_messages_received;
     49 };
     50 
     51 
     52 struct RecvState
     53 {
     54   struct ChannelCount *channel_count;
     55   uint32_t num_channels;
     56   uint64_t num_messages_target;
     57   struct GNUNET_TESTING_CORE_ConnectState *connect_state;
     58   struct GNUNET_TESTING_AsyncContext ac;
     59 };
     60 
     61 
     62 static void
     63 handle_msg_test (void *cls,
     64                  struct GNUNET_TESTING_CORE_Channel *channel,
     65                  const struct GNUNET_TESTING_CORE_Message *msg);
     66 
     67 
     68 static void
     69 do_finish_cmd_delayed (void *cls)
     70 {
     71   struct RecvState *rs = cls;
     72 
     73   LOG (GNUNET_ERROR_TYPE_DEBUG, "Finishing test delayed\n");
     74   GNUNET_TESTING_async_finish (&rs->ac);
     75   GNUNET_free (rs);
     76 }
     77 
     78 
     79 static void
     80 remove_recv_handler (struct GNUNET_TESTING_CORE_ConnectState *connect_state)
     81 {
     82   LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing recv handler\n");
     83   for (uint64_t i = 0; i < connect_state->recv_handlers_len; i++)
     84   {
     85     if (&handle_msg_test == connect_state->recv_handlers[i])
     86     {
     87       // FIXME this is the dirty solution. The attempt below did for whatever
     88       // reason not work.
     89       connect_state->recv_handlers[i] = NULL;
     90       // LOG (GNUNET_ERROR_TYPE_DEBUG,
     91       //    "recv handlers[0]: %p, handle_msg_test: %p, (%lu)\n",
     92       //    connect_state->recv_handlers[0],
     93       //    &handle_msg_test,
     94       //    sizeof (&handle_msg_test));
     95       // LOG (GNUNET_ERROR_TYPE_DEBUG,
     96       //    "recv handlers: %p, %" PRIu64 "\n",
     97       //    connect_state->recv_handlers,
     98       //    connect_state->recv_handlers_len);
     99       // GNUNET_memcpy (&connect_state->recv_handlers[i],
    100       //               &connect_state->recv_handlers[i+1],
    101       //               (connect_state->connect_cbs_len - i - 1) *
    102       //                 sizeof (handle_msg_test));
    103       // LOG (GNUNET_ERROR_TYPE_DEBUG,
    104       //    "recv handlers: %p, %" PRIu64 "\n",
    105       //    connect_state->recv_handlers,
    106       //    connect_state->recv_handlers_len);
    107       // GNUNET_array_grow (connect_state->recv_handlers,
    108       //                   connect_state->recv_handlers_len,
    109       //                   connect_state->recv_handlers_len - 1);
    110     }
    111   }
    112 }
    113 
    114 
    115 static void
    116 handle_msg_test (void *cls,
    117                  struct GNUNET_TESTING_CORE_Channel *channel,
    118                  const struct GNUNET_TESTING_CORE_Message *msg)
    119 {
    120   // struct ChannelCount *channel_count = cls;
    121   struct RecvState *rs = cls;
    122   struct ChannelCount *channel_count;
    123   uint32_t channel_i;
    124   uint64_t num_messages_received;
    125   uint64_t num_messages_target;
    126   enum GNUNET_GenericReturnValue ret;
    127 
    128   LOG (GNUNET_ERROR_TYPE_INFO, "received test message %" PRIu64 " (%" PRIu64
    129        ") %s\n",
    130        GNUNET_ntohll (msg->id),
    131        GNUNET_ntohll (msg->batch),
    132        msg->node_id);
    133 
    134   /* First, find the channel count struct with the channel over which we
    135    * received this message */
    136   channel_count = NULL;
    137   channel_i = rs->num_channels; /* For error checking -
    138                                    should be overwritten in the following loop. */
    139   for (uint32_t i = 0; i<rs->num_channels; i++)
    140   {
    141     struct ChannelCount *channel_count_iter = &rs->channel_count[i];
    142     if (NULL == channel_count_iter->channel)
    143     {
    144       channel_count = channel_count_iter;
    145       channel_count->channel = channel;
    146       channel_count->rs = rs;
    147       channel_i = i;
    148       break;
    149     }
    150     else if (channel == channel_count_iter->channel)
    151     {
    152       channel_count = channel_count_iter;
    153       channel_i = i;
    154       break;
    155     }
    156     // else: continue until suitable channel count structure is found
    157   }
    158   if (NULL == channel_count)
    159   {
    160     /* no suitable channel was found -> add this channel */
    161     GNUNET_array_grow (rs->channel_count,
    162                        rs->num_channels,
    163                        rs->num_channels + 1);
    164     channel_count = &rs->channel_count[rs->num_channels - 1];
    165     channel_count->channel = channel;
    166     channel_count->rs = rs;
    167     channel_i = rs->num_channels;
    168   }
    169 
    170   /* Then update number of received messages */
    171   channel_count->num_messages_received++;
    172 
    173   /* Finally check if this and then other channels received the correct amount
    174    * potentially finish. */
    175   num_messages_received = channel_count->num_messages_received;
    176   num_messages_target = channel_count->rs->num_messages_target;
    177   LOG (GNUNET_ERROR_TYPE_DEBUG,
    178        "Received %" PRIu64 " messages (of %" PRIu64 " on channel %" PRIu32
    179        ")\n",
    180        num_messages_received,
    181        num_messages_target,
    182        channel_i);
    183   if (num_messages_target > num_messages_received)
    184     return;
    185   if (num_messages_target < num_messages_received)
    186     GNUNET_assert (0);
    187   // if (num_messages_target == num_messages_received)
    188   //  GNUNET_TESTING_async_finish (&rs->ac);
    189   ret = GNUNET_YES;
    190   for (uint32_t i = 0; i < rs->num_channels; i++)
    191   {
    192     channel_count = &rs->channel_count[i];
    193     if (channel_count->num_messages_received != rs->num_messages_target)
    194       ret = GNUNET_NO;
    195   }
    196   if (GNUNET_YES == ret)
    197   {
    198     LOG (GNUNET_ERROR_TYPE_INFO,
    199          "Received all expected messages on all channels\n");
    200     remove_recv_handler (rs->connect_state);
    201     // TODO do we want to keep track of this task?
    202     /* If we finish this task, this ARM will shut down this peer, taking with
    203      * it core and with it all the messages still in transit.
    204      * Adding a bit of delay gives the other peer a chance to still receive
    205      * them.
    206      * This might be done nicer - via a barrier? Check the other node's receive
    207      * state?
    208      * The number of 3 Milliseconds was chosen by looking at logs and then
    209      * continuously running the test and seeing how many actually work reliably
    210      * (Increased it quite a bit in the end for valgrind - no repeated tests
    211      * this time.)
    212      */
    213     (void) GNUNET_SCHEDULER_add_delayed (
    214       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100),
    215       do_finish_cmd_delayed,
    216       rs);
    217   }
    218 }
    219 
    220 
    221 static void
    222 exec_recv_run (void *cls,
    223                struct GNUNET_TESTING_Interpreter *is)
    224 {
    225   struct RecvState *rs = cls;
    226   struct GNUNET_TESTING_CORE_ConnectState *connect_state;
    227 
    228   if (GNUNET_OK != GNUNET_CORE_TESTING_get_trait_connect (
    229         // TODO make the "connect" an input to the command
    230         GNUNET_TESTING_interpreter_lookup_command (is, "connect"),
    231         &connect_state))
    232   {
    233     GNUNET_assert (0);
    234   }
    235   ;
    236   rs->connect_state = connect_state;
    237   // FIXME: set cls per handler
    238   GNUNET_array_append (connect_state->recv_handlers,
    239                        connect_state->recv_handlers_len,
    240                        &handle_msg_test);
    241   // FIXME is the following ok?
    242   ((struct GNUNET_TESTING_CORE_ConnectState *) connect_state)->recv_handlers_cls
    243     = rs;
    244 }
    245 
    246 
    247 static void
    248 exec_recv_cleanup (void *cls)
    249 {
    250   // struct RecvState *rs = cls;
    251   // TODO
    252 
    253   // GNUNET_free (rs->channel_count);
    254   // GNUNET_free (rs);
    255 }
    256 
    257 
    258 const struct GNUNET_TESTING_Command
    259 GNUNET_TESTING_CORE_cmd_recv (
    260   const char *label,
    261   uint64_t num_messages)
    262 {
    263   struct RecvState *rs;
    264 
    265   // TODO this could be a static global variable
    266   rs = GNUNET_new (struct RecvState);
    267   rs->num_channels = 0;
    268   rs->channel_count = GNUNET_new_array (rs->num_channels, struct ChannelCount);
    269   rs->num_messages_target = num_messages;
    270   LOG (GNUNET_ERROR_TYPE_DEBUG, "(Setting up _cmd_recv)\n");
    271   return GNUNET_TESTING_command_new_ac (
    272     rs,   // state
    273     label,
    274     &exec_recv_run,
    275     &exec_recv_cleanup,
    276     NULL,   // traits
    277     &rs->ac);   // FIXME
    278 }
    279 
    280 
    281 /* end of src/service/core/testing_core_recv.c */