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;
    }
}