third_party.pigweed.src/pw_transfer/context.cc
Wyatt Hepler e6209d9e14 pw_transfer: Reorganize code; ignore bad chunks after drops
- On writes, only send a transfer parameters update after the first
  chunk with an incorrect offset. This prevents storms of transfer
  parameters updates when early packets in the window are dropped. If
  that update is dropped, the client time out and resend its last chunk.
- Move transfer logic to the ServerContext class.
- Introduce the ClientConnection class, which represents a connection
  to a particular pw_transfer client. It bundles the server writers with
  the transfer parameters for those streams.

Change-Id: If68943610252c63c3044956f335a641523a8a917
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/63284
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
Commit-Queue: Wyatt Hepler <hepler@google.com>
2021-10-02 01:05:06 +00:00

72 lines
2.7 KiB
C++

// Copyright 2021 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_transfer/internal/context.h"
#include "pw_assert/check.h"
#include "pw_status/try.h"
#include "pw_varint/varint.h"
namespace pw::transfer::internal {
size_t Context::MaxWriteChunkSize(size_t max_chunk_size_bytes,
uint32_t channel_id) const {
// Start with the user-provided maximum chunk size, which should be the usable
// payload length on the RPC ingress path after any transport overhead.
ssize_t max_size = max_chunk_size_bytes;
// Subtract the RPC overhead (pw_rpc/internal/packet.proto).
//
// type: 1 byte key, 1 byte value (CLIENT_STREAM)
// channel_id: 1 byte key, varint value (calculate from stream)
// service_id: 1 byte key, 4 byte value
// method_id: 1 byte key, 4 byte value
// payload: 1 byte key, varint length (remaining space)
// status: 0 bytes (not set in stream packets)
//
// TOTAL: 14 bytes + encoded channel_id size + encoded payload length
//
max_size -= 14;
max_size -= varint::EncodedSize(channel_id);
max_size -= varint::EncodedSize(max_size);
// Subtract the transfer service overhead for a client write chunk
// (pw_transfer/transfer.proto).
//
// transfer_id: 1 byte key, varint value (calculate)
// offset: 1 byte key, varint value (calculate)
// data: 1 byte key, varint length (remaining space)
//
// TOTAL: 3 + encoded transfer_id + encoded offset + encoded data length
//
size_t max_offset_in_window = offset() + pending_bytes();
max_size -= 3;
max_size -= varint::EncodedSize(transfer_id());
max_size -= varint::EncodedSize(max_offset_in_window);
max_size -= varint::EncodedSize(max_size);
// A resulting value of zero (or less) renders write transfers unusable, as
// there is no space to send any payload. This should be considered a
// programmer error in the transfer service setup.
PW_CHECK_INT_GT(
max_size,
0,
"Transfer service maximum chunk size is too small to fit a payload. "
"Increase max_chunk_size_bytes to support write transfers.");
return max_size;
}
} // namespace pw::transfer::internal