Exemplo n.º 1
0
// Returns a NodeDB ID that matches the specified criteria, with explicit nid/tnow.
static int nodedbGetDBIDByID(struct s_nodedb *db, const int nid, const int tnow, const int max_lastseen, const int max_lastconnect, const int min_lastconntry) {
	int j, j_max, aid, ret;
	struct s_nodedb_addrdata *dbdata;
	struct s_map *addrset;
	addrset = mapGetValueByID(db->addrdb, nid);
	j_max = mapGetKeyCount(addrset);
	for(j=0; j<j_max; j++) {
		aid = mapGetNextKeyID(addrset);
		dbdata = mapGetValueByID(addrset, aid);
		if(dbdata != NULL) {
			if(
				( (max_lastseen < 0) || (
					(dbdata->lastseen > 0) &&
					((tnow - dbdata->lastseen_t) < max_lastseen) &&
				1)) &&
				( (max_lastconnect < 0) || (
					(dbdata->lastconnect > 0) &&
					((tnow - dbdata->lastconnect_t) < max_lastconnect) &&
				1)) &&
				( (min_lastconntry < 0) || (!(dbdata->lastconntry > 0)) || (
					(dbdata->lastseen > 0) &&
					((tnow - dbdata->lastconntry_t) >= min_lastconntry) &&
					((tnow - dbdata->lastconntry_t) >= ((tnow - dbdata->lastseen_t) / 2)) &&
				1)) &&
			1) {
				ret = (nid * db->num_peeraddrs) + aid;
				return ret;
			}
		}
	}
	return -1;
}
Exemplo n.º 2
0
// Returns a NodeDB ID that matches the specified criteria.
static int nodedbGetDBID(struct s_nodedb *db, struct s_nodeid *nodeid, const int max_lastseen, const int max_lastconnect, const int min_lastconntry) {
	int i, i_max, nid, tnow, ret;
	tnow = utilGetClock();
	i_max = mapGetKeyCount(db->addrdb);
	ret = -1;
	if(nodeid == NULL) { // find DBID for any NodeID
		i = 0;
		while((i < i_max) && (ret < 0)) {
			nid = mapGetNextKeyID(db->addrdb);
			ret = nodedbGetDBIDByID(db, nid, tnow, max_lastseen, max_lastconnect, min_lastconntry);
			i++;
		}
	}
	else { // find DBID for specified NodeID
		nid = mapGetKeyID(db->addrdb, nodeid->id);
		if(!(nid < 0)) {
			ret = nodedbGetDBIDByID(db, nid, tnow, max_lastseen, max_lastconnect, min_lastconntry);
		}
	}
	return ret;
}
Exemplo n.º 3
0
// Generate peerinfo packet.
static void peermgtGenPacketPeerinfo(struct s_packet_data *data, struct s_peermgt *mgt) {
	const int peerinfo_size = (packet_PEERID_SIZE + nodeid_SIZE + peeraddr_SIZE);
	int peerinfo_max = mapGetKeyCount(&mgt->map);
	int peerinfo_count;
	int peerinfo_limit;
	int pos = 4;
	int i = 0;
	int infoid;
	unsigned char infocid[packet_PEERID_SIZE];
	struct s_nodeid infonid;

	// randomize maximum length of peerinfo packet
	if((abs(cryptoRandInt()) % 2) == 1) { peerinfo_limit = 7; } else { peerinfo_limit = 5; }

	// generate peerinfo entries
	peerinfo_count = 0;
	while((i < peerinfo_max) && (peerinfo_count < peerinfo_limit) && (pos + peerinfo_size < data->pl_buf_size)) {
		infoid = peermgtGetNextID(mgt);
		if((infoid > 0) && (mgt->data[infoid].state == peermgt_STATE_COMPLETE) && (!peeraddrIsInternal(&mgt->data[infoid].remoteaddr))) {
			utilWriteInt32(infocid, infoid);
			memcpy(&data->pl_buf[pos], infocid, packet_PEERID_SIZE);
			peermgtGetNodeID(mgt, &infonid, infoid);
			memcpy(&data->pl_buf[(pos + packet_PEERID_SIZE)], infonid.id, nodeid_SIZE);
			memcpy(&data->pl_buf[(pos + packet_PEERID_SIZE + nodeid_SIZE)], &mgt->data[infoid].remoteaddr.addr, peeraddr_SIZE);
			pos = pos + peerinfo_size;
			peerinfo_count++;
		}
		i++;
	}

	// write peerinfo_count
	utilWriteInt32(data->pl_buf, peerinfo_count);

	// set packet metadata
	data->pl_length = (4 + (peerinfo_count * peerinfo_size));
	data->pl_type = packet_PLTYPE_PEERINFO;
	data->pl_options = 0;
}
Exemplo n.º 4
0
static int mapTestsuiteGenerateASCIIString(struct s_map *map, char *str, const int strlen) {
	int size = strlen - 5;
	char c; int i; int j; int k; int l; int m; int n; int o; int p; int h; int x;
	int q = 8192;
	int *nidarray = NULL;
	int cpos = 0;
	if(mapGetKeyCount(map) > 0) {
		nidarray = malloc(q * sizeof(int));
		for(i=0; i<q; i++) nidarray[i]=-1;
		if(nidarray == NULL) return 0;
		h = mapTestsuiteGenerateASCIIStringRecursive(map, nidarray, map->rootid, 0, 0);
		j = 0;
		l = 0;		
		while(j < h) {
			k = 1 << (h-j);
			if(l) {
				m = k >> 1;
				o = 1;
				while(o < m) {
					i = 1 << j;
					x = 0;
					q = nidarray[mapTestsuiteGenerateASCIIStringCalcXY(x,j)];
					n = 0;
					p = 0;
					c = '\0';
					for(;;) {
						c = ' ';
						if(((n + o) % k == 0)) { c = '/'; p = !p; }
						if(((n - o) % k == 0) && (n > o)) c = '\\';
						if(p && (!(q < 0))) str[cpos] = c; else str[cpos] = ' ';
						cpos++; if(!(cpos < size)) return 0;
						if((c == '\\') & p) { x++; q = nidarray[mapTestsuiteGenerateASCIIStringCalcXY(x,j)]; }
						if(!(x < i)) break;
						n++;
					}
					str[cpos] = '\n';
					cpos++; if(!(cpos < size)) return 0;
					o++;
				}
			}
			else {
				x = 0;
				i = 1 << j;
				n = k >> 1;
				while(x < i) {
					while(n < k) {
						snprintf(&str[cpos], 3, "  ");
						cpos = cpos + 2; if(!(cpos < size)) return 0;
						n++;
					}
					n = nidarray[mapTestsuiteGenerateASCIIStringCalcXY(x,j)];
					if(n < 0) {
						snprintf(&str[cpos], 3, "  ");
					}
					else {
						snprintf(&str[cpos-2], 5, "%4d", n);
					}
					cpos = cpos + 2; if(!(cpos < size)) return 0;
					n = 1;
					x++;
				}
				str[cpos] = '\n';
				cpos++; if(!(cpos < size)) return 0;
			}
			if(l) j++;
			l = !l;
		}
Exemplo n.º 5
0
// Generate NodeDB status report.
static void nodedbStatus(struct s_nodedb *db, char *report, const int report_len) {
	int i;
	int j;
	int size;
	int rpsize;
	int pos;
	int tnow;
	unsigned char timediff[4];
	struct s_map *addrset;
	struct s_nodedb_addrdata *addrdata;

	tnow = utilGetClock();
	size = mapGetKeyCount(db->addrdb);
	rpsize = (95 * (1 + db->num_peeraddrs)) + 2;

	pos = 0;
	memcpy(&report[pos], "NodeID + Address                                                  LastSeen  LastConn  LastTry ", 94);
	pos = pos + 94;
	report[pos++] = '\n';

	i = 0;
	while(i < size && pos < (report_len - rpsize)) {
		if(mapIsValidID(db->addrdb, i)) {
			utilByteArrayToHexstring(&report[pos], ((nodeid_SIZE * 2) + 2), mapGetKeyByID(db->addrdb, i), nodeid_SIZE);
			pos = pos + (nodeid_SIZE * 2);
			addrset = mapGetValueByID(db->addrdb, i);
			memcpy(&report[pos], "                              ", 30);
			pos = pos + 30;
			j = 0;
			while(j < db->num_peeraddrs) {
				if(mapIsValidID(addrset, j)) {
					addrdata = mapGetValueByID(addrset, j);
					report[pos++] = '\n';
					memcpy(&report[pos], "            ", 12);
					pos = pos + 12;
					report[pos++] = '-';
					report[pos++] = '-';
					report[pos++] = '>';
					report[pos++] = ' ';
					utilByteArrayToHexstring(&report[pos], ((peeraddr_SIZE * 2) + 2), mapGetKeyByID(addrset, j), peeraddr_SIZE);
					pos = pos + (peeraddr_SIZE * 2);
					report[pos++] = ' ';
					report[pos++] = ' ';
					if(addrdata->lastseen) {
						utilWriteInt32(timediff, (tnow - addrdata->lastseen_t));
						utilByteArrayToHexstring(&report[pos], 10, timediff, 4);
					}
					else {
						memcpy(&report[pos], "--------", 8);
					}
					pos = pos + 8;
					report[pos++] = ' ';
					report[pos++] = ' ';
					if(addrdata->lastconnect) {
						utilWriteInt32(timediff, (tnow - addrdata->lastconnect_t));
						utilByteArrayToHexstring(&report[pos], 10, timediff, 4);
					}
					else {
						memcpy(&report[pos], "--------", 8);
					}
					pos = pos + 8;
					report[pos++] = ' ';
					report[pos++] = ' ';
					if(addrdata->lastconntry) {
						utilWriteInt32(timediff, (tnow - addrdata->lastconntry_t));
						utilByteArrayToHexstring(&report[pos], 10, timediff, 4);
					}
					else {
						memcpy(&report[pos], "--------", 8);
					}
					pos = pos + 8;
				}
				j++;
			}
			report[pos++] = '\n';
		}
		i++;
	}
	report[pos++] = '\0';
}
Exemplo n.º 6
0
// Generate next peer manager packet. Returns length if successful.
static int peermgtGetNextPacketGen(struct s_peermgt *mgt, unsigned char *pbuf, const int pbuf_size, const int tnow, struct s_peeraddr *target) {
	int used = mapGetKeyCount(&mgt->map);
	int len;
	int outlen;
	int fragoutlen;
	int peerid;
	int relayid;
	int usetargetaddr;
	int i;
	int fragcount;
	int fragpos;
	const int plbuf_size = peermgt_MSGSIZE_MIN;
	unsigned char plbuf[plbuf_size];
	struct s_msg authmsg;
	struct s_packet_data data;
	
	// send out user data
	outlen = mgt->outmsg.len;
	fragoutlen = mgt->fragoutsize;
	if(outlen > 0 && (!(fragoutlen > 0))) {
		if(mgt->outmsgbroadcast) { // get PeerID for broadcast message
			do {
				peerid = peermgtGetNextID(mgt);
				mgt->outmsgbroadcastcount++;
			}
			while((!(peermgtIsActiveRemoteID(mgt, peerid) && peermgtGetRemoteFlag(mgt, peerid, peermgt_FLAG_USERDATA))) && (mgt->outmsgbroadcastcount < used));
			if(mgt->outmsgbroadcastcount >= used) {
				mgt->outmsgbroadcast = 0;
				mgt->outmsg.len = 0;
			}
		}
		else { // get PeerID for unicast message
			peerid = mgt->outmsgpeerid;
			mgt->outmsg.len = 0;
		}
		if(peermgtIsActiveRemoteID(mgt, peerid)) {  // check if session is active
			if(peermgtGetRemoteFlag(mgt, peerid, peermgt_FLAG_USERDATA)) {
				if((mgt->fragmentation > 0) && (outlen > peermgt_MSGSIZE_MIN)) {
					// start generating fragmented userdata packets
					mgt->fragoutpeerid = peerid;
					mgt->fragoutcount = (((outlen - 1) / peermgt_MSGSIZE_MIN) + 1); // calculate number of fragments
					mgt->fragoutsize = outlen;
					fragoutlen = outlen;
					mgt->fragoutpos = 0;
				}
				else {
					// generate userdata packet
					data.pl_buf = mgt->outmsg.msg;
					data.pl_buf_size = outlen;
					data.peerid = mgt->data[peerid].remoteid;
					data.seq = ++mgt->data[peerid].remoteseq;
					data.pl_length = outlen;
					data.pl_type = packet_PLTYPE_USERDATA;
					data.pl_options = 0;
					len = packetEncode(pbuf, pbuf_size, &data, &mgt->ctx[peerid]);
					if(len > 0) {
						mgt->data[peerid].lastsend = tnow;
						*target = mgt->data[peerid].remoteaddr;
						return len;
					}
				}
			}
		}
	}

	// send out fragments
	if(fragoutlen > 0) {
		fragcount = mgt->fragoutcount;
		fragpos = mgt->fragoutpos;
		peerid = mgt->fragoutpeerid;
		if(peermgtIsActiveRemoteID(mgt, peerid)) {  // check if session is active
			// generate fragmented packet
			data.pl_buf = &mgt->outmsg.msg[(fragpos * peermgt_MSGSIZE_MIN)];
			if(fragoutlen > peermgt_MSGSIZE_MIN) {
				// start or middle fragment
				data.pl_buf_size = peermgt_MSGSIZE_MIN;
				data.pl_length = peermgt_MSGSIZE_MIN;
				mgt->fragoutsize = (fragoutlen - peermgt_MSGSIZE_MIN);
			}
			else {
				// end fragment
				data.pl_buf_size = fragoutlen;
				data.pl_length = fragoutlen;
				mgt->fragoutsize = 0;
			}
			data.peerid = mgt->data[peerid].remoteid;
			data.seq = ++mgt->data[peerid].remoteseq;
			data.pl_type = packet_PLTYPE_USERDATA_FRAGMENT;
			data.pl_options = (fragcount << 4) | (fragpos);
			len = packetEncode(pbuf, pbuf_size, &data, &mgt->ctx[peerid]);
			mgt->fragoutpos = (fragpos + 1);
			if(len > 0) {
				mgt->data[peerid].lastsend = tnow;
				*target = mgt->data[peerid].remoteaddr;
				return len;
			}
		}
		else {
			// session not active anymore, abort sending fragments
			mgt->fragoutsize = 0;
		}
	}

	// send out request-response packet
	outlen = mgt->rrmsg.len;
	if(outlen > 0) {
		peerid = mgt->rrmsgpeerid;
		usetargetaddr = mgt->rrmsgusetargetaddr;
		mgt->rrmsg.len = 0;
		mgt->rrmsgusetargetaddr = 0;
		if((outlen < peermgt_MSGSIZE_MAX) && (peermgtIsActiveRemoteID(mgt, peerid))) {  // check if session is active
			data.pl_buf = mgt->rrmsg.msg;
			data.pl_buf_size = peermgt_MSGSIZE_MAX;
			data.pl_length = outlen;
			data.pl_type = mgt->rrmsgtype;
			data.pl_options = 0;
			data.peerid = mgt->data[peerid].remoteid;
			data.seq = ++mgt->data[peerid].remoteseq;

			len = packetEncode(pbuf, pbuf_size, &data, &mgt->ctx[peerid]);
			if(len > 0) {
				if(usetargetaddr > 0) {
					*target = mgt->rrmsgtargetaddr;
				}
				else {
					mgt->data[peerid].lastsend = tnow;
					*target = mgt->data[peerid].remoteaddr;
				}
				return len;
			}
		}
	}

	// send peerinfo to peers
	for(i=0; i<used; i++) {
		peerid = peermgtGetNextID(mgt);
		if(peerid > 0) {
			if((tnow - mgt->data[peerid].lastrecv) < peermgt_RECV_TIMEOUT) { // check if session has expired
				if(mgt->data[peerid].state == peermgt_STATE_COMPLETE) {  // check if session is active
					if(((tnow - mgt->data[peerid].lastsend) > peermgt_KEEPALIVE_INTERVAL) || ((tnow - mgt->data[peerid].lastpeerinfo) > peermgt_PEERINFO_INTERVAL)) { // check if we should send peerinfo packet
						data.pl_buf = plbuf;
						data.pl_buf_size = plbuf_size;
						data.peerid = mgt->data[peerid].remoteid;
						data.seq = ++mgt->data[peerid].remoteseq;
						peermgtGenPacketPeerinfo(&data, mgt);
						len = packetEncode(pbuf, pbuf_size, &data, &mgt->ctx[peerid]);
						if(len > 0) {
							mgt->data[peerid].lastsend = tnow;
							mgt->data[peerid].lastpeerinfo = tnow;
							*target = mgt->data[peerid].remoteaddr;
							return len;
						}
					}
				}
			}
			else {
				peermgtDeleteID(mgt, peerid);
			}
		}
	}
	
	// send auth manager message
	if(authmgtGetNextMsg(&mgt->authmgt, &authmsg, target)) {
		data.pl_buf = authmsg.msg;
		data.pl_buf_size = authmsg.len;
		data.peerid = 0;
		data.seq = 0;
		data.pl_length = authmsg.len;
		if(data.pl_length > 0) {
			data.pl_type = packet_PLTYPE_AUTH;
			data.pl_options = 0;
			len = packetEncode(pbuf, pbuf_size, &data, &mgt->ctx[0]);
			if(len > 0) {
				mgt->data[0].lastsend = tnow;
				return len;
			}
		}
	}
	
	// connect new peer
	if((authmgtUsedSlotCount(&mgt->authmgt) < ((authmgtSlotCount(&mgt->authmgt) / 4) * 3)) && ((tnow - mgt->lastconnect) > peermgt_NEWCONNECT_INTERVAL)) {
		i = nodedbNextID(&mgt->nodedb, peermgt_NEWCONNECT_MAX_AGE, 0, 1);
		if(!(i < 0)) {
			peerid = peermgtGetID(mgt, nodedbGetNodeID(&mgt->nodedb, i));
			if(peerid < 0) { // check if node is already connected
				// node is not connected yet
				if(peermgtConnect(mgt, nodedbGetNodeAddress(&mgt->nodedb, i))) { // try to connect
					if(peermgtConnect(mgt, nodedbGetIndirectNodeAddress(&mgt->nodedb, i))) { // try to connect via relay
						relayid = 0; // on success, dont change indirect entry in NodeDB
					}
					else {
						relayid = -1; // on failure, delete indirect entry in NodeDB
					}
					nodedbUpdate(&mgt->nodedb, nodedbGetNodeID(&mgt->nodedb, i), NULL, 0, 0, 1, relayid, 0, 0);
					mgt->lastconnect = tnow;
				}
			}
			else {
				// node is already connected
				if(peeraddrIsInternal(&mgt->data[peerid].remoteaddr)) {
					peermgtSendPingToAddr(mgt, NULL, peerid, mgt->data[peerid].conntime, nodedbGetNodeAddress(&mgt->nodedb, i)); // try to switch peer to a direct connection
					nodedbUpdate(&mgt->nodedb, nodedbGetNodeID(&mgt->nodedb, i), NULL, 0, 0, 1, 0, 0, 0);
					mgt->lastconnect = tnow;
				}
			}
		}
	}
	
	return 0;
}