public void Send(ICopyable data) { //We always use the fragmenting header to signal //to the receiving end that we support (and want) //fragmentation. MemBlock rest = data as MemBlock; if (null == rest) { rest = MemBlock.Copy(data); } int len = rest.Length; if (len > MAX_SEND_SIZE) { throw new SendException(true, System.String.Format("Packet too large: {0}, MaxSize = {1}", len, MAX_SEND_SIZE)); } uint crc32 = rest.Read <uint>(Crc32.ComputeChecksum); //Avoid a RNG operation for now, might need to reconsider //If we use RNG, we have to touch state, that has thread-safety issues int id = _wrapped_sender.GetHashCode() ^ rest.GetHashCode(); byte[] header = new byte[HEADER_SIZE - 2]; int off = FragPType.CopyTo(header, 0); NumberSerializer.WriteInt((int)crc32, header, off); NumberSerializer.WriteInt(id, header, off + 4); MemBlock header_mb = MemBlock.Reference(header); ushort block = 0; int blocksize = ComputeBlockSize(len); while (rest.Length > 0) { int this_size = System.Math.Min(blocksize, rest.Length); MemBlock this_block = rest.Slice(0, this_size); rest = rest.Slice(this_size); //Check to see if this is the last block: if (rest.Length == 0) { block = (ushort)(block ^ (0x8000)); //Set the highest bit, this is last } byte[] block_b = new byte[2]; NumberSerializer.WriteShort((short)block, block_b, 0); MemBlock block_mb = MemBlock.Reference(block_b); _wrapped_sender.Send(new CopyList(header_mb, block_mb, this_block)); block += 1; } }
protected MemBlock DecodeAndClear(uint crc32, int id, ushort total) { ICopyable[] blocks = new ICopyable[total]; bool missing_block = false; ushort last_idx = (ushort)(total - 1); for (ushort i = 0; i < last_idx; i++) { var key = new Triple <uint, int, ushort>(crc32, id, i); var this_block = (MemBlock)_fragments.Remove(key); if (null != this_block) { blocks[i] = this_block; } else { //We are missing one: missing_block = true; break; } } //Get the last one: ushort last_id = (ushort)(last_idx ^ FragmentingSender.LAST_BLOCK_FLAG); var lastkey = new Triple <uint, int, ushort>(crc32, id, last_id); var last_block = (MemBlock)_fragments.Remove(lastkey); blocks[last_idx] = last_block; missing_block = missing_block || (null == last_block); MemBlock result = null; if (false == missing_block) { result = MemBlock.Concat(blocks); uint crc32_ck = result.Read <uint>(Crc32.ComputeChecksum); if (crc32_ck != crc32) { //Something went wrong: result = null; } } _frag_count.Remove(new Pair <uint, int>(crc32, id)); return(result); }