/* This is a test console app for udp net interface. */ int main( int argc, char** argv ) { bool quit = false; PacketReader reader; PacketWriter writer; char buff[512]; NetSession session; LocalClient server; LocalClient sender; int frame = 0; // Init session.OpenPort( 5000 ); server = session.CreateLocalClient(); //session.SetPacketLoss( 50 ); // Send stuff ConsolePrintf( "Server is running.\n" ); while ( !quit ) { session.OnUpdate(); while ( server.IsDataReady() ) { server.ReceiveData( reader, sender ); frame = reader.Read< int >(); ConsolePrintf( "RECV: %d\n", frame ); //quit = !strcmp( buff, "quit" ); sprintf( buff, "echo: %d", frame ); //ConsolePrintf( "Reply: %s\n", buff ); writer.WriteString( buff ); server.SendData( writer ); } } // Quit return 0; }
void RTMFP::Encode(AESEngine& aesEncrypt,PacketWriter& packet) { if(aesEncrypt.type != AESEngine::EMPTY) { // paddingBytesLength=(0xffffffff-plainRequestLength+5)&0x0F int paddingBytesLength = (0xFFFFFFFF-packet.length()+5)&0x0F; // Padd the plain request with paddingBytesLength of value 0xff at the end packet.reset(packet.length()); string end(paddingBytesLength,(UInt8)0xFF); packet.writeRaw(end); } WriteCRC(packet); // Encrypt the resulted request aesEncrypt.process(packet.begin()+4,packet.begin()+4,packet.length()-4); }
bool LUAXML::LUAToXMLElement(Exception& ex, lua_State* pState, PacketWriter& writer) { // -1 => table lua_pushstring(pState, "__name"); lua_rawget(pState, -2); const char* name(lua_tostring(pState, -1)); lua_pop(pState, 1); if (!name) { ex.set(Exception::APPLICATION, "Impossible to write a XML element without name (__name)"); return false; } // write attributes writer.write("<").write(name).write(" "); lua_pushnil(pState); // first key while (lua_next(pState, -2) != 0) { // uses 'key' (at index -2) and 'value' (at index -1) if (lua_type(pState, -2) == LUA_TSTRING && strcmp(lua_tostring(pState, -2),"__name")!=0 && lua_isstring(pState, -1)) writer.write(lua_tostring(pState, -2)).write("=\"").write(lua_tostring(pState, -1)).write("\" "); lua_pop(pState, 1); } if (lua_objlen(pState, -1) == 0) { writer.write("/>"); return true; } writer.write(">"); // write elements lua_pushnil(pState); // first key while (lua_next(pState, -2) != 0) { // uses 'key' (at index -2) and 'value' (at index -1) if (lua_isnumber(pState, -2)) { if (lua_istable(pState, -1)) LUAToXMLElement(ex, pState, writer); // table child else if (lua_isstring(pState, -1)) writer.write(lua_tostring(pState, -1), lua_objlen(pState, -1)); // __value else ex.set(Exception::APPLICATION, "Impossible to convert the value of type ", lua_typename(pState, lua_type(pState, -1)), "to a correct XML value of ",name); } else if (lua_type(pState, -2) != LUA_TSTRING) ex.set(Exception::APPLICATION, "Impossible to convert the key of type ",lua_typename(pState,lua_type(pState,-2)),"to a correct XML element of ",name); lua_pop(pState, 1); } writer.write("</").write(name).write(">"); return true; }
void RTMFP::Pack(PacketWriter& packet,UInt32 farId) { PacketReader reader(packet.begin(),packet.length()); reader.next(4); packet.reset(0); packet.write32(reader.read32()^reader.read32()^farId); }
void FlowWriter::flush(PacketWriter& writer,UInt64 stage,UInt8 flags,bool header,BinaryReader& reader,UInt16 size) { if(_stageAck==0 && header) flags |= MESSAGE_HEADER; if(size==0) flags |= MESSAGE_ABANDONMENT; if(_closed && _messages.size()==1) // On LAST message flags |= MESSAGE_END; // TRACE("FlowWriter %u stage %u",id,stage); writer.write8(flags); if(header) { writer.write7BitLongValue(id); writer.write7BitLongValue(stage); writer.write7BitLongValue(stage-_stageAck); // signature if(_stageAck==0) { writer.writeString8(signature); // No write this in the case where it's a new flow! if(flowId>0) { writer.write8(1+Util::Get7BitValueSize(flowId)); // following size writer.write8(0x0a); // Unknown! writer.write7BitLongValue(flowId); } writer.write8(0); // marker of end for this part } } if(size>0) { reader.readRaw(writer.begin()+writer.position(),size); writer.next(size); } }
// TODO make perhaps a FlowHandshake 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); // UDP hole punching if(type == 0x0f) return _gateway.p2pHandshake(tag,response,peer().address,(const UInt8*)epd.c_str()); if(type == 0x0a){ /// Handshake // RESPONSE 38 // New Cookie char cookie[65]; RandomInputStream ris; ris.read(cookie,64); cookie[64]='\0'; response.write8(64); response.writeRaw(cookie,64); _cookies[cookie] = new Cookie(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 0x38: { _farId = request.read32(); string cookie; request.readRaw(request.read8(),cookie); map<string,Cookie*>::iterator itCookie = _cookies.find(cookie.c_str()); if(itCookie==_cookies.end()) { ERROR("Handshake cookie '%s' unknown",cookie.c_str()); return 0; } request.read8(); // why 0x81? // signature string farSignature; request.readString8(farSignature); // 81 02 1D 02 stable // farPubKeyPart UInt8 farPubKeyPart[128]; request.readRaw((char*)farPubKeyPart,sizeof(farPubKeyPart)); string farCertificat; request.readString8(farCertificat); // peerId = SHA256(farSignature+farPubKey) string temp(farSignature); temp.append((char*)farPubKeyPart,sizeof(farPubKeyPart)); EVP_Digest(temp.c_str(),temp.size(),(UInt8*)peer().id,NULL,EVP_sha256(),NULL); // Compute Diffie-Hellman secret UInt8 pubKey[128]; UInt8 sharedSecret[128]; RTMFP::EndDiffieHellman(RTMFP::BeginDiffieHellman(pubKey),farPubKeyPart,sharedSecret); // Compute Keys UInt8 requestKey[AES_KEY_SIZE]; UInt8 responseKey[AES_KEY_SIZE]; RTMFP::ComputeAsymetricKeys(sharedSecret,pubKey,_signature,farCertificat,requestKey,responseKey); // RESPONSE Util::UnpackUrl(itCookie->second->queryUrl,(string&)peer().path,(map<string,string>&)peer().parameters); response << _gateway.createSession(_farId,peer(),requestKey,responseKey); response.write8(0x81); response.writeString8(_signature); response.writeRaw((char*)pubKey,sizeof(pubKey)); response.write8(0x58); // remove cookie _cookies.erase(itCookie); // db_add_public(s); // TODO return 0x78; } default: ERROR("Unkown handshake packet id '%02x'",id); } return 0; }
UInt8 RTMFPServer::p2pHandshake(const string& tag,PacketWriter& response,const SocketAddress& address,const UInt8* peerIdWanted) { ServerSession* pSessionWanted = (ServerSession*)_sessions.find(peerIdWanted); if(_pCirrus) { // Just to make working the man in the middle mode ! // find the flash client equivalence Session* pSession = _sessions.find(address); if(!pSession) { ERROR("UDP Hole punching error : middle equivalence not found for session wanted"); return 0; } PacketWriter& request = ((Middle*)pSession)->handshaker(); request.write8(0x22); request.write8(0x21); request.write8(0x0F); request.writeRaw(pSessionWanted ? ((Middle*)pSessionWanted)->middlePeer().id : peerIdWanted,ID_SIZE); request.writeRaw(tag); ((Middle*)pSession)->sendHandshakeToTarget(0x30); // no response here! return 0; } if(!pSessionWanted) { DEBUG("UDP Hole punching : session %s wanted not found",Util::FormatHex(peerIdWanted,ID_SIZE).c_str()) set<string> addresses; onRendezVousUnknown(peerIdWanted,addresses); if(addresses.empty()) return 0; set<string>::const_iterator it; for(it=addresses.begin(); it!=addresses.end(); ++it) { try { SocketAddress address(*it); response.writeAddress(address,it==addresses.begin()); } catch(Exception& ex) { ERROR("Bad redirection address %s, %s",(*it).c_str(),ex.displayText().c_str()); } } return 0x71; } else if(pSessionWanted->failed()) { DEBUG("UDP Hole punching : session wanted is deleting"); return 0; } UInt8 result = 0x00; if(_middle) { if(pSessionWanted->pTarget) { HelloAttempt& attempt = _handshake.helloAttempt<HelloAttempt>(tag); attempt.pTarget = pSessionWanted->pTarget; _handshake.createCookie(response,attempt,tag,""); response.writeRaw(&pSessionWanted->pTarget->publicKey[0],pSessionWanted->pTarget->publicKey.size()); result = 0x70; } else ERROR("Peer/peer dumped exchange impossible : no corresponding 'Target' with the session wanted"); } if(result==0x00) { /// Udp hole punching normal process UInt32 times = pSessionWanted->helloAttempt(tag); pSessionWanted->p2pHandshake(address,tag,times,(times>0 || address.host()==pSessionWanted->peer.address.host()) ? _sessions.find(address) : NULL); bool first=true; list<Address>::const_iterator it2; for(it2=pSessionWanted->peer.addresses.begin(); it2!=pSessionWanted->peer.addresses.end(); ++it2) { const Address& addr = *it2; if(addr == address) WARN("A client tries to connect to himself (same %s address)",address.toString().c_str()); response.writeAddress(addr,first); DEBUG("P2P address initiator exchange, %s:%u",Util::FormatHex(&addr.host[0],addr.host.size()).c_str(),addr.port); first=false; } result = 0x71; } return result; }
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); // Fill peer infos UInt16 port; string host; Util::UnpackUrl(epd,host,port,(string&)peer.path,(map<string,string>&)peer.properties); set<string> addresses; peer.onHandshake(attempt.count+1,addresses); if(!addresses.empty()) { set<string>::iterator it; for(it=addresses.begin();it!=addresses.end();++it) { try { if((*it)=="again") ((string&)*it).assign(format("%s:%hu",host,port)); SocketAddress address(*it); response.writeAddress(address,it==addresses.begin()); } catch(Exception& ex) { ERROR("Bad redirection address %s in hello attempt, %s",(*it)=="again" ? epd.c_str() : (*it).c_str(),ex.displayText().c_str()); } } return 0x71; } // 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 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()) { WARN("Cookie %s unknown, maybe already connected (udpBuffer congested?)",Util::FormatHex(request.current(),COOKIE_SIZE).c_str()); return 0; } Cookie& cookie(*itCookie->second); (SocketAddress&)cookie.peerAddress = peer.address; if(cookie.farId==0) { ((UInt32&)cookie.farId) = farId; request.next(COOKIE_SIZE); size_t size = (size_t)request.read7BitLongValue(); // peerId = SHA256(farPubKey) EVP_Digest(request.current(),size,(UInt8*)cookie.peerId,NULL,EVP_sha256(),NULL); cookie.initiatorKey().resize(request.read7BitValue()-2); request.next(2); // unknown request.readRaw(&cookie.initiatorKey()[0],cookie.initiatorKey().size()); cookie.initiatorNonce().resize(request.read7BitValue()); request.readRaw(&cookie.initiatorNonce()[0],cookie.initiatorNonce().size()); cookie.computeKeys(); } else if(cookie.id>0) { // Repeat cookie reponse! cookie.read(response); return 0x78; } // else Keys are computing (multi-thread) break; } default: ERROR("Unkown handshake packet id %u",id); } return 0; }
void RTMFP::Pack(PacketWriter& packet,UInt32 farId) { PacketReader reader(packet.data(),packet.size()); reader.next(4); BinaryWriter(packet.data(),4).write32(reader.read32()^reader.read32()^farId); }
void RTMFP::WriteCRC(PacketWriter& packet) { // Compute the CRC and add it at the beginning of the request PacketReader reader(packet.data(),packet.size()); reader.next(6); BinaryWriter(packet.data()+4,2).write16(CheckSum(reader)); }
void RTMFP::Pack(PacketWriter packet,UInt32 farId) { packet.reset(); PacketReader reader(packet); reader.read32(); packet.write32(reader.read32()^reader.read32()^farId); }
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
void dump_to_file(PacketWriter &writer, int packet_count, PDU &packet) { while(packet_count--) { writer.write(packet); } }
UInt8 RTMFPHandshake::handshakeHandler(UInt8 id,PacketReader& request,PacketWriter& response) { switch(id){ case 0x30: { request.next(1); 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) { const UInt8* peerId = (const UInt8*)epd.c_str(); RTMFPSession* pSessionWanted = _sessions.find<RTMFPSession>(peerId); if(pSessionWanted) { if(pSessionWanted->failed()) return 0x00; // TODO no way in RTMFP to tell "died!" /// Udp hole punching UInt32 times = attempt(tag); RTMFPSession* pSession(NULL); if(times > 0 || peer.address.host() == pSessionWanted->peer.address.host()) pSession = _sessions.find<RTMFPSession>(peer.address); pSessionWanted->p2pHandshake(tag,peer.address,times,pSession); RTMFP::WriteAddress(response,pSessionWanted->peer.address, RTMFP::ADDRESS_PUBLIC); DEBUG("P2P address initiator exchange, ",pSessionWanted->peer.address.toString()); for(const SocketAddress& address : pSessionWanted->peer.localAddresses) { RTMFP::WriteAddress(response,address, RTMFP::ADDRESS_LOCAL); DEBUG("P2P address initiator exchange, ",address.toString()); } // add the turn address (RelayServer) if possible and required if (pSession && times>0) { UInt8 timesBeforeTurn(0); if(pSession->peer.parameters().getNumber("timesBeforeTurn",timesBeforeTurn) && timesBeforeTurn>=times) { UInt16 port = invoker.relayer.relay(pSession->peer.address,pSessionWanted->peer.address,20); // 20 sec de timeout is enough for RTMFP! if(port>0) { Exception ex; SocketAddress address; string addr; SocketAddress::Split(pSession->peer.serverAddress,addr); bool success(false); EXCEPTION_TO_LOG(success=address.set(ex,addr, port),"RTMFP turn impossible") if (success) RTMFP::WriteAddress(response,address, RTMFP::ADDRESS_REDIRECTION); } // else ERROR already display by RelayServer class } } return 0x71; } DEBUG("UDP Hole punching, session ", Util::FormatHex(peerId, ID_SIZE, LOG_BUFFER), " wanted not found") set<SocketAddress> addresses; peer.onRendezVousUnknown(peerId,addresses); set<SocketAddress>::const_iterator it; for(it=addresses.begin();it!=addresses.end();++it) { if(it->host().isWildcard()) continue; if(peer.address == *it) WARN("A client tries to connect to himself (same ",peer.address.toString()," address)"); RTMFP::WriteAddress(response,*it,RTMFP::ADDRESS_REDIRECTION); DEBUG("P2P address initiator exchange, ",it->toString()); } return addresses.empty() ? 0 : 0x71; }
void CBodyBasics::TransmitBody(INT64 nTime, int nBodyCount, IBody** ppBodies) { // UDP Message msg; PacketWriter pw; bool ok; HRESULT hr; for (int cptr = 0; cptr < clients.size(); cptr++) { if (clients[cptr].active == 1) { //printFucker("sending to client " + clients[cptr].address + ": " + std::to_string(nBodyCount) + " bodies!\n"); // SEND FRAME START OVER UDP msg.init("/beginFrame"); msg.pushInt32(nBodyCount); pw.init(); pw.startBundle().startBundle().addMessage(msg).endBundle().endBundle(); ok = clients[cptr].socket.sendPacket(pw.packetData(), pw.packetSize()); for (int i = 0; i < nBodyCount; ++i) { IBody* pBody = ppBodies[i]; if (pBody) { BOOLEAN bTracked = false; hr = pBody->get_IsTracked(&bTracked); if (SUCCEEDED(hr) && bTracked) { Joint joints[JointType_Count]; D2D1_POINT_2F jointPoints[JointType_Count]; HandState leftHandState = HandState_Unknown; HandState rightHandState = HandState_Unknown; pBody->get_HandLeftState(&leftHandState); pBody->get_HandRightState(&rightHandState); hr = pBody->GetJoints(_countof(joints), joints); if (SUCCEEDED(hr)) { msg.init("/beginBody"); msg.pushInt32(i); pw.init(); pw.startBundle().startBundle().addMessage(msg).endBundle().endBundle(); ok = clients[cptr].socket.sendPacket(pw.packetData(), pw.packetSize()); for (int j = 0; j < _countof(joints); ++j) { // /kinect body joint x y z msg.init("/bodyJoint"); msg.pushInt32(i); msg.pushInt32(j); // body relative - joints[1] is spineMid which maps to Torso in OpenNI msg.pushFloat(joints[j].Position.X - joints[1].Position.X); msg.pushFloat(joints[j].Position.Y - joints[1].Position.Y); msg.pushFloat(joints[j].Position.Z - joints[1].Position.Z); // send message pw.init(); pw.startBundle().startBundle().addMessage(msg).endBundle().endBundle(); ok = clients[cptr].socket.sendPacket(pw.packetData(), pw.packetSize()); } msg.init("/endBody"); msg.pushInt32(i); pw.init(); pw.startBundle().startBundle().addMessage(msg).endBundle().endBundle(); ok = clients[cptr].socket.sendPacket(pw.packetData(), pw.packetSize()); } } } } // SEND FRAME END OVER UDP msg.init("/endFrame"); pw.init(); pw.startBundle().startBundle().addMessage(msg).endBundle().endBundle(); ok = clients[cptr].socket.sendPacket(pw.packetData(), pw.packetSize()); } } }