Files
skalacoin/include/nets/net_node.h
T

124 lines
5.3 KiB
C

#ifndef NET_NODE_H
#define NET_NODE_H
#ifndef _WIN32
// POSIX
#include <tcpd/tcpconnection.h>
#include <tcpd/tcpclient.h>
#include <tcpd/tcpserver.h>
#endif
#include <constants.h>
#include <packettype.h>
#include <udpd/udpnode.h>
// Forward declaration - the discovery state is defined in nodediscovery.c (opaque here).
typedef struct node_discovery node_discovery_t;
#include <stddef.h>
#include <dlibc/vector.h>
#include <dlibc/set.h>
#include <pthread.h>
#include <block/block.h>
#include <block/chain.h>
#include <block/transaction.h>
#include <stdatomic.h>
typedef struct {
tcp_server_t* server;
tcp_client_t outboundClients[MAX_CONS];
size_t outboundCount;
// Dedup cache for recently seen block hashes (canonical 32-byte hash)
set_t* seenBlocks;
// Protects seenBlocks
pthread_mutex_t seenLock;
// Protects outboundClients snapshots and peerBlockHeight writes
pthread_mutex_t outboundLock;
void (*on_connect)(tcp_connection_t* conn, void* user);
void (*on_data)(tcp_connection_t* conn, const unsigned char* data, size_t len, void* user);
void (*on_disconnect)(tcp_connection_t* conn, void* user);
void* callbackUser;
// Maintenance thread for periodic tasks (orphan attach, pruning, metrics)
pthread_t maintenanceThread;
// Cross-thread stop flag: written by Node_Destroy on the main thread, read by the maintenance
// thread's loop condition. `volatile` stops the compiler hoisting the load but provides neither
// atomicity nor ordering, so this has to be a real atomic (and TSan rightly flagged it).
_Atomic int maintenanceRunning;
int maintenanceIntervalMs;
// UDP ping/pong daemon (latency oracle) and peer discovery state
udp_node_t* udpNode;
node_discovery_t* discovery;
} net_node_t;
net_node_t* Node_Create();
void Node_Destroy(net_node_t* node);
void Node_SetCallbacks(
net_node_t* node,
void (*on_connect)(tcp_connection_t* conn, void* user),
void (*on_data)(tcp_connection_t* conn, const unsigned char* data, size_t len, void* user),
void (*on_disconnect)(tcp_connection_t* conn, void* user),
void* user
);
int Node_ConnectPeer(net_node_t* node, const char* ip, unsigned short port);
int Node_ConnectStartupPeers(net_node_t* node, const char** ips, const unsigned short* ports, size_t peersCount);
int Node_SendPacket(net_node_t* node, tcp_connection_t* conn, packet_type_t packetType, const void* payload, size_t payloadLen);
int Node_BroadcastTransaction(net_node_t* node, signed_transaction_t* tx, tcp_connection_t* excludeNode);
// Helpers for outbound peer selection and block broadcast
int Node_GetBestOutboundPeer(net_node_t* node, tcp_connection_t** outConn, uint64_t* outHeight);
/**
* Delivery receipts for windowed sync.
*
* A FETCH_BLOCK reply is handled on the peer's io thread and may legitimately never reach the
* chain: a block belonging to a competing branch is filed in the orphan pool instead. A sync loop
* that infers arrival from the chain growing therefore cannot tell "arrived but forked" from "lost
* in transit", so it re-requests until it times out. Against a peer on a fork that costs one full
* retry-and-timeout cycle for EVERY block, which is why syncing to a forked peer used to crawl.
*
* DUPLICATE is what makes a backwards fork walk terminate: it means we already hold exactly that
* block, so the two chains agree at that height and there is no reason to keep descending.
**/
typedef enum {
NODE_DELIVERY_APPENDED = 0, // joined our chain
NODE_DELIVERY_DUPLICATE = 1, // we already held this exact block -- common ground
NODE_DELIVERY_ORPHANED = 2, // belongs to a competing branch; now in the orphan pool
NODE_DELIVERY_REJECTED = 3 // failed validation
} node_delivery_status_t;
void Node_NoteBlockDelivered(uint64_t height, node_delivery_status_t status);
bool Node_TakeBlockDelivery(uint64_t height, node_delivery_status_t* outStatus);
void Node_ResetBlockDeliveries(void);
void Node_BroadcastChainRange(net_node_t* node, size_t startHeightInclusive, tcp_connection_t* sourceConn);
// Callback logic
void Node_Server_OnConnect(tcp_connection_t* client);
void Node_Server_OnData(tcp_connection_t* client);
void Node_Server_OnDisconnect(tcp_connection_t* client);
void Node_Client_OnConnect(tcp_connection_t* client);
void Node_Client_OnData(tcp_connection_t* client);
void Node_Client_OnDisconnect(tcp_connection_t* client);
void Node_GetClientList(net_node_t* node, tcp_connection_t** outClients, size_t* outCount);
// Computes a connection's peer listen endpoint (IP + advertised/dialed listen port) into *out.
// Outbound: the dialed peerAddr port already is the listen port. Inbound: uses peerListenPort.
// Returns non-zero on success (usable endpoint with a known, non-zero port), zero otherwise.
int Node_ConnListenEndpoint(const tcp_connection_t* conn, struct sockaddr_storage* out);
// Returns the node identity advertised by a connection's peer, or 0 if it is not known yet.
uint64_t Node_ConnPeerNodeId(const tcp_connection_t* conn);
// Fills outEndpoints with the listen endpoints of all current connections (inbound + outbound),
// deduped by IP+port, and outNodeIds (optional, may be NULL) with the matching peer identities.
// Returns the number of endpoints written (<= maxOut).
size_t Node_GetPeerEndpoints(net_node_t* node, struct sockaddr_storage* outEndpoints, uint64_t* outNodeIds, size_t maxOut);
#endif