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 */