Stream::StreamID ASIOReadBuffer::processPartialChunk(uint8* dataBuffer, uint32 packetLength, uint32 &bufferReceived, Chunk&retval) { unsigned int headerLength=bufferReceived; Stream::StreamID retid; retid.unserialize(dataBuffer,headerLength); assert(headerLength<=bufferReceived&&"High water mark must be greater than maximum StreamID size"); bufferReceived-=headerLength; assert(headerLength<=packetLength&&"High water mark must be greater than maximum StreamID size"); retval.resize(packetLength-headerLength); if (packetLength>headerLength) { std::memcpy(&*retval.begin(),dataBuffer+headerLength,bufferReceived); } return retid; }
void MultiplexedSocket::shutDownClosedStream(unsigned int controlCode,const Stream::StreamID &id) { if (controlCode==TCPStream::TCPStreamCloseStream){ std::deque<StreamIDCallbackPair> registrations; CommitCallbacks(registrations,CONNECTED,false); CallbackMap::iterator where=mCallbacks.find(id); if (where!=mCallbacks.end()) { std::tr1::shared_ptr<AtomicValue<int> > sendStatus=where->second->mSendStatus.lock(); if (sendStatus) { TCPStream::closeSendStatus(*sendStatus); } where->second->mConnectionCallback(Stream::Disconnected,"Remote Host Disconnected"); CommitCallbacks(registrations,CONNECTED,false);//just in case stream committed new callbacks during callback where=mCallbacks.find(id); delete where->second; mCallbacks.erase(where); } } std::tr1::unordered_set<Stream::StreamID>::iterator where=mOneSidedClosingStreams.find(id); if (where!=mOneSidedClosingStreams.end()) { mOneSidedClosingStreams.erase(where); } if (id.odd()==((mHighestStreamID.read()&1)?true:false)) { mFreeStreamIDs.push(id); } }
Stream::ReceivedResponse MultiplexedSocket::receiveFullChunk(unsigned int whichSocket, Stream::StreamID id,Chunk&newChunk){ Stream::ReceivedResponse retval = Stream::AcceptedData; if (id==Stream::StreamID()) {//control packet if(newChunk.size()) { unsigned int controlCode=*newChunk.begin(); switch (controlCode) { case TCPStream::TCPStreamCloseStream: case TCPStream::TCPStreamAckCloseStream: if (newChunk.size()>1) { unsigned int avail_len=newChunk.size()-1; id.unserialize((const uint8*)&(newChunk[1]),avail_len); if (avail_len+1>newChunk.size()) { SILOG(tcpsst,warning,"Control Chunk too short"); } } if (id!=Stream::StreamID()) { std::tr1::unordered_map<Stream::StreamID,unsigned int>::iterator where=mAckedClosingStreams.find(id); if (where!=mAckedClosingStreams.end()){ where->second++; int how_much=where->second; if (where->second==mSockets.size()) { mAckedClosingStreams.erase(where); shutDownClosedStream(controlCode,id); if (controlCode==TCPStream::TCPStreamCloseStream) { closeStream(getSharedPtr(),id,TCPStream::TCPStreamAckCloseStream); } } }else{ if (mSockets.size()==1) { shutDownClosedStream(controlCode,id); if (controlCode==TCPStream::TCPStreamCloseStream) { closeStream(getSharedPtr(),id,TCPStream::TCPStreamAckCloseStream); } }else { mAckedClosingStreams[id]=1; } } } break; default: break; } } }else { std::deque<StreamIDCallbackPair> registrations; CommitCallbacks(registrations,CONNECTED,false); CallbackMap::iterator where=mCallbacks.find(id); if (where!=mCallbacks.end()) { retval=where->second->mBytesReceivedCallback(newChunk); }else if (mOneSidedClosingStreams.find(id)==mOneSidedClosingStreams.end()) { //new substream TCPStream*newStream=new TCPStream(getSharedPtr(),id); TCPSetCallbacks setCallbackFunctor(this,newStream); mNewSubstreamCallback(newStream,setCallbackFunctor); if (setCallbackFunctor.mCallbacks != NULL) { CommitCallbacks(registrations,CONNECTED,false);//make sure bytes are received retval=setCallbackFunctor.mCallbacks->mBytesReceivedCallback(newChunk); }else { closeStream(getSharedPtr(),id); } }else { //IGNORED MESSAGE } } return retval; }
Chunk*ASIOSocketWrapper::constructControlPacket(const MultiplexedSocketPtr &thus, TCPStream::TCPStreamControlCodes code,const Stream::StreamID&sid) { const unsigned int max_size=16; switch (thus->getStreamType()) { case TCPStream::BASE64_ZERODELIM: { uint8 dataStream[max_size+Stream::StreamID::MAX_HEX_SERIALIZED_LENGTH+1]; Stream::StreamID controlStream;//control packet unsigned int streamidsize=0; unsigned int size=streamidsize=controlStream.serializeToHex(&dataStream[0],max_size); assert(size<max_size); dataStream[size++]=code; unsigned int cur=size; size=max_size-cur; size=sid.serialize(&dataStream[cur],size); assert(size+cur<=max_size); MemoryReference serializedStreamId(dataStream,streamidsize); return toBase64ZeroDelim(MemoryReference(dataStream+streamidsize,size+cur-streamidsize),MemoryReference(NULL,0),MemoryReference(NULL,0),&serializedStreamId); } break; case TCPStream::RFC_6455: { uint8 dataStream[max_size + Stream::StreamID::MAX_SERIALIZED_LENGTH + 2]; unsigned int packetHeaderLength = 2; unsigned int size = max_size; unsigned int cur = packetHeaderLength; Stream::StreamID controlStream; unsigned int streamidsize = controlStream.serialize(&dataStream[cur], max_size); assert(streamidsize < max_size); cur += streamidsize; dataStream[cur++] = code; size = max_size - cur; size = sid.serialize(&dataStream[cur], size); assert(size + cur <= max_size); MemoryReference serializedStreamId(&dataStream[packetHeaderLength], streamidsize); dataStream[0] = 0x80 | 0x02 ; // Flags = FIN/Unfragmented, Opcode = 2: binary data dataStream[1] = size + cur - packetHeaderLength; // Less than 125. return new Chunk(dataStream, dataStream + size + cur); } break; case TCPStream::LENGTH_DELIM: default: { uint8 dataStream[max_size+VariableLength::MAX_SERIALIZED_LENGTH+Stream::StreamID::MAX_SERIALIZED_LENGTH]; unsigned int size=max_size; Stream::StreamID controlStream;//control packet size=controlStream.serialize(&dataStream[VariableLength::MAX_SERIALIZED_LENGTH],size); assert(size<max_size); dataStream[VariableLength::MAX_SERIALIZED_LENGTH+size++]=code; unsigned int cur=VariableLength::MAX_SERIALIZED_LENGTH+size; size=max_size-cur; size=sid.serialize(&dataStream[cur],size); assert(size+cur<=max_size); VariableLength streamSize=VariableLength(size+cur-VariableLength::MAX_SERIALIZED_LENGTH); unsigned int actualHeaderLength=streamSize.serialize(dataStream,VariableLength::MAX_SERIALIZED_LENGTH); if (actualHeaderLength!=VariableLength::MAX_SERIALIZED_LENGTH) { unsigned int retval=streamSize.serialize(dataStream+VariableLength::MAX_SERIALIZED_LENGTH-actualHeaderLength,VariableLength::MAX_SERIALIZED_LENGTH); assert(retval==actualHeaderLength); } return new Chunk(dataStream+VariableLength::MAX_SERIALIZED_LENGTH-actualHeaderLength,dataStream+size+cur); } break; } }