void FlowConnection::rawHandler(UInt8 type,PacketReader& data) { UInt16 flag = data.read16(); if(flag!=0x03) { Flow::rawHandler(type,data); return; } // setBufferTime UInt32 streamId = data.read32(); if(streamId>0) { INFO("setBufferTime %u on stream %u",data.read32(),streamId) BinaryWriter& raw = writer.writeRawMessage(); raw.write16(0); raw.write32(streamId); } }
void FlowStream::videoHandler(PacketReader& packet) { if(_pPublication && _pPublication->publisherId() == _index) { _pPublication->pushVideoPacket(packet.read32(),packet,_numberLostFragments); _numberLostFragments=0; } else WARN("a video packet has been received on a no publisher FlowStream, certainly a publication currently closing"); }
void FlowStream::videoHandler(PacketReader& packet) { if(_pPublication && _pPublication->publisherId() == _index) { _pPublication->pushVideoPacket(peer,packet.read32(),packet,_numberLostFragments); _numberLostFragments=0; } else fail("a video packet has been received on a no publisher FlowStream"); }
AMF::ContentType RTMFPFlow::unpack(PacketReader& packet,UInt32& time) { if(packet.available()==0) return AMF::EMPTY; AMF::ContentType type = (AMF::ContentType)packet.read8(); switch(type) { // amf content case AMF::INVOCATION_AMF3: packet.next(1); case AMF::INVOCATION: packet.next(4); return AMF::INVOCATION; case AMF::AUDIO: case AMF::VIDEO: time = packet.read32(); break; case AMF::DATA: packet.next(1); case AMF::RAW: packet.next(4); case AMF::CHUNKSIZE: break; default: ERROR("Unpacking type '",Format<UInt8>("%02x",(UInt8)type),"' unknown"); break; } return type; }
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; }
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); } }
// 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 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; }
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