testing_core_cmd_send.c (6814B)
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_send.c 23 * @brief a function to send messages to 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-send", __VA_ARGS__) 39 40 41 static void * 42 connect_cb (void *cls, 43 const struct GNUNET_PeerIdentity *peer_id, 44 struct GNUNET_MQ_Handle *mq); 45 46 47 struct SendState 48 { 49 struct GNUNET_TESTING_CORE_ConnectState *connect_state; 50 uint64_t num_messages; 51 enum GNUNET_GenericReturnValue await_new_connection; 52 }; 53 54 55 static void 56 cleanup_callbacks (struct SendState *send_state) 57 { 58 struct GNUNET_TESTING_CORE_ConnectState *connect_state = 59 send_state->connect_state; 60 struct GNUNET_TESTING_CORE_ConnectCb *connect_cb_iter; 61 62 for (uint64_t i = 0; i < connect_state->connect_cbs_len; i++) 63 { 64 connect_cb_iter = &connect_state->connect_cbs[i]; 65 if (connect_cb == connect_cb_iter->callback) 66 { 67 /* remove the callback */ 68 GNUNET_memcpy (connect_cb_iter, 69 connect_cb_iter + 1, 70 (connect_state->connect_cbs_len - i - 1) 71 * sizeof (struct GNUNET_TESTING_CORE_ConnectCb)); 72 GNUNET_array_grow (connect_state->connect_cbs, 73 connect_state->connect_cbs_len, 74 connect_state->connect_cbs_len - 1); 75 // FIXME the following seems to be a double free, but I currently don't 76 // know where the other free should be 77 // GNUNET_free (connect_cb_iter); 78 } 79 } 80 } 81 82 83 static void 84 send_messages (struct SendState *send_state) 85 { 86 const struct GNUNET_TESTING_CORE_ConnectState *connect_state = 87 send_state->connect_state; 88 struct GNUNET_MQ_Envelope *env; 89 struct GNUNET_TESTING_CORE_Message *msg; 90 struct GNUNET_TESTING_CORE_Channel *channel_iter; 91 uint64_t channel_index = 0; 92 93 LOG (GNUNET_ERROR_TYPE_DEBUG, 94 "Going to send %" PRIu64 " messages\n", 95 send_state->num_messages); 96 GNUNET_assert (NULL != connect_state->channels_head); 97 /* For now send on all available channels as we don't know at this stage 98 * which is an usable channel - this should be fine as the unusable channel 99 * will (probably) be discovered and cleaned up in the process. */ 100 for (channel_iter = connect_state->channels_head; 101 NULL != channel_iter; 102 channel_iter = channel_iter->next) 103 { 104 for (uint64_t i = 0; i < send_state->num_messages; i++) 105 { 106 LOG (GNUNET_ERROR_TYPE_DEBUG, 107 "Going to send message (type %u) %" PRIu64 ", %s (channel %" PRIu64 108 ") to %s\n", 109 MTYPE, 110 i, 111 connect_state->node_id, 112 channel_index, 113 GNUNET_i2s (&channel_iter->peer_id)); 114 env = GNUNET_MQ_msg (msg, MTYPE); // usually we wanted to keep the 115 // envelopes to potentially cancel the 116 // message 117 msg->id = GNUNET_htonll (i); 118 msg->batch = GNUNET_htonll (channel_index); 119 GNUNET_memcpy (msg->node_id, connect_state->node_id, NODE_ID_LEN); 120 GNUNET_MQ_send (channel_iter->mq, env); 121 LOG (GNUNET_ERROR_TYPE_DEBUG, 122 "Sent message %" PRIu64 " (channel %" PRIu64 ")\n", 123 i, 124 channel_index); 125 } 126 channel_index++; 127 } 128 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sent messages\n"); 129 130 cleanup_callbacks (send_state); 131 GNUNET_free (send_state); 132 } 133 134 135 static void * 136 connect_cb ( 137 void *cls, 138 const struct GNUNET_PeerIdentity *peer_id, 139 struct GNUNET_MQ_Handle *mq) 140 { 141 struct SendState *send_state = cls; 142 143 send_messages (send_state); 144 // FIXME this returns something but the calling function discards the 145 // returned value anyways 146 return NULL; 147 } 148 149 150 static void 151 exec_send_run (void *cls, 152 struct GNUNET_TESTING_Interpreter *is) 153 { 154 struct SendState *send_state = cls; 155 struct GNUNET_TESTING_CORE_ConnectState *connect_state; 156 157 // TODO make the "connect" label an input to the command 158 if (GNUNET_OK != GNUNET_CORE_TESTING_get_trait_connect ( 159 GNUNET_TESTING_interpreter_lookup_command (is, "connect"), 160 &connect_state)) 161 { 162 GNUNET_assert (0); 163 } 164 ; 165 send_state->connect_state = connect_state; 166 167 LOG (GNUNET_ERROR_TYPE_DEBUG, "Going to (register to) send messages\n"); 168 169 if ((NULL != connect_state->channels_head) && 170 (GNUNET_NO == send_state->await_new_connection)) 171 { 172 /* We are connected to a peer - send messages */ 173 send_messages (send_state); 174 } 175 else 176 { 177 /* We are not connected yet - subscribe via callback */ 178 // FIXME is the following ok? 179 struct GNUNET_TESTING_CORE_ConnectCb *connect_cb_struct = 180 GNUNET_new (struct GNUNET_TESTING_CORE_ConnectCb); 181 LOG (GNUNET_ERROR_TYPE_DEBUG, 182 "Registering our connect callback with the connect callbacks\n"); 183 connect_cb_struct->callback = connect_cb; 184 connect_cb_struct->cls = send_state; 185 GNUNET_array_append (connect_state->connect_cbs, 186 connect_state->connect_cbs_len, 187 *connect_cb_struct); 188 } 189 } 190 191 192 static void 193 exec_send_cleanup (void *cls) 194 { 195 // struct GNUNET_TESTING_CORE_ConnectState *connect_state = cls; 196 197 } 198 199 200 // TODO add a AWAIT_NEW_CONNECTION flag 201 const struct GNUNET_TESTING_Command 202 GNUNET_TESTING_CORE_cmd_send ( 203 const char *label, 204 uint64_t num_messages, 205 enum GNUNET_GenericReturnValue await_new_connection) 206 { 207 struct SendState *send_state; 208 209 // TODO make struct static global? 210 send_state = GNUNET_new (struct SendState); 211 send_state->num_messages = num_messages; 212 send_state->await_new_connection = await_new_connection; 213 LOG (GNUNET_ERROR_TYPE_DEBUG, "(Setting up _cmd_send)\n"); 214 return GNUNET_TESTING_command_new ( 215 send_state, // state 216 label, 217 &exec_send_run, 218 &exec_send_cleanup, 219 NULL); 220 } 221 222 223 /* end of src/service/core/testing_core_recv.c */