private static Message GetBlock(Message msg, Int32 num, Int32 szx) { Int32 blockSize = BlockOption.DecodeSZX(szx); Int32 payloadOffset = num * blockSize; Int32 payloadLeft = msg.PayloadSize - payloadOffset; if (payloadLeft > 0) { Message block = null; if (msg is Request) { block = new Request(msg.Code, msg.IsConfirmable); } else { block = new Response(msg.Code); if (num == 0 && msg.Type == MessageType.CON) { block.Type = MessageType.CON; } else { block.Type = msg.IsNonConfirmable ? MessageType.NON : MessageType.ACK; } block.ID = msg.ID; } block.PeerAddress = msg.PeerAddress; block.Token = msg.Token; // use same options foreach (Option opt in msg.GetOptions()) { block.AddOption(opt); } // calculate 'more' bit Boolean m = blockSize < payloadLeft; // limit block size to size of payload left if (!m) { blockSize = payloadLeft; } // copy payload block Byte[] blockPayload = new Byte[blockSize]; Array.Copy(msg.Payload, payloadOffset, blockPayload, 0, blockSize); block.Payload = blockPayload; Option blockOpt = null; if (msg is Request) { blockOpt = new BlockOption(OptionType.Block1, num, szx, m); } else { blockOpt = new BlockOption(OptionType.Block2, num, szx, m); } block.SetOption(blockOpt); return(block); } else { return(null); } }
/// <summary> /// Sending a message. /// </summary> /// <param name="msg">The message to be sent</param> protected override void DoSendMessage(Message msg) { int sendSZX = _defaultSZX; int sendNUM = 0; // block negotiation if ((msg is Response) && ((Response)msg).Request != null) { BlockOption buddyBlock = (BlockOption)((Response)msg).Request.GetFirstOption(OptionType.Block2); if (buddyBlock != null) { if (buddyBlock.SZX < sendSZX) { sendSZX = buddyBlock.SZX; } sendNUM = buddyBlock.NUM; } } // check if transfer needs to be split up if (msg.PayloadSize > BlockOption.DecodeSZX(sendSZX)) { // split message up using block1 for requests and block2 for responses Message msgBlock = GetBlock(msg, sendNUM, sendSZX); if (msgBlock != null) { BlockOption block1 = (BlockOption)msgBlock.GetFirstOption(OptionType.Block1); BlockOption block2 = (BlockOption)msgBlock.GetFirstOption(OptionType.Block2); // only cache if blocks remaining for request if ((block1 != null && block1.M) || (block2 != null && block2.M)) { msg.SetOption(block1); msg.SetOption(block2); TransferContext transfer = new TransferContext(msg); _outgoing[msg.SequenceKey] = transfer; if (log.IsDebugEnabled) { log.Debug(String.Format("TransferLayer - Caching blockwise transfer for NUM {0} : {1}", sendNUM, msg.SequenceKey)); } } else { // must be block2 by client if (log.IsDebugEnabled) { log.Debug(String.Format("TransferLayer - Answering block request without caching: {0} | {1}", msg.SequenceKey, block2)); } } // send block and wait for reply SendMessageOverLowerLayer(msgBlock); } else { // must be block2 by client if (log.IsInfoEnabled) { log.Info(String.Format("TransferLayer - Rejecting initial out-of-scope request: {0} | NUM: {1}, SZX: {2} ({3} bytes), M: n/a, {4} bytes available", msg.SequenceKey, sendNUM, sendSZX, BlockOption.DecodeSZX(sendSZX), msg.PayloadSize)); } HandleOutOfScopeError(msg.NewReply(true)); } } else { // send complete message SendMessageOverLowerLayer(msg); } }
/// <summary> /// Initializes a transfer layer. /// </summary> /// <param name="defaultBlockSize">The default block size used for block-wise transfers or -1 to disable outgoing block-wise transfers</param> public TransferLayer(Int32 defaultBlockSize) { if (defaultBlockSize == 0) { defaultBlockSize = CoapConstants.DefaultBlockSize; } if (defaultBlockSize > 0) { _defaultSZX = BlockOption.EncodeSZX(defaultBlockSize); if (!BlockOption.ValidSZX(_defaultSZX)) { _defaultSZX = defaultBlockSize > 1024 ? 6 : BlockOption.EncodeSZX(defaultBlockSize & 0x07f0); if (log.IsWarnEnabled) { log.Warn(String.Format("TransferLayer - Unsupported block size {0}, using {1} instead", defaultBlockSize, BlockOption.DecodeSZX(_defaultSZX))); } } } else { // disable outgoing blockwise transfers _defaultSZX = -1; } }