static bool nc_msg_verack(struct nc_conn *conn) { if (conn->seen_verack) return false; conn->seen_verack = true; if (debugging) fprintf(plog, "net: %s verack\n", conn->addr_str); /* * When a connection attempt is made, the peer is deleted * from the peer list. When we successfully connect, * the peer is re-added. Thus, peers are immediately * forgotten if they fail, on the first try. */ conn->peer.last_ok = time(NULL); conn->peer.n_ok++; conn->peer.addr.nTime = (uint32_t) conn->peer.last_ok; peerman_add(conn->nci->peers, &conn->peer, true); /* request peer addresses */ if ((conn->protover >= CADDR_TIME_VERSION) && (!nc_conn_send(conn, "getaddr", NULL, 0))) return false; LOG("req addr success, now request blocks"); /* request blocks */ bool rc = true; time_t now = time(NULL); time_t cutoff = now - (24 * 60 * 60); if (conn->nci->last_getblocks < cutoff) { LOG("compose blocks message"); struct msg_getblocks gb; msg_getblocks_init(&gb); blkdb_locator(&db, NULL, &gb.locator); cstring *s = ser_msg_getblocks(&gb); rc = nc_conn_send(conn, "getblocks", s->str, s->len); cstr_free(s, true); msg_getblocks_free(&gb); conn->nci->last_getblocks = now; } return rc; }
/* connection begins */ static void nc_conn_evt_connected(int fd, short events, void *priv) { struct nc_conn *conn = priv; if ((events & EV_WRITE) == 0) { fprintf(plog, "net: %s connection timeout\n", conn->addr_str); goto err_out; } int err = 0; socklen_t len = sizeof(err); /* check success of connect(2) */ if ((getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0) || (err != 0)) { fprintf(plog, "net: connect %s failed: %s\n", conn->addr_str, strerror(err)); goto err_out; } if (debugging) fprintf(plog, "net: connected to %s\n", conn->addr_str); conn->connected = true; /* clear event used for watching connect(2) */ event_free(conn->ev); conn->ev = NULL; /* build and send "version" message */ cstring *msg_data = nc_version_build(conn); bool rc = nc_conn_send(conn, "version", msg_data->str, msg_data->len); cstr_free(msg_data, true); if (!rc) { fprintf(plog, "net: %s !conn_send\n", conn->addr_str); goto err_out; } /* switch to read-header state */ conn->msg_p = conn->hdrbuf; /* from message.c #define P2P_HDR_SZ (4 + 12 + 4 + 4)*/ conn->expected = P2P_HDR_SZ; conn->reading_hdr = true; if (!nc_conn_read_enable(conn)) { fprintf(plog, "net: %s read not enabled\n", conn->addr_str); goto err_out; } return; err_out: nc_conn_kill(conn); }
static bool nc_msg_version(struct nc_conn *conn) { if (conn->seen_version){ LOG("version command already seen from:%s", conn->addr_str); return false; } conn->seen_version = true; struct const_buffer buf = { conn->msg.data, conn->msg.hdr.data_len }; struct msg_version mv; bool rc = false; msg_version_init(&mv); if (!deser_msg_version(&mv, &buf)) goto out; if (debugging) { char fromstr[64], tostr[64]; bn_address_str(fromstr, sizeof(fromstr), mv.addrFrom.ip); bn_address_str(tostr, sizeof(tostr), mv.addrTo.ip); fprintf(plog, "net: %s version(%u, 0x%llx, %lld, To:%s, From:%s, %s, %u)\n", conn->addr_str, mv.nVersion, (unsigned long long) mv.nServices, (long long) mv.nTime, tostr, fromstr, mv.strSubVer, mv.nStartingHeight); } if (!(mv.nServices & NODE_NETWORK)) /* require NODE_NETWORK */ goto out; if (mv.nonce == instance_nonce) /* connected to ourselves? */ goto out; conn->protover = MIN(mv.nVersion, PROTO_VERSION); /* acknowledge version receipt */ if (!nc_conn_send(conn, "verack", NULL, 0)) goto out; rc = true; out: msg_version_free(&mv); return rc; }
static bool nc_msg_inv(struct nc_conn *conn) { struct const_buffer buf = { conn->msg.data, conn->msg.hdr.data_len }; struct msg_vinv mv, mv_out; bool rc = false; msg_vinv_init(&mv); msg_vinv_init(&mv_out); if (!deser_msg_vinv(&mv, &buf)) goto out; if (log_state->debug && mv.invs && mv.invs->len == 1) { struct bp_inv *inv = parr_idx(mv.invs, 0); char hexstr[BU256_STRSZ]; bu256_hex(hexstr, &inv->hash); char typestr[32]; switch (inv->type) { case MSG_TX: strcpy(typestr, "tx"); break; case MSG_BLOCK: strcpy(typestr, "block"); break; default: sprintf(typestr, "unknown 0x%x", inv->type); break; } log_debug("net: %s inv %s %s", conn->addr_str, typestr, hexstr); } else if (mv.invs) { log_debug("net: %s inv (%zu sz)", conn->addr_str, mv.invs->len); } if (!mv.invs || !mv.invs->len) goto out_ok; /* scan incoming inv's for interesting material */ unsigned int i; for (i = 0; i < mv.invs->len; i++) { struct bp_inv *inv = parr_idx(mv.invs, i); switch (inv->type) { case MSG_BLOCK: if (conn->nci->inv_block_process(&inv->hash)) msg_vinv_push(&mv_out, MSG_BLOCK, &inv->hash); break; case MSG_TX: default: break; } } /* send getdata, if they have anything we want */ if (mv_out.invs && mv_out.invs->len) { cstring *s = ser_msg_vinv(&mv_out); rc = nc_conn_send(conn, "getdata", s->str, s->len); cstr_free(s, true); } out_ok: rc = true; out: msg_vinv_free(&mv); msg_vinv_free(&mv_out); return rc; }
/* * struct msg_vinv { parr *invs; array of bp_inv }; struct bp_inv { uint32_t type; bu256_t hash; }; * * */ static bool nc_msg_inv(struct nc_conn *conn) { struct const_buffer buf = { conn->msg.data, conn->msg.hdr.data_len }; struct msg_vinv mv, mv_out; bool rc = false; unsigned int i=0; int msg_tx, msg_block, msg_other; msg_tx = msg_block = msg_other = 0; msg_vinv_init(&mv);//memset msg_vinv_init(&mv_out);//memset if (!deser_msg_vinv(&mv, &buf)) goto out; if (mv.invs){ //LOG("Peer [%s] gave %d inventory vectors",conn->addr_str, mv.invs->len); for (i = 0;i < mv.invs->len; i++){ struct bp_inv *inv = parr_idx(mv.invs, 0); switch (inv->type){ case MSG_TX: msg_tx++; break; case MSG_BLOCK: msg_block++; break; default: msg_other++; } } if (mv.invs->len > 0){ LOG("Inventory vectors: msg[%d], block[%d], other[%d]", msg_tx, msg_block, msg_other); } } if (debugging && mv.invs && mv.invs->len == 1) { struct bp_inv *inv = parr_idx(mv.invs, 0); char hexstr[BU256_STRSZ]; bu256_hex(hexstr, &inv->hash); char typestr[32]; switch (inv->type) { case MSG_TX: strcpy(typestr, "tx"); break; case MSG_BLOCK: strcpy(typestr, "block"); break; default: sprintf(typestr, "unknown 0x%x", inv->type); break; } fprintf(plog, "net: %s inv %s %s\n", conn->addr_str, typestr, hexstr); } else if (debugging && mv.invs) { fprintf(plog, "net: %s inv (%zu sz)\n", conn->addr_str, mv.invs->len); } if (!mv.invs || !mv.invs->len) goto out_ok; /* scan incoming inv's for interesting material */ /*declared at beginnning of function--> unsigned int i;*/ for (i = 0; i < mv.invs->len; i++) { struct bp_inv *inv = parr_idx(mv.invs, i); switch (inv->type) { case MSG_BLOCK: if (!blkdb_lookup(&db, &inv->hash) && !have_orphan(&inv->hash)) msg_vinv_push(&mv_out, MSG_BLOCK, &inv->hash); break; case MSG_TX: default: break; } } /* send getdata, if they have anything we want */ if (mv_out.invs && mv_out.invs->len) { cstring *s = ser_msg_vinv(&mv_out); rc = nc_conn_send(conn, "getdata", s->str, s->len); cstr_free(s, true); } out_ok: rc = true; out: msg_vinv_free(&mv); msg_vinv_free(&mv_out); return rc; }