/* format a string into an ei_x_buff, except the version token */ static int eiformat(const char** fmt, union arg** args, ei_x_buff* x) { const char* p = *fmt; int res; ei_x_buff x2; while (isspace((int)*p)) ++p; switch (*p) { case '~': res = pformat(&p, args, x); break; case '[': res = ei_x_new(&x2); if (res >= 0) res = plist(&p, args, &x2, 0); if (res > 0) res = ei_x_encode_list_header(x, res); if (res >= 0) res = ei_x_append(x, &x2); ei_x_free(&x2); break; case '{': res = ei_x_new(&x2); if (res >= 0) res = ptuple(&p, args, &x2, 0); if (res >= 0) res = ei_x_encode_tuple_header(x, res); if (res >= 0) res = ei_x_append(x, &x2); ei_x_free(&x2); break; case '"': res = pstring(&p, x); break; case '\'': res = pquotedatom(&p, x); break; default: if (isdigit((int)*p)) res = pdigit(&p, x); else if ((*p == '-' || *p == '+') && isdigit((int)*(p+1))) res = pdigit(&p, x); else if (islower((int)*p)) res = patom(&p, x); else res = -1; break; /* Variables */ } *fmt = p; return res; }
// ------------------------------------------ int PCPStream::readBroadcastAtoms(AtomStream &atom, int numc, BroadcastState &bcs) { ChanPacket pack; //int ttl=0; int ver = 0; int ver_vp = 0; GnuID fromID, destID; int r = 0; char ver_ex_prefix[2]; int ver_ex_number = 0; fromID.clear(); destID.clear(); bcs.initPacketSettings(); MemoryStream pmem(pack.data, sizeof(pack.data)); AtomStream patom(pmem); patom.writeParent(PCP_BCST, numc); for (int i = 0; i < numc; i++) { int c, d; ID4 id = atom.read(c, d); if (id == PCP_BCST_TTL) { bcs.ttl = atom.readChar() - 1; patom.writeChar(id, bcs.ttl); } else if (id == PCP_BCST_HOPS) { bcs.numHops = atom.readChar() + 1; patom.writeChar(id, bcs.numHops); } else if (id == PCP_BCST_FROM) { atom.readBytes(fromID.id, 16); patom.writeBytes(id, fromID.id, 16); routeList.add(fromID); } else if (id == PCP_BCST_GROUP) { bcs.group = atom.readChar(); patom.writeChar(id, bcs.group); } else if (id == PCP_BCST_DEST) { atom.readBytes(destID.id, 16); patom.writeBytes(id, destID.id, 16); bcs.forMe = destID.isSame(servMgr->sessionID); char idstr1[64]; char idstr2[64]; destID.toStr(idstr1); servMgr->sessionID.toStr(idstr2); } else if (id == PCP_BCST_CHANID) { atom.readBytes(bcs.chanID.id, 16); patom.writeBytes(id, bcs.chanID.id, 16); } else if (id == PCP_BCST_VERSION) { ver = atom.readInt(); patom.writeInt(id, ver); } else if (id == PCP_BCST_VERSION_VP) { ver_vp = atom.readInt(); patom.writeInt(id, ver_vp); } else if (id == PCP_BCST_VERSION_EX_PREFIX) { atom.readBytes(ver_ex_prefix, 2); patom.writeBytes(id, ver_ex_prefix, 2); } else if (id == PCP_BCST_VERSION_EX_NUMBER) { ver_ex_number = atom.readShort(); patom.writeShort(id, ver_ex_number); } else if (id == PCP_HOST) { ChanHit hit; readHostAtoms(atom, c, bcs, hit, false); Servent *sv = servMgr->findServentByServentID(bcs.servent_id); if (hit.uphost.ip == 0) { // LOG_DEBUG("bcs servent_id = %d", bcs.servent_id); if (bcs.numHops == 1) { hit.uphost.ip = servMgr->serverHost.ip; hit.uphost.port = servMgr->serverHost.port; hit.uphostHops = 1; } else { //Servent *sv = servMgr->findServentByServentID(bcs.servent_id); if (sv) { hit.uphost.ip = sv->getHost().ip; hit.uphost.port = sv->waitPort; hit.uphostHops = bcs.numHops - 1; } } } if (sv && ((hit.numHops == 1 && (hit.rhost[0].ip == sv->getHost().ip && hit.uphost.ip == servMgr->serverHost.ip && hit.uphost.port == servMgr->serverHost.port) || (hit.rhost[1].localIP() && hit.rhost[1].ip == sv->getHost().ip)) || (hit.numHops != 1 && chanMgr->findParentHit(hit)))) { int oldPos = pmem.pos; hit.writeAtoms(patom, hit.chanID); pmem.pos = oldPos; r = readAtom(patom, bcs); } else { char tmp[80], tmp2[80], tmp3[80]; memset(tmp, 0, 80); memset(tmp2, 0, 80); memset(tmp3, 0, 80); hit.uphost.toStr(tmp); hit.host.toStr(tmp2); if (sv) sv->getHost().toStr(tmp3); LOG_DEBUG("### Invalid bcst: hops=%d, l/r = %d/%d, ver=%d(VP%04d), ttl=%d", bcs.numHops, hit.numListeners, hit.numRelays, ver, ver_vp, bcs.ttl); LOG_DEBUG("### %s <- %s <- sv(%s)", tmp2, tmp, tmp3); bcs.ttl = 0; } } else { // copy and process atoms int oldPos = pmem.pos; patom.writeAtoms(id, atom.io, c, d); pmem.pos = oldPos; r = readAtom(patom, bcs); } } char fromStr[64]; fromStr[0] = 0; if (fromID.isSet()) fromID.toStr(fromStr); char destStr[64]; destStr[0] = 0; if (destID.isSet()) destID.toStr(destStr); char tmp[64]; bcs.chanID.toStr(tmp); // Broadcast flood if (servMgr->lastPCPFromID.isSame(fromID) && time(NULL) - servMgr->lastPCPBcstTime < 3) { memcpy(servMgr->lastPCPFromID.id, fromID.id, 16); servMgr->lastPCPBcstTime = time(NULL); LOG_DEBUG("PCP bcst reject: group=%d, hops=%d, ver=%d(%c%c%04d), from=%s, dest=%s ttl=%d", bcs.group, bcs.numHops, ver, ver_ex_prefix[0], ver_ex_prefix[1], ver_ex_number, fromStr, destStr, bcs.ttl); return r; } memcpy(servMgr->lastPCPFromID.id, fromID.id, 16); servMgr->lastPCPBcstTime = time(NULL); // LOG_DEBUG(tmp); if (ver_ex_number) { LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(%c%c%04d), from=%s, dest=%s ttl=%d", bcs.group, bcs.numHops, ver, ver_ex_prefix[0], ver_ex_prefix[1], ver_ex_number, fromStr, destStr, bcs.ttl); } else if (ver_vp) { LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(VP%04d), from=%s, dest=%s ttl=%d", bcs.group, bcs.numHops, ver, ver_vp, fromStr, destStr, bcs.ttl); } else { LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d, from=%s, dest=%s ttl=%d", bcs.group, bcs.numHops, ver, fromStr, destStr, bcs.ttl); } if (fromID.isSet()) if (fromID.isSame(servMgr->sessionID)) { LOG_ERROR("BCST loopback"); return PCP_ERROR_BCST + PCP_ERROR_LOOPBACK; } // broadcast back out if ttl > 0 if ((bcs.ttl > 0) && (!bcs.forMe)) { pack.len = pmem.pos; pack.type = ChanPacket::T_PCP; if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS | PCP_BCST_GROUP_RELAYS)) { pack.priority = 11 - bcs.numHops; chanMgr->broadcastPacketUp(pack, bcs.chanID, remoteID, destID); } if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS | PCP_BCST_GROUP_RELAYS)) { servMgr->broadcastPacket(pack, bcs.chanID, remoteID, destID, Servent::T_COUT); } if (bcs.group & (PCP_BCST_GROUP_RELAYS | PCP_BCST_GROUP_TRACKERS)) { servMgr->broadcastPacket(pack, bcs.chanID, remoteID, destID, Servent::T_CIN); } if (bcs.group & (PCP_BCST_GROUP_RELAYS)) { servMgr->broadcastPacket(pack, bcs.chanID, remoteID, destID, Servent::T_RELAY); } // LOG_DEBUG("ttl=%d",ttl); } else { // LOG_DEBUG("ttl=%d",ttl); } return r; }
// ------------------------------------------ int PCPStream::readPacket(Stream & in, BroadcastState & bcs) { int error = PCP_ERROR_GENERAL; try { AtomStream atom(in); ChanPacket pack; MemoryStream mem(pack.data, sizeof(pack.data)); AtomStream patom(mem); // send outward packets error = PCP_ERROR_WRITE; if (outData.numPending()) { outData.readPacket(pack); pack.writeRaw(in); } error = PCP_ERROR_GENERAL; if (outData.willSkip()) { error = PCP_ERROR_WRITE + PCP_ERROR_SKIP; throw StreamException("Send too slow"); } error = PCP_ERROR_READ; // poll for new downward packet if (in.readReady()) { int numc, numd; ID4 id; id = atom.read(numc, numd); mem.rewind(); pack.len = patom.writeAtoms(id, in, numc, numd); pack.type = ChanPacket::T_PCP; //inData.writePacket(pack); //} error = PCP_ERROR_GENERAL; // process downward packets //if (inData.numPending()) //{ //inData.readPacket(pack); mem.rewind(); //int numc,numd; id = patom.read(numc, numd); error = PCPStream::procAtom(patom, id, numc, numd, bcs); if (error) { throw StreamException("PCP exception"); } } error = 0; } catch (StreamException &e) { LOG_ERROR("PCP readPacket: %s (%d)", e.msg, error); } return error; }