UInt32 RTMFP::Unpack(PacketReader& packet) { packet.reset(); UInt32 id=0; for(int i=0;i<3;++i) id ^= packet.read32(); packet.reset(4); return id; }
bool WSSession::buildPacket(PacketReader& packet) { if (packet.available()<2) return false; UInt8 type = packet.read8() & 0x0F; UInt8 lengthByte = packet.read8(); UInt32 size=lengthByte&0x7f; if (size==127) { if (packet.available()<8) return false; size = (UInt32)packet.read64(); } else if (size==126) { if (packet.available()<2) return false; size = packet.read16(); } if(lengthByte&0x80) size += 4; if (packet.available()<size) return false; packet.shrink(size); if (lengthByte & 0x80) { shared_ptr<WSUnmasking> pWSUnmasking(new WSUnmasking(invoker, packet.current(),packet.available(), type)); decode<WSUnmasking>(pWSUnmasking); } else { packet.reset(packet.position()-1); *(UInt8*)packet.current() = type; } return true; }
void Publication::pushRawPacket(UInt8 type,PacketReader& packet) { list<Listener*>::const_iterator it; int pos = packet.position(); for(it=_listeners.begin();it!=_listeners.end();++it) { (*it)->pushRawPacket(type,packet); packet.reset(pos); } }
void Publication::pushVideoPacket(PacketReader& packet) { UInt32 time = packet.read32(); // TODO? list<Listener*>::const_iterator it; int pos = packet.position(); for(it=_listeners.begin();it!=_listeners.end();++it) { (*it)->pushVideoPacket(packet); packet.reset(pos); } }
bool RTMFP::Decode(AESEngine& aesDecrypt,PacketReader& packet) { // Decrypt aesDecrypt.process(packet.current(),packet.current(),packet.available()); // Check the first 2 CRC bytes packet.reset(4); UInt16 sum = packet.read16(); return (sum == CheckSum(packet)); }
void ServerConnection::packetHandler(PacketReader& packet) { UInt8 marker = packet.read8(); if(marker!=0x0b) { ERROR("ServerConnection with an unknown %u marker, it should be 0x0b",marker); return; } packet.next(2); UInt8 id = packet.read8(); switch(id) { case 0x71: { packet.next(2); string tag; packet.readString8(tag); map<string,P2PHandshakerAddress>::iterator it = _p2pHandshakers.find(tag); if(it==_p2pHandshakers.end()) { ERROR("Unknown ServerConnection tag %s on P2P handshake",tag.c_str()); break; } (SocketAddress&)_handshake.peer.address = it->second; packet.reset(0); PacketWriter writer(packet.current(),packet.available()+16); // +16 for futur 0xFFFF padding writer.clear(packet.available()); _handshake.send(writer); _p2pHandshakers.erase(it); break; } case 0x40: { if(!_connected) { // Edge hello response _connected=true; return; } // Edge keepalive PacketWriter& packet(writer()); packet.write8(0x41); packet.write16(0); flush(); INFO("Keepalive RTMFP server"); break; } case 0x45: { // Server is death! (bool&)died=true; break; } default: ERROR("Unkown ServerConnection packet id %u",id); } }
void Listener::pushDataPacket(const string& name,PacketReader& packet) { // TODO create _dataWriter ?? if(_unbuffered) { UInt16 offset = name.size()+9; if(packet.position()>=offset) { packet.reset(packet.position()-offset); _writer.writeUnbufferedMessage(packet.current(),packet.available()); return; } WARN("Written unbuffered impossible, it requires %u head bytes available on PacketReader given",offset); } StreamCopier::copyStream(packet.stream(),_writer.writeAMFPacket(name).writer.stream()); }
void write(UInt32 time,PacketReader& data,bool unbuffered) { // if(_type==0x08) // time=0; /* if(_type==0x09) TRACE("Video timestamp : %u",_time) else TRACE("Audio timestamp : %u",_time);*/ if(unbuffered) { if(data.position()>=5) { data.reset(data.position()-5); PacketWriter writer(data.current(),5); writer.write8(_type); writer.write32(time); writeUnbufferedMessage(data.current(),data.available(),data.current(),5); return; } WARN("Written unbuffered impossible, it requires 5 head bytes available on PacketReader given"); } BinaryWriter& out = writeRawMessage(true); out.write8(_type); out.write32(time); StreamCopier::copyStream(data.stream(),out.stream()); }
void RTMFPWriter::acknowledgment(PacketReader& packet) { UInt64 bufferSize = packet.read7BitLongValue(); // TODO use this value in reliability mechanism? if(bufferSize==0) { // In fact here, we should send a 0x18 message (with id flow), // but it can create a loop... We prefer the following behavior fail("Negative acknowledgment"); return; } UInt64 stageAckPrec = _stageAck; UInt64 stageReaden = packet.read7BitLongValue(); UInt64 stage = _stageAck+1; if(stageReaden>_stage) { ERROR("Acknowledgment received ",stageReaden," superior than the current sending stage ",_stage," on writer ",id); _stageAck = _stage; } else if(stageReaden<=_stageAck) { // already acked if(packet.available()==0) DEBUG("Acknowledgment ",stageReaden," obsolete on writer ",id); } else _stageAck = stageReaden; UInt64 maxStageRecv = stageReaden; UInt32 pos=packet.position(); while(packet.available()>0) maxStageRecv += packet.read7BitLongValue()+packet.read7BitLongValue()+2; if(pos != packet.position()) { // TRACE(stageReaden,"..x"Util::FormatHex(reader.current(),reader.available())); packet.reset(pos); } UInt64 lostCount = 0; UInt64 lostStage = 0; bool repeated = false; bool header = true; bool stop=false; auto it=_messagesSent.begin(); while(!stop && it!=_messagesSent.end()) { RTMFPMessage& message(**it); if(message.fragments.empty()) { CRITIC("RTMFPMessage ",(stage+1)," is bad formatted on fowWriter ",id); ++it; continue; } map<UInt32,UInt64>::iterator itFrag=message.fragments.begin(); while(message.fragments.end()!=itFrag) { // ACK if(_stageAck>=stage) { message.fragments.erase(message.fragments.begin()); itFrag=message.fragments.begin(); ++_ackCount; ++stage; continue; } // Read lost informations while(!stop) { if(lostCount==0) { if(packet.available()>0) { lostCount = packet.read7BitLongValue()+1; lostStage = stageReaden+1; stageReaden = lostStage+lostCount+packet.read7BitLongValue(); } else { stop=true; break; } } // check the range if(lostStage>_stage) { // Not yet sent ERROR("Lost information received ",lostStage," have not been yet sent on writer ",id); stop=true; } else if(lostStage<=_stageAck) { // already acked --lostCount; ++lostStage; continue; } break; } if(stop) break; // lostStage > 0 and lostCount > 0 if(lostStage!=stage) { if(repeated) { ++stage; ++itFrag; header=true; } else // No repeated, it means that past lost packet was not repeatable, we can ack this intermediate received sequence _stageAck = stage; continue; } /// Repeat message asked! if(!message.repeatable) { if(repeated) { ++itFrag; ++stage; header=true; } else { INFO("RTMFPWriter ",id," : message ",stage," lost"); --_ackCount; ++_lostCount; _stageAck = stage; } --lostCount; ++lostStage; continue; } repeated = true; // Don't repeate before that the receiver receives the itFrag->second sending stage if(itFrag->second >= maxStageRecv) { ++stage; header=true; --lostCount; ++lostStage; ++itFrag; continue; } // Repeat message DEBUG("RTMFPWriter ",id," : stage ",stage," repeated"); UInt32 fragment(itFrag->first); itFrag->second = _stage; // Save actual stage sending to wait that the receiver gets it before to retry UInt32 contentSize = message.size() - fragment; // available ++itFrag; // Compute flags UInt8 flags = 0; if(fragment>0) flags |= MESSAGE_WITH_BEFOREPART; // fragmented if(itFrag!=message.fragments.end()) { flags |= MESSAGE_WITH_AFTERPART; contentSize = itFrag->first - fragment; } UInt32 size = contentSize+4; UInt32 availableToWrite(_band.availableToWrite()); if(!header && size>availableToWrite) { _band.flush(); header=true; } if(header) size+=headerSize(stage); if(size>availableToWrite) _band.flush(); // Write packet size-=3; // type + timestamp removed, before the "writeMessage" flush(_band.writeMessage(header ? 0x10 : 0x11,(UInt16)size) ,stage,flags,header,message,fragment,contentSize); header=false; --lostCount; ++lostStage; ++stage; } if(message.fragments.empty()) { if(message.repeatable) --_repeatable; if(_ackCount || _lostCount) { _qos.add(_lostCount / (_lostCount + _ackCount)); _ackCount=_lostCount=0; } delete *it; it=_messagesSent.erase(it); } else ++it; } if(lostCount>0 && packet.available()>0) ERROR("Some lost information received have not been yet sent on writer ",id); // rest messages repeatable? if(_repeatable==0) _trigger.stop(); else if(_stageAck>stageAckPrec || repeated) _trigger.reset(); }
bool RTMFP::ReadCRC(PacketReader& packet) { // Check the first 2 CRC bytes packet.reset(4); UInt16 sum = packet.read16(); return (sum == CheckSum(packet)); }
void MobHandler::monsterControl(Player *player, PacketReader &packet) { int32_t mobid = packet.get<int32_t>(); Mob *mob = Maps::getMap(player->getMap())->getMob(mobid); if (mob == nullptr || mob->getControlStatus() == Mobs::ControlStatus::ControlNone) { return; } int16_t moveid = packet.get<int16_t>(); bool useskill = packet.getBool(); int8_t skill = packet.get<int8_t>(); uint8_t realskill = 0; uint8_t level = 0; Pos projectiletarget = packet.getPos(); packet.skipBytes(5); // 1 byte of always 0?, 4 bytes of always 1 or always 0? Pos spot = packet.getPos(); MovementHandler::parseMovement(mob, packet); if (useskill && (skill == -1 || skill == 0)) { if (!(mob->hasStatus(StatusEffects::Mob::Freeze) || mob->hasStatus(StatusEffects::Mob::Stun) || mob->hasStatus(StatusEffects::Mob::ShadowWeb))) { uint8_t size = mob->getSkillCount(); bool used = false; if (size) { bool stop = false; uint8_t rand = Randomizer::Instance()->randChar(size - 1); MobSkillInfo *info = MobDataProvider::Instance()->getMobSkill(mob->getMobId(), rand); realskill = info->skillId; level = info->level; MobSkillLevelInfo *mobskill = SkillDataProvider::Instance()->getMobSkill(realskill, level); switch (realskill) { case MobSkills::WeaponAttackUp: case MobSkills::WeaponAttackUpAoe: stop = mob->hasStatus(StatusEffects::Mob::Watk); break; case MobSkills::MagicAttackUp: case MobSkills::MagicAttackUpAoe: stop = mob->hasStatus(StatusEffects::Mob::Matk); break; case MobSkills::WeaponDefenseUp: case MobSkills::WeaponDefenseUpAoe: stop = mob->hasStatus(StatusEffects::Mob::Wdef); break; case MobSkills::MagicDefenseUp: case MobSkills::MagicDefenseUpAoe: stop = mob->hasStatus(StatusEffects::Mob::Mdef); break; case MobSkills::WeaponImmunity: case MobSkills::MagicImmunity: case MobSkills::WeaponDamageReflect: case MobSkills::MagicDamageReflect: stop = mob->hasImmunity(); break; case MobSkills::McSpeedUp: stop = mob->hasStatus(StatusEffects::Mob::Speed); break; case MobSkills::Summon: { int16_t limit = mobskill->limit; if (limit == 5000) // Custom limit based on number of players on map limit = 30 + Maps::getMap(mob->getMapId())->getNumPlayers() * 2; if (mob->getSpawnCount() >= limit) stop = true; break; } } if (!stop) { time_t now = time(0); time_t ls = mob->getLastSkillUse(realskill); if (ls == 0 || ((int32_t)(now - ls) > mobskill->interval)) { mob->setLastSkillUse(realskill, now); int64_t reqhp = mob->getHp() * 100; reqhp /= mob->getMaxHp(); if ((uint8_t)(reqhp) <= mobskill->hp) { if (info->effectAfter == 0) { handleMobSkill(mob, realskill, level, mobskill); } else { new Timer::Timer(bind(&MobHandler::handleMobSkill, mob, realskill, level, mobskill), Timer::Id(Timer::Types::MobSkillTimer, mob->getMobId(), mob->getCounter()), mob->getTimers(), Timer::Time::fromNow(info->effectAfter)); } used = true; } } } } if (!used) { realskill = 0; level = 0; } } } MobsPacket::moveMobResponse(player, mobid, moveid, useskill, mob->getMp(), realskill, level); packet.reset(19); MobsPacket::moveMob(player, mobid, useskill, skill, projectiletarget, packet.getBuffer(), packet.getBufferLength()); }
void InventoryHandler::useCashItem(Player *player, PacketReader &packet) { packet.get<int8_t>(); // Type packet.skipBytes(1); int32_t itemid = packet.get<int32_t>(); if (!player->getInventory()->getItemAmount(itemid)) { // Hacking return; } bool used = false; if (GameLogicUtilities::getItemType(itemid) == Items::Types::WeatherCash) { string message = packet.getString(); if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } if (message.length() <= 35) { Map *map = Maps::getMap(player->getMap()); message = player->getName() + " 's message : " + message; used = map->createWeather(player, false, Items::WeatherTime, itemid, message); } } else if (GameLogicUtilities::getItemType(itemid) == Items::Types::CashPetFood) { // Pet food. Pet *pet = player->getPets()->getSummoned(0); if (pet != nullptr) { if (pet->getFullness() < Stats::MaxFullness) { PetsPacket::showAnimation(player, pet, 1); pet->modifyFullness(Stats::MaxFullness, false); pet->addCloseness(100); // All cash pet food gives 100 closeness. used = true; } } } else { switch (itemid) { case Items::TeleportRock: case Items::TeleportCoke: case Items::VipRock: // Only occurs when you actually try to move somewhere used = handleRockTeleport(player, itemid, packet); break; case Items::FirstJobSpReset: case Items::SecondJobSpReset: case Items::ThirdJobSpReset: case Items::FourthJobSpReset: { int32_t toskill = packet.get<int32_t>(); int32_t fromskill = packet.get<int32_t>(); if (!player->getSkills()->addSkillLevel(fromskill, -1, true)) { // Hacking return; } if (!player->getSkills()->addSkillLevel(toskill, 1, true)) { // Hacking return; } used = true; break; } case Items::ApReset: { int32_t tostat = packet.get<int32_t>(); int32_t fromstat = packet.get<int32_t>(); player->getStats()->addStat(tostat, 1, true); player->getStats()->addStat(fromstat, -1, true); used = true; break; } case Items::Megaphone: { string msg = player->getMedalName() + " : " + packet.getString(); InventoryPacket::showMegaphone(player, msg); used = true; break; } case Items::SuperMegaphone: { string msg = player->getMedalName() + " : " + packet.getString(); bool whisper = packet.getBool(); InventoryPacket::showSuperMegaphone(player, msg, whisper); used = true; break; } case Items::DiabloMessenger: case Items::Cloud9Messenger: case Items::LoveholicMessenger: { string msg = packet.getString(); string msg2 = packet.getString(); string msg3 = packet.getString(); string msg4 = packet.getString(); InventoryPacket::showMessenger(player, msg, msg2, msg3, msg4, packet.getBuffer(), packet.getBufferLength(), itemid); used = true; break; } case Items::ItemMegaphone: { string msg = player->getMedalName() + " : " + packet.getString(); bool whisper = packet.getBool(); Item *item = nullptr; if (packet.getBool()) { int8_t inv = (int8_t) packet.get<int32_t>(); int16_t slot = (int16_t) packet.get<int32_t>(); item = player->getInventory()->getItem(inv, slot); if (item == nullptr) { // Hacking return; } } InventoryPacket::showItemMegaphone(player, msg, whisper, item); used = true; break; } case Items::ArtMegaphone: { int8_t lines = packet.get<int8_t>(); if (lines < 1 || lines > 3) { // Hacking return; } string text[3]; for (int8_t i = 0; i < lines; i++) { text[i] = player->getMedalName() + " : " + packet.getString(); } bool whisper = packet.getBool(); InventoryPacket::showTripleMegaphone(player, lines, text[0], text[1], text[2], whisper); used = true; break; } case Items::PetNameTag: { string name = packet.getString(); PetHandler::changeName(player, name); used = true; break; } case Items::ItemNameTag: { int16_t slot = packet.get<int16_t>(); if (slot != 0) { Item *item = player->getInventory()->getItem(Inventories::EquipInventory, slot); if (item == nullptr) { // Hacking or failure, dunno return; } item->setName(player->getName()); InventoryPacket::addNewItem(player, Inventories::EquipInventory, slot, item, true); used = true; } break; } case Items::ItemLock: case Items::ScissorsOfKarma: { int8_t inventory = (int8_t) packet.get<int32_t>(); int16_t slot = (int16_t) packet.get<int32_t>(); if (slot != 0) { Item *item = player->getInventory()->getItem(inventory, slot); if (item == nullptr || (itemid == Items::ItemLock && item->hasLock()) || item->hasTradeBlock() || (itemid == Items::ScissorsOfKarma && item->hasKarma())) { // Hacking or failure, dunno return; } ItemInfo *info = ItemDataProvider::Instance()->getItemInfo(item->getId()); if (itemid == Items::ScissorsOfKarma && info->karmascissors) { // Hacking return; } switch (itemid) { case Items::ItemLock: item->setLock(true); break; case Items::ScissorsOfKarma: item->setKarma(true); break; } InventoryPacket::addNewItem(player, inventory, slot, item, true); used = true; } break; } case Items::MapleTvMessenger: case Items::Megassenger: { bool hasreceiver = (packet.get<int8_t>() == 3); bool show_whisper = (itemid == Items::Megassenger ? packet.getBool() : false); Player *receiver = PlayerDataProvider::Instance()->getPlayer(packet.getString()); int32_t time = 15; if ((hasreceiver && receiver != nullptr) || (!hasreceiver && receiver == nullptr)) { string msg = packet.getString(); string msg2 = packet.getString(); string msg3 = packet.getString(); string msg4 = packet.getString(); string msg5 = packet.getString(); if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } MapleTvs::Instance()->addMessage(player, receiver, msg, msg2, msg3, msg4, msg5, itemid - (itemid == Items::Megassenger ? 3 : 0), time); if (itemid == Items::Megassenger) { InventoryPacket::showSuperMegaphone(player, player->getMedalName() + " : " + msg + msg2 + msg3 + msg4 + msg5, show_whisper); } used = true; } break; } case Items::MapleTvStarMessenger: case Items::StarMegassenger: { int32_t time = 30; bool show_whisper = (itemid == Items::StarMegassenger ? packet.getBool() : false); string msg = packet.getString(); string msg2 = packet.getString(); string msg3 = packet.getString(); string msg4 = packet.getString(); string msg5 = packet.getString(); if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } MapleTvs::Instance()->addMessage(player, nullptr, msg, msg2, msg3, msg4, msg5, itemid - (itemid == Items::StarMegassenger ? 3 : 0), time); if (itemid == Items::StarMegassenger) { InventoryPacket::showSuperMegaphone(player, player->getMedalName() + " : " + msg + msg2 + msg3 + msg4 + msg5, show_whisper); } used = true; break; } case Items::MapleTvHeartMessenger: case Items::HeartMegassenger: { bool show_whisper = (itemid == Items::HeartMegassenger ? packet.getBool() : false); string name = packet.getString(); Player *receiver = PlayerDataProvider::Instance()->getPlayer(name); int32_t time = 60; if (receiver != nullptr) { string msg = packet.getString(); string msg2 = packet.getString(); string msg3 = packet.getString(); string msg4 = packet.getString(); string msg5 = packet.getString(); if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } MapleTvs::Instance()->addMessage(player, receiver, msg, msg2, msg3, msg4, msg5, itemid - (itemid == Items::HeartMegassenger ? 3 : 0), time); if (itemid == Items::HeartMegassenger) { InventoryPacket::showSuperMegaphone(player, player->getMedalName() + " : " + msg + msg2 + msg3 + msg4 + msg5, show_whisper); } used = true; } break; } case Items::BronzeSackOfMesos: case Items::SilverSackOfMesos: case Items::GoldSackOfMesos: { int32_t mesos = ItemDataProvider::Instance()->getMesoBonus(itemid); if (!player->getInventory()->modifyMesos(mesos)) { InventoryPacket::sendMesobagFailed(player); } else { InventoryPacket::sendMesobagSucceed(player, mesos); used = true; } break; } case Items::Chalkboard: case Items::Chalkboard2: { string msg = packet.getString(); player->setChalkboard(msg); InventoryPacket::sendChalkboardUpdate(player, msg); break; } case Items::FungusScroll: case Items::OinkerDelight: case Items::ZetaNightmare: Inventory::useItem(player, itemid); used = true; break; case Items::ViciousHammer: { int8_t inventory = (int8_t) packet.get<int32_t>(); // How pointless... int16_t slot = (int16_t) packet.get<int32_t>(); Item *f = player->getInventory()->getItem(inventory, slot); if (f == nullptr || f->getHammers() == Items::MaxHammers) { // Hacking, probably return; } f->incHammers(); f->incSlots(); InventoryPacket::sendHammerSlots(player, f->getHammers()); player->getInventory()->setHammerSlot(slot); used = true; break; } case Items::CongratulatorySong: if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } used = Maps::getMap(player->getMap())->playJukebox(player, itemid, 60 * 5); // 5 minutes is enough! break; case Items::KoreanKite: case Items::HeartBalloon: case Items::GraduationBanner: case Items::AdmissionBanner: { string message = packet.getString(); if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } used = Maps::getMap(player->getMap())->createKite(player, itemid, message); if (!used) { InventoryPacket::sendCannotFlyHere(player); } break; } default: { packet.reset(); std::stringstream x; x << "Unknown cash item! ItemID: " << itemid << "; Player ID: " << player->getId() << "; Packet: " << packet; ChannelServer::Instance()->log(LogTypes::Info, x.str()); break; } } } if (used) { Inventory::takeItem(player, itemid, 1); } else { InventoryPacket::blankUpdate(player); } }
UInt8 Handshake::handshakeHandler(UInt8 id,PacketReader& request,PacketWriter& response) { switch(id){ case 0x30: { request.read8(); // passer un caractere (boite dans boite) UInt8 epdLen = request.read8()-1; UInt8 type = request.read8(); string epd; request.readRaw(epdLen,epd); string tag; request.readRaw(16,tag); response.writeString8(tag); if(type == 0x0f) return _gateway.p2pHandshake(tag,response,peer.address,(const UInt8*)epd.c_str()); if(type == 0x0a){ /// Handshake HelloAttempt& attempt = helloAttempt<HelloAttempt>(tag); if(edges().size()>0 && (_invoker.edgesAttemptsBeforeFallback==0 || attempt.count <_invoker.edgesAttemptsBeforeFallback)) { if(_invoker.edgesAttemptsBeforeFallback>0) { try { URI uri(epd); response.writeAddress(SocketAddress(uri.getHost(),uri.getPort()),false); // TODO check with true! } catch(Exception& ex) { ERROR("Parsing %s URL problem in hello attempt : %s",epd.c_str(),ex.displayText().c_str()); } } map<int,list<Edge*> > edgesSortedByCount; map<string,Edge*>::const_iterator it; for(it=edges().begin();it!=edges().end();++it) edgesSortedByCount[it->second->count].push_back(it->second); UInt8 count=0; map<int,list<Edge*> >::const_iterator it2; for(it2=edgesSortedByCount.begin();it2!=edgesSortedByCount.end();++it2) { list<Edge*>::const_iterator it3; for(it3=it2->second.begin();it3!=it2->second.end();++it3) { response.writeAddress((*it3)->address,false); if((++count)==6) // 6 redirections maximum break; } if(it3!=it2->second.end()) break; } return 0x71; } if(edges().size()>0) WARN("After %u hello attempts, impossible to connect to edges. Edges are busy? or unreachable?",_invoker.edgesAttemptsBeforeFallback); // New Cookie createCookie(response,attempt,tag,epd); // instance id (certificat in the middle) response.writeRaw(_certificat,sizeof(_certificat)); return 0x70; } else ERROR("Unkown handshake first way with '%02x' type",type); break; } case 0x39: case 0x38: { (UInt32&)farId = request.read32(); if(request.read7BitLongValue()!=COOKIE_SIZE) { ERROR("Bad handshake cookie '%s': its size should be 64 bytes",Util::FormatHex(request.current(),COOKIE_SIZE).c_str()); return 0; } map<const UInt8*,Cookie*,CompareCookies>::iterator itCookie = _cookies.find(request.current()); if(itCookie==_cookies.end()) { if(id!=0x39) { ERROR("Handshake cookie '%s' unknown",Util::FormatHex(request.current(),COOKIE_SIZE).c_str()); return 0; } Cookie* pCookie = new Cookie(); UInt32 pos = request.position(); request.readRaw((UInt8*)pCookie->value,COOKIE_SIZE); request >> (string&)pCookie->queryUrl; request.reset(pos); itCookie = _cookies.insert(pair<const UInt8*,Cookie*>(pCookie->value,pCookie)).first; } Cookie& cookie(*itCookie->second); if(cookie.id==0) { UInt8 decryptKey[AES_KEY_SIZE];UInt8* pDecryptKey=&decryptKey[0]; UInt8 encryptKey[AES_KEY_SIZE];UInt8* pEncryptKey=&encryptKey[0]; if(id==0x38) { request.next(COOKIE_SIZE); size_t size = (size_t)request.read7BitLongValue(); // peerId = SHA256(farPubKey) EVP_Digest(request.current(),size,(UInt8*)peer.id,NULL,EVP_sha256(),NULL); vector<UInt8> publicKey(request.read7BitValue()-2); request.next(2); // unknown request.readRaw(&publicKey[0],publicKey.size()); size = request.read7BitValue(); cookie.computeKeys(&publicKey[0],publicKey.size(),request.current(),(UInt16)size,decryptKey,encryptKey); } else { // edge pDecryptKey=NULL; pEncryptKey=NULL; memcpy((UInt8*)peer.id,request.current(),ID_SIZE); request.next(COOKIE_SIZE); request.next(request.read7BitEncoded()); } // Fill peer infos Util::UnpackUrl(cookie.queryUrl,(string&)peer.path,(map<string,string>&)peer.properties); // RESPONSE Session& session = _gateway.createSession(farId,peer,pDecryptKey,pEncryptKey,cookie); (UInt32&)cookie.id = session.id; string address; if(id==0x39) { // Session by edge session.flags |= SESSION_BY_EDGE; Edge* pEdge = _invoker.edges(peer.address); if(!pEdge) ERROR("Edge session creation by an unknown server edge %s",peer.address.toString().c_str()) else pEdge->addSession(session); request >> address; } else // Session direct address = session.peer.address.toString(); session.peer.addresses.clear(); session.peer.addresses.push_back(address); cookie.write(); } else