// 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; }
int p2psecConnect(P2PSEC_CTX *p2psec, const unsigned char *destination_addr) { struct s_peeraddr addr; memcpy(addr.addr, destination_addr, peeraddr_SIZE); return peermgtConnect(&p2psec->mgt, &addr); }