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