BitLab 0.1.0
BitLab: A Browser for the Bitcoin P2P Network and Blockchain
Loading...
Searching...
No Matches
peer_connection.h File Reference
#include <stdint.h>
#include <pthread.h>

Go to the source code of this file.

Data Structures

struct  bitcoin_msg_header
 
struct  Node
 The structure to store information about a connected peer. More...
 

Macros

#define MAX_NODES   100
 
#define BITCOIN_MAINNET_MAGIC   0xD9B4BEF9
 
#define BITCOIN_MAINNET_PORT   8333
 
#define htole16(x)   ((uint16_t)((((x) & 0xFF) << 8) | (((x) >> 8) & 0xFF)))
 
#define htole32(x)   ((uint32_t)((((x) & 0xFF) << 24) | (((x) >> 8) & 0xFF00) | (((x) >> 16) & 0xFF) | (((x) >> 24) & 0xFF000000)))
 
#define htole64(x)   ((uint64_t)((((x) & 0xFF) << 56) | (((x) >> 8) & 0xFF00) | (((x) >> 16) & 0xFF0000) | (((x) >> 24) & 0xFF000000) | (((x) >> 32) & 0xFF00000000) | (((x) >> 40) & 0xFF0000000000) | (((x) >> 48) & 0xFF000000000000) | (((x) >> 56) & 0xFF00000000000000)))
 
#define MAX_LOCATOR_COUNT   10
 
#define GENESIS_BLOCK_HASH   "0000000000000000000000000000000000000000000000000000000000000000"
 
#define HEADERS_FILE   "headers.dat"
 
#define MAX_HEADERS_COUNT   2000
 

Functions

void list_connected_nodes ()
 Lists all connected nodes and their details.
 
int get_idx (const char *ip_address)
 Get the index of the node with the given IP address.
 
void send_getaddr_and_wait (int idx)
 Sends a 'getaddr' message to the peer and waits for a response.
 
int connect_to_peer (const char *ip_addr)
 Connects to a peer using the specified IP address.
 
void disconnect (int node_id)
 Disconnects from the node specified by the node ID.
 
unsigned char * load_blocks_from_file (const char *filename, size_t *payload_len)
 
void send_getheaders_and_wait (int idx)
 Sends a 'getheaders' message to the peer and waits for a response.
 
void send_headers (int idx, const unsigned char *start_hash, const unsigned char *stop_hash)
 Sends a 'headers' message to the peer.
 
void send_getblocks_and_wait (int idx)
 Sends a 'getblocks' message to the peer and waits for a response.
 
void send_getdata_and_wait (int idx, const unsigned char *hashes, size_t hash_count)
 Sends a 'getdata' message to the peer and waits for a response.
 
void send_inv_and_wait (int idx, const unsigned char *inv_data, size_t inv_count)
 Sends an 'inv' message to the peer and waits for a response.
 
void send_tx (int idx, const unsigned char *tx_data, size_t tx_size)
 Sends a 'tx' message to the specified node.
 

Variables

Node nodes [MAX_NODES]
 

Macro Definition Documentation

◆ BITCOIN_MAINNET_MAGIC

#define BITCOIN_MAINNET_MAGIC   0xD9B4BEF9

Definition at line 11 of file peer_connection.h.

◆ BITCOIN_MAINNET_PORT

#define BITCOIN_MAINNET_PORT   8333

Definition at line 14 of file peer_connection.h.

◆ GENESIS_BLOCK_HASH

#define GENESIS_BLOCK_HASH   "0000000000000000000000000000000000000000000000000000000000000000"

Definition at line 21 of file peer_connection.h.

◆ HEADERS_FILE

#define HEADERS_FILE   "headers.dat"

Definition at line 22 of file peer_connection.h.

◆ htole16

#define htole16 (   x)    ((uint16_t)((((x) & 0xFF) << 8) | (((x) >> 8) & 0xFF)))

Definition at line 16 of file peer_connection.h.

◆ htole32

#define htole32 (   x)    ((uint32_t)((((x) & 0xFF) << 24) | (((x) >> 8) & 0xFF00) | (((x) >> 16) & 0xFF) | (((x) >> 24) & 0xFF000000)))

Definition at line 17 of file peer_connection.h.

◆ htole64

#define htole64 (   x)    ((uint64_t)((((x) & 0xFF) << 56) | (((x) >> 8) & 0xFF00) | (((x) >> 16) & 0xFF0000) | (((x) >> 24) & 0xFF000000) | (((x) >> 32) & 0xFF00000000) | (((x) >> 40) & 0xFF0000000000) | (((x) >> 48) & 0xFF000000000000) | (((x) >> 56) & 0xFF00000000000000)))

Definition at line 18 of file peer_connection.h.

◆ MAX_HEADERS_COUNT

#define MAX_HEADERS_COUNT   2000

Definition at line 23 of file peer_connection.h.

◆ MAX_LOCATOR_COUNT

#define MAX_LOCATOR_COUNT   10

Definition at line 20 of file peer_connection.h.

◆ MAX_NODES

#define MAX_NODES   100

Definition at line 8 of file peer_connection.h.

Function Documentation

◆ connect_to_peer()

int connect_to_peer ( const char *  ip_addr)

Connects to a peer using the specified IP address.

This function attempts to establish a connection to a peer using the given IP address. It returns a socket file descriptor if the connection is successful, or -1 if it fails.

Parameters
ip_addrThe IP address of the peer to connect to.

Definition at line 1032 of file peer_connection.c.

1033{
1034 // Create the socket
1035 int sockfd;
1036 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
1037 {
1038 fprintf(stderr, "[Error] socket creation failed: %s\n", strerror(errno));
1039 return -1;
1040 }
1041
1042 struct timeval timeout;
1043 timeout.tv_sec = 3; // seconds
1044 timeout.tv_usec = 0; // microseconds
1045
1046 // Set timeout for recv
1047 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0)
1048 {
1049 perror("setsockopt failed");
1050 close(sockfd);
1051 exit(EXIT_FAILURE);
1052 }
1053 // Set timeout for connect()
1054 if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0)
1055 {
1056 perror("setsockopt failed");
1057 close(sockfd);
1058 return -1;
1059 }
1060
1061 // Prepare the sockaddr_in
1062 struct sockaddr_in servaddr;
1063 memset(&servaddr, 0, sizeof(servaddr));
1064 servaddr.sin_family = AF_INET;
1065 servaddr.sin_port = htons(BITCOIN_MAINNET_PORT);
1066
1067 if (inet_pton(AF_INET, ip_addr, &servaddr.sin_addr) <= 0)
1068 {
1069 fprintf(stderr, "[Error] inet_pton failed (IP '%s'): %s\n",
1070 ip_addr, strerror(errno));
1071 close(sockfd);
1072 return -1;
1073 }
1074
1075 // Connect
1076 if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
1077 {
1078 fprintf(stderr, "[Error] connect to %s:%d failed: %s\n",
1079 ip_addr, BITCOIN_MAINNET_PORT, strerror(errno));
1080 close(sockfd);
1081 return -1;
1082 }
1083
1084 printf("[+] Connected to peer %s:%d\n", ip_addr, BITCOIN_MAINNET_PORT);
1085
1086 // Build the 'version' payload
1087 unsigned char version_payload[200];
1088 size_t version_payload_len = build_version_payload(
1089 version_payload, sizeof(version_payload));
1090 if (version_payload_len == 0)
1091 {
1092 fprintf(stderr, "[Error] build_version_payload() failed.\n");
1093 close(sockfd);
1094 return -1;
1095 }
1096
1097 // Create the full 'version' message
1098 unsigned char version_msg[256];
1099 size_t version_msg_len = build_message(
1100 version_msg,
1101 sizeof(version_msg),
1102 "version",
1103 version_payload,
1104 version_payload_len
1105 );
1106 if (version_msg_len == 0)
1107 {
1108 fprintf(stderr, "[Error] build_message() failed for 'version'.\n");
1109 close(sockfd);
1110 return -1;
1111 }
1112
1113 // Send the 'version' message
1114 ssize_t bytes_sent = send(sockfd, version_msg, version_msg_len, 0);
1115 if (bytes_sent < 0)
1116 {
1117 fprintf(stderr, "[Error] send() of 'version' failed: %s\n", strerror(errno));
1118 close(sockfd);
1119 return -1;
1120 }
1121 printf("[+] Sent 'version' message (%zd bytes).\n", bytes_sent);
1122
1123 char log_filename[256];
1124 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log",
1125 ip_addr);
1126 init_logging(log_filename);
1127 // Read loop - up to 10 messages
1128 unsigned char recv_buf[2048];
1129 bool connected = false;
1130 for (int i = 0; i < 4; ++i)
1131 {
1132 printf("[d] Executing %dth receive loop iteration\n", i);
1133 ssize_t n = recv(sockfd, recv_buf, sizeof(recv_buf), 0);
1134 if (n < 0)
1135 {
1136 if (errno == EAGAIN || errno == EWOULDBLOCK)
1137 {
1138 log_message(LOG_WARN, log_filename, __FILE__,
1139 "recv() timed out, continuing...");
1140 continue;
1141 }
1142 fprintf(stderr, "[Error] recv() failed: %s\n", strerror(errno));
1143 break;
1144 }
1145 if (n == 0)
1146 {
1147 // Peer closed the connection
1148 printf("[i] Peer closed the connection.\n");
1149 break;
1150 }
1151
1152 // If we have at least a full header, parse it
1153 if (n < (ssize_t)sizeof(bitcoin_msg_header))
1154 {
1155 printf("[!] Received %zd bytes (less than header size 24).\n", n);
1156 continue;
1157 }
1158
1159 printf("[<] Received %zd bytes.\n", n);
1160
1161 // Cast to a header
1162 bitcoin_msg_header* hdr = (bitcoin_msg_header*)recv_buf;
1163
1164 // Check the magic
1165 if (hdr->magic == BITCOIN_MAINNET_MAGIC)
1166 {
1167 char cmd_name[13];
1168 memset(cmd_name, 0, sizeof(cmd_name));
1169 memcpy(cmd_name, hdr->command, 12);
1170
1171 printf("[<] Received command: '%s'\n", cmd_name);
1172
1173 // Determine the payload length & pointer
1174 size_t payload_len = hdr->length;
1175
1176 if (n < (ssize_t)(sizeof(bitcoin_msg_header) + payload_len))
1177 {
1178 printf("[!] Incomplete message; got %zd bytes, expected %zu.\n",
1179 n, sizeof(bitcoin_msg_header) + payload_len);
1180 continue;
1181 }
1182
1183 // Handle known commands
1184 if (strcmp(cmd_name, "version") == 0)
1185 {
1186 // Send verack once we get their version
1187 ssize_t verack_sent = send_verack(sockfd, ip_addr);
1188 if (verack_sent < 0)
1189 {
1190 fprintf(stderr, "[Error] sending verack: %s\n", strerror(errno));
1191 }
1192 else
1193 {
1194 printf("[+] Sent 'verack' message.\n");
1195 }
1196 connected = true;
1197 }
1198 else if (strcmp(cmd_name, "verack") == 0)
1199 {
1200 connected = true;
1201 break;
1202 }
1203 else
1204 {
1205 // Unhandled command
1206 printf("[!] Unhandled command: '%s' (payload size=%u)\n",
1207 cmd_name, hdr->length);
1208 }
1209 }
1210 else
1211 {
1212 printf("[!] Unexpected magic bytes (0x%08X).\n", hdr->magic);
1213 }
1214 }
1215 if (connected == true)
1216 {
1217 for (int j = 0; j < MAX_NODES; ++j)
1218 {
1219 if (nodes[j].is_connected == 0)
1220 {
1221 guarded_print_line("connected to node: %s | %d.", ip_addr, j);
1222 initialize_node(&nodes[j], ip_addr, 8333, sockfd);
1224 break;
1225 }
1226 }
1227 }
1228 else
1229 {
1230 guarded_print_line("Couldn't connect to node\n");
1231 close(sockfd);
1232 }
1233 return 0;
1234}
void log_message(log_level level, const char *filename, const char *source_file, const char *format,...)
Log a message used to log a message to the console or a file.
Definition log.c:89
void init_logging(const char *filename)
Initialize logging used to initialize the logging system, open and preserve the log file.
Definition log.c:34
@ LOG_WARN
Definition log.h:31
static size_t build_message(unsigned char *buf, size_t buf_size, const char *command, const unsigned char *payload, size_t payload_len)
build_message: Creates a Bitcoin P2P message (header + payload) in buf.
Node nodes[MAX_NODES]
void initialize_node(Node *node, const char *ip, uint16_t port, int socket_fd)
static size_t build_version_payload(unsigned char *buf, size_t buf_size)
build_version_payload: Build a minimal "version" message payload.
void create_peer_thread(Node *node)
static ssize_t send_verack(int sockfd, const char *ip_addr)
send_verack: Constructs a verack message with an empty payload (length = 0) and a valid 4-byte checks...
#define BITCOIN_MAINNET_PORT
#define MAX_NODES
#define BITCOIN_MAINNET_MAGIC
void guarded_print_line(const char *format,...)
Guarded print line function.
Definition utils.c:65

References BITCOIN_MAINNET_MAGIC, BITCOIN_MAINNET_PORT, build_message(), build_version_payload(), bitcoin_msg_header::command, create_peer_thread(), guarded_print_line(), init_logging(), initialize_node(), bitcoin_msg_header::length, log_message(), LOG_WARN, bitcoin_msg_header::magic, MAX_NODES, nodes, and send_verack().

Referenced by cli_connect().

◆ disconnect()

void disconnect ( int  node_id)

Disconnects from the node specified by the node ID.

This function disconnects from the node specified by the given node ID. It closes the socket, terminates the thread, and logs the disconnection.

Parameters
node_idThe ID of the node in the nodes array to disconnect from.

Definition at line 1236 of file peer_connection.c.

1237{
1238 if (node_id < 0 || node_id >= MAX_NODES || !nodes[node_id].is_connected)
1239 {
1240 fprintf(stderr, "[Error] Invalid node ID or node not connected.\n");
1241 return;
1242 }
1243
1244 Node* node = &nodes[node_id];
1245 char log_filename[256];
1246 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log",
1247 node->ip_address);
1248
1249 log_message(LOG_INFO, log_filename, __FILE__, "Disconnecting from node %s:%u",
1250 node->ip_address, node->port);
1251
1252 close(node->socket_fd);
1253
1254 node->is_connected = 0;
1255
1256 if (pthread_cancel(node->thread) != 0)
1257 {
1258 perror("Failed to cancel thread for peer");
1259 }
1260
1261 log_message(LOG_INFO, log_filename, __FILE__,
1262 "Successfully disconnected from node %s:%u", node->ip_address,
1263 node->port);
1264}
@ LOG_INFO
Definition log.h:30
The structure to store information about a connected peer.
char ip_address[64]
uint16_t port
pthread_t thread
int socket_fd
int is_connected

References Node::ip_address, Node::is_connected, LOG_INFO, log_message(), MAX_NODES, nodes, Node::port, Node::socket_fd, and Node::thread.

Referenced by cli_disconnect().

◆ get_idx()

int get_idx ( const char *  ip_address)

Get the index of the node with the given IP address.

Parameters
ip_addressThe IP address of the node.
Returns
The index of the node in the global array.

Definition at line 291 of file peer_connection.c.

292{
293 for (int i = 0; i < MAX_NODES; ++i)
294 {
295 if (nodes[i].is_connected == 1 && strcmp(nodes[i].ip_address, ip_address) == 0)
296 {
297 return i;
298 }
299 }
300 return -1;
301}

References MAX_NODES, and nodes.

Referenced by peer_communication().

◆ list_connected_nodes()

void list_connected_nodes ( )

Lists all connected nodes and their details.

This function iterates through the list of nodes and prints the details of each node that is currently connected.

Definition at line 269 of file peer_connection.c.

270{
271 for (int i = 0; i < MAX_NODES; ++i)
272 {
273 if (nodes[i].is_connected == 1)
274 {
275 guarded_print_line("Node %d:", i);
276 guarded_print_line(" IP Address: %s", nodes[i].ip_address);
277 guarded_print_line(" Port: %u", nodes[i].port);
278 guarded_print_line(" Socket FD: %d", nodes[i].socket_fd);
279 guarded_print_line(" Thread ID: %lu", nodes[i].thread);
280 guarded_print_line(" Is Connected: %d", nodes[i].is_connected);
281 guarded_print_line(" Is operation in progress: %d",
282 nodes[i].operation_in_progress);
283 guarded_print_line(" Compact blocks: %lu",
284 nodes[i].compact_blocks);
285 guarded_print_line(" Fee_rate: %lu",
286 nodes[i].fee_rate);
287 }
288 }
289}

References guarded_print_line(), MAX_NODES, and nodes.

Referenced by cli_list().

◆ load_blocks_from_file()

unsigned char * load_blocks_from_file ( const char *  filename,
size_t *  payload_len 
)

Definition at line 1491 of file peer_connection.c.

1492{
1493 FILE* file = fopen(filename, "rb");
1494 if (!file)
1495 {
1496 perror("Failed to open file for reading");
1497 return NULL;
1498 }
1499
1500 fseek(file, 0, SEEK_END);
1501 *payload_len = ftell(file);
1502 fseek(file, 0, SEEK_SET);
1503
1504 unsigned char* payload = (unsigned char*)malloc(*payload_len);
1505 if (!payload)
1506 {
1507 perror("Failed to allocate memory");
1508 fclose(file);
1509 return NULL;
1510 }
1511
1512 fread(payload, 1, *payload_len, file);
1513 fclose(file);
1514 guarded_print("Blocks loaded from file: %s\n", filename);
1515 return payload;
1516}
void guarded_print(const char *format,...)
Guarded print function.
Definition utils.c:55

References guarded_print().

Referenced by cli_inv(), and peer_communication().

◆ send_getaddr_and_wait()

void send_getaddr_and_wait ( int  idx)

Sends a 'getaddr' message to the peer and waits for a response.

This function sends a 'getaddr' message to the peer identified by the given index and waits for a response. It is used to request a list of known peers from the connected peer.

Parameters
idxThe index of the peer in the nodes array.

Definition at line 303 of file peer_connection.c.

304{
305 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
306 {
307 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
308 return;
309 }
310
311 Node* node = &nodes[idx];
312 char log_filename[256];
313 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log",
314 node->ip_address);
315
316 // Build the 'getaddr' message
317 unsigned char getaddr_msg[sizeof(bitcoin_msg_header)];
318 size_t msg_len = build_message(getaddr_msg, sizeof(getaddr_msg), "getaddr", NULL,
319 0);
320 if (msg_len == 0)
321 {
322 fprintf(stderr, "[Error] Failed to build 'getaddr' message.\n");
323 return;
324 }
325
326 // Send the 'getaddr' message
327 ssize_t bytes_sent = send(node->socket_fd, getaddr_msg, msg_len, 0);
328 if (bytes_sent < 0)
329 {
330 log_message(LOG_INFO, log_filename, __FILE__,
331 "[Error] Failed to send 'getaddr' message: %s", strerror(errno));
332 return;
333 }
334
335 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'getaddr' message.");
336 node->operation_in_progress = 1;
337
338 // Wait for 10 seconds for a response
339 struct timeval tv;
340 tv.tv_sec = 3;
341 tv.tv_usec = 0;
342 setsockopt(node->socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
343
344 char buffer[32768];
345 size_t total_bytes_received = 0;
346 ssize_t bytes_received;
347
348 // Receive the message in parts
349 while (total_bytes_received < sizeof(bitcoin_msg_header))
350 {
351 log_message(LOG_INFO, log_filename, __FILE__, "first while receiving");
352 bytes_received = recv(node->socket_fd, buffer + total_bytes_received,
353 sizeof(buffer) - total_bytes_received - 1, 0);
354 if (bytes_received <= 0)
355 {
356 log_message(LOG_INFO, log_filename, __FILE__, "Recv 1 failed: %s",
357 strerror(errno));
358 node->is_connected = 0;
359 node->operation_in_progress = 0;
360 return;
361 }
362 total_bytes_received += bytes_received;
363 }
364
366 size_t payload_len = hdr->length;
367 size_t message_size = sizeof(bitcoin_msg_header) + payload_len;
368 int retry_count = 0;
369 const int max_retries = 1;
370
371 while (total_bytes_received < message_size)
372 {
373 log_message(LOG_INFO, log_filename, __FILE__, "second while receiving");
374 bytes_received = recv(node->socket_fd, buffer + total_bytes_received,
375 sizeof(buffer) - total_bytes_received - 1, 0);
376 if (bytes_received <= 0)
377 {
378 if (errno == EAGAIN || errno == EWOULDBLOCK)
379 {
380 log_message(LOG_INFO, log_filename, __FILE__,
381 "second while receiving inside if errno");
382 // Resource temporarily unavailable, continue receiving
383
384 if (++retry_count >= max_retries)
385 {
386 log_message(LOG_WARN, log_filename, __FILE__,
387 "Max retries reached, stopping recv.");
388 node->is_connected = 0;
389 node->operation_in_progress = 0;
390 break;
391 }
392 continue;
393 }
394 log_message(LOG_INFO, log_filename, __FILE__, "Recv failed: %s",
395 strerror(errno));
396 node->is_connected = 0;
397 node->operation_in_progress = 0;
398 return;
399 }
400 total_bytes_received += bytes_received;
401 }
402
403 buffer[total_bytes_received] = '\0'; // Null-terminate the received data
404
405 if (hdr->magic == BITCOIN_MAINNET_MAGIC)
406 {
407 char cmd_name[13];
408 memset(cmd_name, 0, sizeof(cmd_name));
409 memcpy(cmd_name, hdr->command, 12);
410
411 log_message(LOG_INFO, log_filename, __FILE__, "[!] Received %s command ",
412 cmd_name);
413
414 const unsigned char* payload_data = (unsigned char*)buffer + sizeof(
416
417
418 if (strcmp(cmd_name, "addr") == 0)
419 {
420 size_t offset = 0;
421
422 // Check if the payload length is sufficient to read the count of address entries
423 if (payload_len < 1)
424 {
425 log_message(LOG_WARN, log_filename, __FILE__,
426 "Insufficient payload length to read address count");
427 return;
428 }
429
430 // Read the count of address entries (var_int)
431 uint64_t count = read_var_int(payload_data + offset, &offset);
432
433 // Log the count of address entries
434 log_message(LOG_INFO, log_filename, __FILE__, "Address count: %llu", count);
435
436 // Ensure count does not exceed the maximum allowed entries
437 if (count > 1000)
438 {
439 log_message(LOG_WARN, log_filename, __FILE__,
440 "Address count exceeds maximum allowed: %llu", count);
441 return;
442 }
443
444 for (uint64_t i = 0; i < count; i++)
445 {
446 if (offset + 30 > payload_len)
447 {
448 log_message(LOG_WARN, log_filename, __FILE__,
449 "Insufficient payload length for address entry");
450 return;
451 }
452
453 // Read timestamp (4 bytes)
454 uint32_t timestamp;
455 memcpy(&timestamp, payload_data + offset, 4);
456 timestamp = ntohl(timestamp);
457 offset += 4;
458
459 // Read services (8 bytes, skip for now)
460 offset += 8;
461
462 // Read IP address (16 bytes)
463 struct in6_addr ip_addr;
464 memcpy(&ip_addr, payload_data + offset, 16);
465 offset += 16;
466
467 // Read port (2 bytes)
468 uint16_t port;
469 memcpy(&port, payload_data + offset, 2);
470 port = ntohs(port);
471 offset += 2;
472
473 // Convert IP to string
474 char ip_str[INET6_ADDRSTRLEN];
475 inet_ntop(AF_INET6, &ip_addr, ip_str, INET6_ADDRSTRLEN);
476
477 // Determine if the address is IPv4-mapped or IPv6
478 const char* ip_type = "IPv6";
479 if (IN6_IS_ADDR_V4MAPPED(&ip_addr))
480 {
481 struct in_addr ipv4_addr;
482 memcpy(&ipv4_addr, &ip_addr.s6_addr[12], 4);
483 inet_ntop(AF_INET, &ipv4_addr, ip_str, INET_ADDRSTRLEN);
484 ip_type = "IPv4";
485 }
486
487 // Check if it's a valid IPv4 address
488 if (strcmp(ip_type, "IPv4") == 0 && is_valid_ipv4(ip_str) && !
489 is_in_private_network(ip_str))
490 {
491 // Guarded print of the IP address and port
492 guarded_print_line("Valid IPv4 Peer: %s:%u (timestamp: %u)", ip_str,
493 port, timestamp);
494
495 // Add to peer queue
496 add_peer_to_queue(ip_str, port);
497
498 // Log the result if valid
499 log_message(LOG_INFO, log_filename, __FILE__,
500 "Received valid IPv4 address: %s:%u (timestamp: %u)",
501 ip_str, port, timestamp);
502 }
503 else if (strcmp(ip_type, "IPv6") == 0)
504 {
505 // Log the IPv6 addresses if needed
506 log_message(LOG_INFO, log_filename, __FILE__,
507 "Received IPv6 address: %s:%u (timestamp: %u)",
508 ip_str, port, timestamp);
509 }
510 }
511
512 if (offset != payload_len)
513 {
514 log_message(LOG_WARN, log_filename, __FILE__,
515 "Remaining bytes after processing: %zu",
516 payload_len - offset);
517 }
518 }
519 }
520 else
521 {
522 log_message(LOG_WARN, log_filename, __FILE__,
523 "else hdr->magic ");
524 }
525
526 node->operation_in_progress = 0;
527}
int is_in_private_network(const char *ip_addr)
Check if the IP address is in the private prefix (e.g.
Definition ip.c:98
void add_peer_to_queue(const char *ip, int port)
Add a peer to the queue.
Definition peer_queue.c:15
int operation_in_progress
size_t read_var_int(const unsigned char *data, uint64_t *value)
Convert a 64-bit integer from network byte order to host byte order.
int is_valid_ipv4(const char *ip_str)
Check if the IP address is valid.
Definition utils.c:116

References add_peer_to_queue(), BITCOIN_MAINNET_MAGIC, build_message(), bitcoin_msg_header::command, guarded_print_line(), Node::ip_address, Node::is_connected, is_in_private_network(), is_valid_ipv4(), bitcoin_msg_header::length, LOG_INFO, log_message(), LOG_WARN, bitcoin_msg_header::magic, MAX_NODES, nodes, Node::operation_in_progress, read_var_int(), and Node::socket_fd.

Referenced by cli_getaddr().

◆ send_getblocks_and_wait()

void send_getblocks_and_wait ( int  idx)

Sends a 'getblocks' message to the peer and waits for a response.

This function sends a 'getblocks' message to the peer identified by the given index and waits for a response. It is used to request a list of blocks from the connected peer. The response is processed and the blocks are saved to a file.

Parameters
idxThe index of the peer in the nodes array.

Definition at line 1518 of file peer_connection.c.

1519{
1520 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
1521 {
1522 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
1523 return;
1524 }
1525
1526 Node* node = &nodes[idx];
1527 char log_filename[256];
1528 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
1529
1530 // Define block locator and locator count
1531 unsigned char block_locator[MAX_LOCATOR_COUNT * 32];
1532 int locator_count = 1; // Set to 1 to request blocks starting from the latest known block
1533
1534 // Load the latest known block hash
1535 load_latest_known_block_hash(block_locator);
1536
1537 // Build the 'getblocks' message
1538 unsigned char getblocks_msg[sizeof(bitcoin_msg_header) + 4 + 1 + (MAX_LOCATOR_COUNT * 32) + 32];
1539 size_t msg_len = build_getblocks_message(getblocks_msg, sizeof(getblocks_msg), block_locator, locator_count);
1540 if (msg_len == 0)
1541 {
1542 fprintf(stderr, "[Error] Failed to build 'getblocks' message.\n");
1543 return;
1544 }
1545
1546 // Send the 'getblocks' message
1547 ssize_t bytes_sent = send(node->socket_fd, getblocks_msg, msg_len, 0);
1548 if (bytes_sent < 0)
1549 {
1550 log_message(LOG_INFO, log_filename, __FILE__,
1551 "[Error] Failed to send 'getblocks' message: %s", strerror(errno));
1552 return;
1553 }
1554
1555 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'getblocks' message.");
1556 node->operation_in_progress = 1;
1557
1558 // Wait for 10 seconds for a response
1559 struct timeval tv;
1560 tv.tv_sec = 10;
1561 tv.tv_usec = 0;
1562 setsockopt(node->socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
1563
1564 // Increase buffer size to handle larger responses
1565 unsigned char buffer[32768];
1566 size_t total_bytes_received = 0;
1567 ssize_t bytes_received;
1568
1569 // Receive the message in parts
1570 while ((bytes_received = recv(node->socket_fd, buffer + total_bytes_received, sizeof(buffer) - total_bytes_received - 1, 0)) > 0)
1571 {
1572 total_bytes_received += bytes_received;
1573 }
1574
1575 if (bytes_received < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
1576 {
1577 log_message(LOG_INFO, log_filename, __FILE__,
1578 "[Error] Failed to receive response: %s", strerror(errno));
1579 node->operation_in_progress = 0;
1580 return;
1581 }
1582
1583 log_message(LOG_INFO, log_filename, __FILE__, "Received response to 'getblocks' message.");
1584 node->operation_in_progress = 0;
1585
1586 // Process the response and print to CLI
1587 guarded_print("Received response to 'getblocks' message:\n");
1588 parse_inv_message(buffer, total_bytes_received);
1589
1590 // Save the blocks to a file
1591 save_blocks_to_file(buffer, total_bytes_received, "blocks.dat");
1592}
size_t build_getblocks_message(unsigned char *buffer, size_t buffer_size, const unsigned char *block_locator, size_t locator_count)
void parse_inv_message(const unsigned char *payload, size_t payload_len)
void save_blocks_to_file(const unsigned char *payload, size_t payload_len, const char *filename)
void load_latest_known_block_hash(unsigned char *block_hash)
#define MAX_LOCATOR_COUNT

References build_getblocks_message(), guarded_print(), Node::ip_address, load_latest_known_block_hash(), LOG_INFO, log_message(), MAX_LOCATOR_COUNT, MAX_NODES, nodes, Node::operation_in_progress, parse_inv_message(), save_blocks_to_file(), and Node::socket_fd.

Referenced by cli_getblocks().

◆ send_getdata_and_wait()

void send_getdata_and_wait ( int  idx,
const unsigned char *  hashes,
size_t  hash_count 
)

Sends a 'getdata' message to the peer and waits for a response.

This function sends a 'getdata' message to the peer identified by the given index and waits for a response. It is used to request specific blocks or transactions from the connected peer based on the provided hashes. The response is saved to a file and logged to the Bitlab logs.

Parameters
idxThe index of the peer in the nodes array.
hashesAn array of hashes representing the blocks or transactions to request.
hash_countThe number of hashes in the array.

Definition at line 1728 of file peer_connection.c.

1729{
1730 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
1731 {
1732 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
1733 return;
1734 }
1735
1736 if (hash_count == 0 || hash_count > 50000)
1737 {
1738 fprintf(stderr, "[Error] Invalid hash count. Must be between 1 and 50000.\n");
1739 return;
1740 }
1741
1742 Node* node = &nodes[idx];
1743 char log_filename[256];
1744 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
1745
1746 // Build the 'getdata' message
1747 unsigned char getdata_msg[sizeof(bitcoin_msg_header) + 1 + (hash_count * 36)];
1748 size_t msg_len = build_getdata_message(getdata_msg, sizeof(getdata_msg), hashes, hash_count);
1749 if (msg_len == 0)
1750 {
1751 fprintf(stderr, "[Error] Failed to build 'getdata' message.\n");
1752 return;
1753 }
1754
1755 // Send the 'getdata' message
1756 ssize_t bytes_sent = send(node->socket_fd, getdata_msg, msg_len, 0);
1757 if (bytes_sent < 0)
1758 {
1759 log_message(LOG_INFO, log_filename, __FILE__,
1760 "[Error] Failed to send 'getdata' message: %s", strerror(errno));
1761 return;
1762 }
1763
1764 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'getdata' message.");
1765 node->operation_in_progress = 1;
1766
1767 // Wait for 20 seconds for a response (increased timeout)
1768 struct timeval tv;
1769 tv.tv_sec = 20;
1770 tv.tv_usec = 0;
1771 setsockopt(node->socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
1772
1773 // Receive the response
1774 unsigned char buffer[32768];
1775 ssize_t bytes_received;
1776
1777 while ((bytes_received = recv(node->socket_fd, buffer, sizeof(buffer), 0)) > 0)
1778 {
1779 bitcoin_msg_header* hdr = (bitcoin_msg_header*)buffer;
1780 if (hdr->magic == BITCOIN_MAINNET_MAGIC)
1781 {
1782 char cmd_name[13];
1783 memset(cmd_name, 0, sizeof(cmd_name));
1784 memcpy(cmd_name, hdr->command, 12);
1785
1786 if (strcmp(cmd_name, "block") == 0)
1787 {
1788 log_message(LOG_INFO, log_filename, __FILE__, "Received 'block' message.");
1789 decode_transactions(buffer + sizeof(bitcoin_msg_header), hdr->length);
1790 }
1791 }
1792 }
1793
1794 if (bytes_received < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
1795 {
1796 log_message(LOG_INFO, log_filename, __FILE__,
1797 "[Error] Failed to receive block message: %s", strerror(errno));
1798 }
1799
1800 node->operation_in_progress = 0;
1801}
void decode_transactions(const unsigned char *block_data, size_t block_len)
size_t build_getdata_message(unsigned char *buffer, size_t buffer_size, const unsigned char *hashes, size_t hash_count)

References BITCOIN_MAINNET_MAGIC, build_getdata_message(), bitcoin_msg_header::command, decode_transactions(), Node::ip_address, bitcoin_msg_header::length, LOG_INFO, log_message(), bitcoin_msg_header::magic, MAX_NODES, nodes, Node::operation_in_progress, and Node::socket_fd.

Referenced by cli_getdata(), and handle_inv_message().

◆ send_getheaders_and_wait()

void send_getheaders_and_wait ( int  idx)

Sends a 'getheaders' message to the peer and waits for a response.

This function sends a 'getheaders' message to the peer identified by the given index and waits for a response. It is used to request a list of known peers from the connected peer.

Parameters
idxThe index of the peer in the nodes array.

Definition at line 1330 of file peer_connection.c.

1331{
1332 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
1333 {
1334 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
1335 return;
1336 }
1337
1338 Node* node = &nodes[idx];
1339 char log_filename[256];
1340 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
1341
1342 // Define block locator and locator count
1343 unsigned char block_locator[MAX_LOCATOR_COUNT * 32];
1344 int locator_count = 1; // Set to 1 to request headers starting from the latest known block
1345
1346 // Load the latest known block hash
1347 load_latest_known_block_hash(block_locator);
1348
1349 // Build the 'getheaders' message
1350 unsigned char getheaders_msg[sizeof(bitcoin_msg_header) + 4 + 1 + (MAX_LOCATOR_COUNT * 32) + 32];
1351 size_t msg_len = build_getheaders_message(getheaders_msg, sizeof(getheaders_msg), block_locator, locator_count);
1352 if (msg_len == 0)
1353 {
1354 fprintf(stderr, "[Error] Failed to build 'getheaders' message.\n");
1355 return;
1356 }
1357
1358 // Send the 'getheaders' message
1359 ssize_t bytes_sent = send(node->socket_fd, getheaders_msg, msg_len, 0);
1360 if (bytes_sent < 0)
1361 {
1362 log_message(LOG_INFO, log_filename, __FILE__,
1363 "[Error] Failed to send 'getheaders' message: %s", strerror(errno));
1364 return;
1365 }
1366
1367 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'getheaders' message.");
1368 node->operation_in_progress = 1;
1369
1370 // Wait for 10 seconds for a response
1371 struct timeval tv;
1372 tv.tv_sec = 10;
1373 tv.tv_usec = 0;
1374 setsockopt(node->socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
1375
1376 // Receive the response
1377 unsigned char buffer[4096];
1378 ssize_t bytes_received = recv(node->socket_fd, buffer, sizeof(buffer), 0);
1379 if (bytes_received < 0)
1380 {
1381 log_message(LOG_INFO, log_filename, __FILE__,
1382 "[Error] Failed to receive response: %s", strerror(errno));
1383 node->operation_in_progress = 0;
1384 return;
1385 }
1386
1387 log_message(LOG_INFO, log_filename, __FILE__, "Received response to 'getheaders' message.");
1388 node->operation_in_progress = 0;
1389
1390 // Process the response and print to CLI
1391 guarded_print("Received response to 'getheaders' message:\n");
1392 parse_headers_message(buffer, bytes_received);
1393}
size_t build_getheaders_message(unsigned char *buffer, size_t buffer_size, const unsigned char *block_locator, size_t locator_count)
void parse_headers_message(const unsigned char *payload, size_t payload_len)

References build_getheaders_message(), guarded_print(), Node::ip_address, load_latest_known_block_hash(), LOG_INFO, log_message(), MAX_LOCATOR_COUNT, MAX_NODES, nodes, Node::operation_in_progress, parse_headers_message(), and Node::socket_fd.

Referenced by cli_getheaders().

◆ send_headers()

void send_headers ( int  idx,
const unsigned char *  start_hash,
const unsigned char *  stop_hash 
)

Sends a 'headers' message to the peer.

This function sends a 'headers' message to the peer identified by the given index. It retrieves the block headers from the local storage starting from the specified start hash up to the stop hash or the maximum number of headers allowed.

Parameters
idxThe index of the peer in the nodes array.
start_hashThe hash of the first block header to send.
stop_hashThe hash of the last block header to send.

Definition at line 1395 of file peer_connection.c.

1396{
1397 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
1398 {
1399 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
1400 return;
1401 }
1402
1403 Node* node = &nodes[idx];
1404 char log_filename[256];
1405 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
1406
1407 // Open the headers file
1408 FILE* file = fopen(HEADERS_FILE, "rb");
1409 if (!file)
1410 {
1411 perror("Failed to open headers file");
1412 return;
1413 }
1414
1415 // Find the starting block header
1416 unsigned char buffer[81];
1417 size_t headers_count = 0;
1418 int found_start = 0;
1419 while (fread(buffer, 80, 1, file) == 1)
1420 {
1421 if (memcmp(buffer, start_hash, 32) == 0)
1422 {
1423 found_start = 1;
1424 break;
1425 }
1426 }
1427
1428 if (!found_start)
1429 {
1430 fclose(file);
1431 fprintf(stderr, "[Error] Start hash not found in headers file.\n");
1432 return;
1433 }
1434
1435 // Build the 'headers' message
1436 unsigned char headers_msg[sizeof(bitcoin_msg_header) + 1 + (MAX_HEADERS_COUNT * 81)];
1437 size_t offset = sizeof(bitcoin_msg_header);
1438 headers_msg[offset++] = 0; // Placeholder for count
1439
1440 while (headers_count < MAX_HEADERS_COUNT && fread(buffer, 80, 1, file) == 1)
1441 {
1442 memcpy(headers_msg + offset, buffer, 80);
1443 offset += 80;
1444 headers_msg[offset++] = 0; // Transaction count (var_int, 0 for headers only)
1445 headers_count++;
1446
1447 if (memcmp(buffer, stop_hash, 32) == 0)
1448 {
1449 break;
1450 }
1451 }
1452
1453 fclose(file);
1454
1455 // Set the count
1456 headers_msg[sizeof(bitcoin_msg_header)] = headers_count;
1457
1458 // Build the message header
1459 bitcoin_msg_header* header = (bitcoin_msg_header*)headers_msg;
1461 strncpy(header->command, "headers", 12);
1462 header->length = htole32(offset - sizeof(bitcoin_msg_header));
1463 compute_checksum(headers_msg + sizeof(bitcoin_msg_header), offset - sizeof(bitcoin_msg_header), header->checksum);
1464
1465 // Send the 'headers' message
1466 ssize_t bytes_sent = send(node->socket_fd, headers_msg, offset, 0);
1467 if (bytes_sent < 0)
1468 {
1469 log_message(LOG_INFO, log_filename, __FILE__,
1470 "[Error] Failed to send 'headers' message: %s", strerror(errno));
1471 return;
1472 }
1473
1474 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'headers' message.");
1475}
static void compute_checksum(const unsigned char *payload, size_t payload_len, unsigned char out[4])
compute_checksum: Calculate the double-SHA256 of the payload, then copy the first 4 bytes into out[4]...
#define MAX_HEADERS_COUNT
#define htole32(x)
#define HEADERS_FILE

References BITCOIN_MAINNET_MAGIC, compute_checksum(), HEADERS_FILE, htole32, Node::ip_address, LOG_INFO, log_message(), bitcoin_msg_header::magic, MAX_HEADERS_COUNT, MAX_NODES, nodes, and Node::socket_fd.

Referenced by peer_communication().

◆ send_inv_and_wait()

void send_inv_and_wait ( int  idx,
const unsigned char *  inv_data,
size_t  inv_count 
)

Sends an 'inv' message to the peer and waits for a response.

This function sends an 'inv' message to the peer identified by the given index and waits for a response. It is used to advertise the knowledge of one or more objects (blocks or transactions). The inventory data is provided as input to the function.

Parameters
idxThe index of the peer in the nodes array.
inv_dataAn array of inventory vectors (type + hash).
inv_countThe number of inventory vectors in the array.

Sends an 'inv' message to the peer and waits for a response.

This function sends an 'inv' message to the peer identified by the given index. It is used to advertise the knowledge of one or more objects (blocks or transactions). The inventory data is provided as input to the function.

Parameters
idxThe index of the peer in the nodes array.
inv_dataAn array of inventory vectors (type + hash).
inv_countThe number of inventory vectors in the array.

Definition at line 1866 of file peer_connection.c.

1867{
1868 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
1869 {
1870 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
1871 return;
1872 }
1873
1874 if (inv_count == 0 || inv_count > 50000)
1875 {
1876 fprintf(stderr, "[Error] Invalid inventory count. Must be between 1 and 50000.\n");
1877 return;
1878 }
1879
1880 Node* node = &nodes[idx];
1881 char log_filename[256];
1882 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
1883
1884 size_t var_int_size = write_var_int(NULL, inv_count); // Get the size of the var_int encoding
1885 size_t payload_size = var_int_size + (inv_count * 36); // var_int size + 36 bytes per inventory vector
1886 size_t inv_msg_size = sizeof(bitcoin_msg_header) + payload_size;
1887
1888 printf("inv_count: %zu, inv_msg_size: %zu\n", inv_count, inv_msg_size);
1889
1890 unsigned char* inv_msg = (unsigned char*)malloc(inv_msg_size);
1891 if (!inv_msg)
1892 {
1893 fprintf(stderr, "[Error] Failed to allocate memory for 'inv' message.\n");
1894 return;
1895 }
1896
1897 size_t msg_len = build_inv_message(inv_msg, inv_msg_size, inv_data, inv_count);
1898 printf("msg_len: %zu\n", msg_len);
1899 if (msg_len == 0)
1900 {
1901 fprintf(stderr, "[Error] Failed to build 'inv' message.\n");
1902 free(inv_msg);
1903 return;
1904 }
1905
1906 // Send the 'inv' message
1907 ssize_t bytes_sent = send(node->socket_fd, inv_msg, msg_len, 0);
1908 if (bytes_sent < 0)
1909 {
1910 log_message(LOG_INFO, log_filename, __FILE__,
1911 "[Error] Failed to send 'inv' message: %s", strerror(errno));
1912 free(inv_msg);
1913 return;
1914 }
1915
1916 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'inv' message.");
1917 printf("Sent 'inv' message.\n");
1918 node->operation_in_progress = 1;
1919
1920 // Wait for 10 seconds for a response
1921 struct timeval tv;
1922 tv.tv_sec = 10;
1923 tv.tv_usec = 0;
1924 setsockopt(node->socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
1925
1926 // Receive the response
1927 unsigned char buffer[32768];
1928 ssize_t bytes_received = recv(node->socket_fd, buffer, sizeof(buffer), 0);
1929 if (bytes_received < 0)
1930 {
1931 log_message(LOG_INFO, log_filename, __FILE__,
1932 "[Error] Failed to receive response: %s", strerror(errno));
1933 node->operation_in_progress = 0;
1934 free(inv_msg);
1935 return;
1936 }
1937
1938 log_message(LOG_INFO, log_filename, __FILE__, "Received response to 'inv' message.");
1939 printf("Received response to 'inv' message.\n");
1940 node->operation_in_progress = 0;
1941
1942 // Process the response
1943 if (bytes_received >= (ssize_t)sizeof(bitcoin_msg_header))
1944 {
1945 bitcoin_msg_header* hdr = (bitcoin_msg_header*)buffer;
1946 if (hdr->magic == BITCOIN_MAINNET_MAGIC)
1947 {
1948 char cmd_name[13];
1949 memset(cmd_name, 0, sizeof(cmd_name));
1950 memcpy(cmd_name, hdr->command, 12);
1951
1952 printf("Received command: '%s'\n", cmd_name);
1953
1954 if (strcmp(cmd_name, "inv") == 0)
1955 {
1956 printf("Received 'inv' response:\n");
1957 handle_inv_message(idx, buffer + sizeof(bitcoin_msg_header), bytes_received - sizeof(bitcoin_msg_header));
1958 }
1959 else
1960 {
1961 printf("Unhandled command: '%s'\n", cmd_name);
1962 }
1963 }
1964 else
1965 {
1966 printf("Unexpected magic bytes (0x%08X).\n", hdr->magic);
1967 }
1968 }
1969 else
1970 {
1971 printf("Received incomplete message.\n");
1972 }
1973
1974 free(inv_msg);
1975}
size_t write_var_int(unsigned char *buf, uint64_t value)
void handle_inv_message(int idx, const unsigned char *payload, size_t payload_len)
size_t build_inv_message(unsigned char *buffer, size_t buffer_size, const unsigned char *inv_data, size_t inv_count)
Builds an 'inv' message.

References BITCOIN_MAINNET_MAGIC, build_inv_message(), bitcoin_msg_header::command, handle_inv_message(), Node::ip_address, LOG_INFO, log_message(), bitcoin_msg_header::magic, MAX_NODES, nodes, Node::operation_in_progress, Node::socket_fd, and write_var_int().

Referenced by cli_inv().

◆ send_tx()

void send_tx ( int  idx,
const unsigned char *  tx_data,
size_t  tx_size 
)

Sends a 'tx' message to the specified node.

This function sends a 'tx' message to the node identified by the given index with the provided transaction data. It constructs the message with the appropriate Bitcoin protocol header and sends it over the network socket associated with the node.

Parameters
idxThe index of the node in the nodes array.
tx_dataA pointer to the transaction data in hexadecimal format.
tx_sizeThe size of the transaction data in bytes.

Definition at line 2047 of file peer_connection.c.

2048{
2049 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
2050 {
2051 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
2052 return;
2053 }
2054
2055 Node* node = &nodes[idx];
2056 char log_filename[256];
2057 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
2058
2059 if (!tx_data || tx_size == 0)
2060 {
2061 fprintf(stderr, "[Error] Invalid transaction data.\n");
2062 return;
2063 }
2064
2065 // Build the 'tx' message with the appropriate header
2066 unsigned char tx_msg[sizeof(bitcoin_msg_header) + tx_size];
2067
2068 // Build the message header
2069 bitcoin_msg_header* header = (bitcoin_msg_header*)tx_msg;
2071 strncpy(header->command, "tx", 12);
2072 header->length = htole32(tx_size);
2073 compute_checksum(tx_data, tx_size, header->checksum);
2074
2075 // Copy the transaction data
2076 memcpy(tx_msg + sizeof(bitcoin_msg_header), tx_data, tx_size);
2077
2078 // Send the 'tx' message
2079 ssize_t bytes_sent = send(node->socket_fd, tx_msg, sizeof(bitcoin_msg_header) + tx_size, 0);
2080 if (bytes_sent < 0)
2081 {
2082 log_message(LOG_INFO, log_filename, __FILE__,
2083 "[Error] Failed to send 'tx' message: %s", strerror(errno));
2084 return;
2085 }
2086
2087 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'tx' message (%zu bytes).", tx_size);
2088}

References BITCOIN_MAINNET_MAGIC, compute_checksum(), htole32, Node::ip_address, LOG_INFO, log_message(), bitcoin_msg_header::magic, MAX_NODES, nodes, and Node::socket_fd.

Referenced by cli_tx().

Variable Documentation

◆ nodes