Exemple #1
0
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;
}
Exemple #2
0
/*  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);
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}
Exemple #5
0
/*
 *
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;
}