void btc_node_send_version(btc_node *node) { if (!node) return; /* get new string buffer */ cstring *version_msg_cstr = cstr_new_sz(256); /* copy socket_addr to p2p addr */ btc_p2p_address fromAddr; btc_p2p_address_init(&fromAddr); btc_p2p_address toAddr; btc_p2p_address_init(&toAddr); btc_addr_to_p2paddr(&node->addr, &toAddr); /* create a version message struct */ btc_p2p_version_msg version_msg; memset(&version_msg, 0, sizeof(version_msg)); /* create a serialized version message */ btc_p2p_msg_version_init(&version_msg, &fromAddr, &toAddr, node->nodegroup->clientstr); btc_p2p_msg_version_ser(&version_msg, version_msg_cstr); /* create p2p message */ cstring *p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_VERSION, version_msg_cstr->str, version_msg_cstr->len); /* send message */ btc_node_send(node, p2p_msg); /* cleanup */ cstr_free(version_msg_cstr, true); cstr_free(p2p_msg, true); }
void node_periodical_timer(int fd, short event, void *ctx) { UNUSED(fd); UNUSED(event); btc_node *node = (btc_node *)ctx; uint64_t now = time(NULL); /* pass data to the callback and give it a chance to cancle the call */ if (node->nodegroup->periodic_timer_cb) if (!node->nodegroup->periodic_timer_cb(node, &now)) return; if (node->time_started_con+BTC_CONNECT_TIMEOUT_S < now && ((node->state & NODE_CONNECTING) == NODE_CONNECTING)) { node->state = 0; node->time_started_con = 0; node->state |= NODE_ERRORED; node->state |= NODE_TIMEOUT; btc_node_connection_state_changed(node); } if ( ((node->state & NODE_CONNECTED) == NODE_CONNECTED) && node->lastping + BTC_PING_INTERVAL_S < now) { //time for a ping uint64_t nonce; btc_cheap_random_bytes((uint8_t *)&nonce, sizeof(nonce)); cstring *pingmsg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_PING, &nonce, sizeof(nonce)); btc_node_send(node, pingmsg); cstr_free(pingmsg, true); node->lastping = now; } }
int btc_node_parse_message(btc_node *node, btc_p2p_msg_hdr *hdr, struct const_buffer *buf) { node->nodegroup->log_write_cb("received command from node %d: %s\n", node->nodeid, hdr->command); if (memcmp(hdr->netmagic, node->nodegroup->chainparams->netmagic, sizeof(node->nodegroup->chainparams->netmagic)) != 0) return 0; /* send the header and buffer to the possible callback */ /* callback can decide to run the internal base message logic */ if (!node->nodegroup->parse_cmd_cb || node->nodegroup->parse_cmd_cb(node, hdr, buf)) { if (strcmp(hdr->command, BTC_MSG_VERSION) == 0) { /* confirm version for verack */ cstring *verack = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_VERACK, NULL, 0); btc_node_send(node, verack); cstr_free(verack, true); } else if (strcmp(hdr->command, BTC_MSG_VERACK) == 0) { /* complete handshake if verack has been received */ node->version_handshake = true; /* execute callback and inform that the node is ready for custom message logic */ if (node->nodegroup->handshake_done_cb) node->nodegroup->handshake_done_cb(node); } else if (strcmp(hdr->command, BTC_MSG_PING) == 0) { /* response pings */ uint64_t nonce = 0; deser_u64(&nonce, buf); cstring *pongmsg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_PONG, &nonce, 8); btc_node_send(node, pongmsg); cstr_free(pongmsg, true); } } /* pass data to the "post command" callback */ if (node->nodegroup->postcmd_cb) node->nodegroup->postcmd_cb(node, hdr, buf); return true; }
void test_protocol() { /* get new string buffer */ cstring *version_msg_cstr = cstr_new_sz(256); cstring *inv_msg_cstr = cstr_new_sz(256); struct sockaddr_in test_sa, test_sa_check; memset(&test_sa, 0, sizeof(test_sa)); memset(&test_sa_check, 0, sizeof(test_sa_check)); test_sa.sin_family = AF_INET; struct sockaddr_in6 test_sa6, test_sa6_check; test_sa6.sin6_family = AF_INET6; test_sa6.sin6_port = htons(1024); evutil_inet_pton(AF_INET, "10.0.0.1", &test_sa.sin_addr); // store IP in antelope char i6buf[1024]; memset(&i6buf, 0, 1024); evutil_inet_pton(AF_INET6, "::1", &test_sa6.sin6_addr); btc_p2p_address ipv6Test; btc_p2p_address_init(&ipv6Test); btc_addr_to_p2paddr((struct sockaddr *)&test_sa6, &ipv6Test); btc_p2paddr_to_addr(&ipv6Test, (struct sockaddr *)&test_sa6_check); memset(&i6buf, 0, 1024); u_assert_int_eq(test_sa6.sin6_port, test_sa6_check.sin6_port); /* copy socket_addr to p2p addr */ btc_p2p_address fromAddr; btc_p2p_address_init(&fromAddr); btc_p2p_address toAddr; btc_p2p_address_init(&toAddr); btc_addr_to_p2paddr((struct sockaddr *)&test_sa, &toAddr); btc_p2paddr_to_addr(&toAddr, (struct sockaddr *)&test_sa_check); u_assert_int_eq(test_sa.sin_port, test_sa_check.sin_port); evutil_inet_ntop(AF_INET, &test_sa_check.sin_addr, i6buf, 1024); u_assert_str_eq(i6buf, "10.0.0.1"); /* create a inv message struct */ btc_p2p_inv_msg inv_msg, inv_msg_check; memset(&inv_msg, 0, sizeof(inv_msg)); uint256 hash = {0}; btc_p2p_msg_inv_init(&inv_msg, 1, hash); btc_p2p_msg_inv_ser(&inv_msg, inv_msg_cstr); struct const_buffer buf_inv = {inv_msg_cstr->str, inv_msg_cstr->len}; u_assert_int_eq(btc_p2p_msg_inv_deser(&inv_msg_check, &buf_inv), true); u_assert_int_eq(inv_msg_check.type, 1); u_assert_mem_eq(inv_msg_check.hash, inv_msg.hash, sizeof(inv_msg.hash)); cstr_free(inv_msg_cstr, true); /* create a version message struct */ btc_p2p_version_msg version_msg; memset(&version_msg, 0, sizeof(version_msg)); /* create a serialized version message */ btc_p2p_msg_version_init(&version_msg, &fromAddr, &toAddr, "client", false); btc_p2p_msg_version_ser(&version_msg, version_msg_cstr); /* create p2p message */ cstring *p2p_msg = btc_p2p_message_new((unsigned const char *)&btc_chainparams_main.netmagic, BTC_MSG_VERSION, version_msg_cstr->str, version_msg_cstr->len); struct const_buffer buf = {p2p_msg->str, p2p_msg->len}; btc_p2p_msg_hdr hdr; btc_p2p_deser_msghdr(&hdr, &buf); u_assert_mem_eq(hdr.netmagic, &btc_chainparams_main.netmagic, 4); u_assert_str_eq(hdr.command, BTC_MSG_VERSION); u_assert_int_eq(hdr.data_len, version_msg_cstr->len); u_assert_int_eq(buf.len, hdr.data_len); u_assert_int_eq(buf.len, hdr.data_len); u_assert_mem_eq(buf.p, version_msg_cstr->str, hdr.data_len); btc_p2p_version_msg v_msg_check; u_assert_int_eq(btc_p2p_msg_version_deser(&v_msg_check, &buf), true); u_assert_int_eq(v_msg_check.version, BTC_PROTOCOL_VERSION); u_assert_str_eq(v_msg_check.useragent, "client"); u_assert_int_eq(v_msg_check.start_height, 0); cstr_free(p2p_msg, true); cstr_free(version_msg_cstr, true); /* getheaders */ uint256 genesis_hash = {0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xd6, 0x68, 0x9c, 0x08, 0x5a, 0xe1, 0x65, 0x83, 0x1e, 0x93, 0x4f, 0xf7, 0x63, 0xae, 0x46, 0xa2, 0xa6, 0xc1, 0x72, 0xb3, 0xf1, 0xb6, 0x0a, 0x8c, 0xe2, 0x6f}; vector *blocklocators = vector_new(1, NULL); vector_add(blocklocators, genesis_hash); cstring *getheader_msg = cstr_new_sz(256); btc_p2p_msg_getheaders(blocklocators, NULL, getheader_msg); p2p_msg = btc_p2p_message_new((unsigned const char *)&btc_chainparams_main.netmagic, BTC_MSG_GETHEADERS, getheader_msg->str, getheader_msg->len); buf.p = p2p_msg->str; buf.len = p2p_msg->len; btc_p2p_deser_msghdr(&hdr, &buf); u_assert_str_eq(hdr.command, BTC_MSG_GETHEADERS); u_assert_int_eq(hdr.data_len, getheader_msg->len); uint256 hashstop_check; vector *blocklocators_check = vector_new(1, free); btc_p2p_deser_msg_getheaders(blocklocators_check, hashstop_check, &buf); u_assert_mem_eq(NULLHASH, hashstop_check, sizeof(hashstop_check)); uint8_t *hash_loc_0 = vector_idx(blocklocators_check, 0); u_assert_mem_eq(genesis_hash, hash_loc_0, sizeof(genesis_hash)); /* cleanup */ cstr_free(getheader_msg, true); vector_free(blocklocators, true); vector_free(blocklocators_check, true); cstr_free(p2p_msg, true); }