1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_transfer: 2*61c4878aSAndroid Build Coastguard Worker 3*61c4878aSAndroid Build Coastguard Worker=========== 4*61c4878aSAndroid Build Coastguard Workerpw_transfer 5*61c4878aSAndroid Build Coastguard Worker=========== 6*61c4878aSAndroid Build Coastguard Worker``pw_transfer`` is a reliable data transfer protocol which runs on top of 7*61c4878aSAndroid Build Coastguard WorkerPigweed RPC. 8*61c4878aSAndroid Build Coastguard Worker 9*61c4878aSAndroid Build Coastguard Worker.. attention:: 10*61c4878aSAndroid Build Coastguard Worker 11*61c4878aSAndroid Build Coastguard Worker ``pw_transfer`` is under construction and so is its documentation. 12*61c4878aSAndroid Build Coastguard Worker 13*61c4878aSAndroid Build Coastguard Worker----- 14*61c4878aSAndroid Build Coastguard WorkerUsage 15*61c4878aSAndroid Build Coastguard Worker----- 16*61c4878aSAndroid Build Coastguard Worker 17*61c4878aSAndroid Build Coastguard WorkerC++ 18*61c4878aSAndroid Build Coastguard Worker=== 19*61c4878aSAndroid Build Coastguard Worker 20*61c4878aSAndroid Build Coastguard WorkerTransfer thread 21*61c4878aSAndroid Build Coastguard Worker--------------- 22*61c4878aSAndroid Build Coastguard WorkerTo run transfers as either a client or server (or both), a dedicated thread is 23*61c4878aSAndroid Build Coastguard Workerrequired. The transfer thread is used to process all transfer-related events 24*61c4878aSAndroid Build Coastguard Workersafely. The same transfer thread can be shared by a transfer client and service 25*61c4878aSAndroid Build Coastguard Workerrunning on the same system. 26*61c4878aSAndroid Build Coastguard Worker 27*61c4878aSAndroid Build Coastguard Worker.. note:: 28*61c4878aSAndroid Build Coastguard Worker 29*61c4878aSAndroid Build Coastguard Worker All user-defined transfer callbacks (i.e. the virtual interface of a 30*61c4878aSAndroid Build Coastguard Worker ``Handler`` or completion function in a transfer client) will be 31*61c4878aSAndroid Build Coastguard Worker invoked from the transfer thread's context. 32*61c4878aSAndroid Build Coastguard Worker 33*61c4878aSAndroid Build Coastguard WorkerIn order to operate, a transfer thread requires two buffers: 34*61c4878aSAndroid Build Coastguard Worker 35*61c4878aSAndroid Build Coastguard Worker- The first is a *chunk buffer*. This is used to stage transfer packets received 36*61c4878aSAndroid Build Coastguard Worker by the RPC system to be processed by the transfer thread. It must be large 37*61c4878aSAndroid Build Coastguard Worker enough to store the largest possible chunk the system supports. 38*61c4878aSAndroid Build Coastguard Worker 39*61c4878aSAndroid Build Coastguard Worker- The second is an *encode buffer*. This is used by the transfer thread to 40*61c4878aSAndroid Build Coastguard Worker encode outgoing RPC packets. It is necessarily larger than the chunk buffer. 41*61c4878aSAndroid Build Coastguard Worker Typically, this is sized to the system's maximum transmission unit at the 42*61c4878aSAndroid Build Coastguard Worker transport layer. 43*61c4878aSAndroid Build Coastguard Worker 44*61c4878aSAndroid Build Coastguard WorkerA transfer thread is created by instantiating a ``pw::transfer::Thread``. This 45*61c4878aSAndroid Build Coastguard Workerclass derives from ``pw::thread::ThreadCore``, allowing it to directly be used 46*61c4878aSAndroid Build Coastguard Workerwhen creating a system thread. Refer to :ref:`module-pw_thread-thread-creation` 47*61c4878aSAndroid Build Coastguard Workerfor additional information. 48*61c4878aSAndroid Build Coastguard Worker 49*61c4878aSAndroid Build Coastguard Worker**Example thread configuration** 50*61c4878aSAndroid Build Coastguard Worker 51*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 52*61c4878aSAndroid Build Coastguard Worker 53*61c4878aSAndroid Build Coastguard Worker #include "pw_transfer/transfer_thread.h" 54*61c4878aSAndroid Build Coastguard Worker 55*61c4878aSAndroid Build Coastguard Worker namespace { 56*61c4878aSAndroid Build Coastguard Worker 57*61c4878aSAndroid Build Coastguard Worker // The maximum number of concurrent transfers the thread should support as 58*61c4878aSAndroid Build Coastguard Worker // either a client or a server. These can be set to 0 (if only using one or 59*61c4878aSAndroid Build Coastguard Worker // the other). 60*61c4878aSAndroid Build Coastguard Worker constexpr size_t kMaxConcurrentClientTransfers = 5; 61*61c4878aSAndroid Build Coastguard Worker constexpr size_t kMaxConcurrentServerTransfers = 3; 62*61c4878aSAndroid Build Coastguard Worker 63*61c4878aSAndroid Build Coastguard Worker // The maximum payload size that can be transmitted by the system's 64*61c4878aSAndroid Build Coastguard Worker // transport stack. This would typically be defined within some transport 65*61c4878aSAndroid Build Coastguard Worker // header. 66*61c4878aSAndroid Build Coastguard Worker constexpr size_t kMaxTransmissionUnit = 512; 67*61c4878aSAndroid Build Coastguard Worker 68*61c4878aSAndroid Build Coastguard Worker // The maximum amount of data that should be sent within a single transfer 69*61c4878aSAndroid Build Coastguard Worker // packet. By necessity, this should be less than the max transmission unit. 70*61c4878aSAndroid Build Coastguard Worker // 71*61c4878aSAndroid Build Coastguard Worker // pw_transfer requires some additional per-packet overhead, so the actual 72*61c4878aSAndroid Build Coastguard Worker // amount of data it sends may be lower than this. 73*61c4878aSAndroid Build Coastguard Worker constexpr size_t kMaxTransferChunkSizeBytes = 480; 74*61c4878aSAndroid Build Coastguard Worker 75*61c4878aSAndroid Build Coastguard Worker // Buffers for storing and encoding chunks (see documentation above). 76*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kMaxTransferChunkSizeBytes> chunk_buffer; 77*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kMaxTransmissionUnit> encode_buffer; 78*61c4878aSAndroid Build Coastguard Worker 79*61c4878aSAndroid Build Coastguard Worker pw::transfer::Thread<kMaxConcurrentClientTransfers, 80*61c4878aSAndroid Build Coastguard Worker kMaxConcurrentServerTransfers> 81*61c4878aSAndroid Build Coastguard Worker transfer_thread(chunk_buffer, encode_buffer); 82*61c4878aSAndroid Build Coastguard Worker 83*61c4878aSAndroid Build Coastguard Worker } // namespace 84*61c4878aSAndroid Build Coastguard Worker 85*61c4878aSAndroid Build Coastguard Worker // pw::transfer::TransferThread is the generic, non-templated version of the 86*61c4878aSAndroid Build Coastguard Worker // Thread class. A Thread can implicitly convert to a TransferThread. 87*61c4878aSAndroid Build Coastguard Worker pw::transfer::TransferThread& GetSystemTransferThread() { 88*61c4878aSAndroid Build Coastguard Worker return transfer_thread; 89*61c4878aSAndroid Build Coastguard Worker } 90*61c4878aSAndroid Build Coastguard Worker 91*61c4878aSAndroid Build Coastguard Worker.. _pw_transfer-transfer-server: 92*61c4878aSAndroid Build Coastguard Worker 93*61c4878aSAndroid Build Coastguard WorkerTransfer server 94*61c4878aSAndroid Build Coastguard Worker--------------- 95*61c4878aSAndroid Build Coastguard Worker``pw_transfer`` provides an RPC service for running transfers through an RPC 96*61c4878aSAndroid Build Coastguard Workerserver. 97*61c4878aSAndroid Build Coastguard Worker 98*61c4878aSAndroid Build Coastguard WorkerTo know how to read data from or write data to device, a ``Handler`` interface 99*61c4878aSAndroid Build Coastguard Workeris defined (``pw_transfer/public/pw_transfer/handler.h``). Transfer handlers 100*61c4878aSAndroid Build Coastguard Workerrepresent a transferable resource, wrapping a stream reader and/or writer with 101*61c4878aSAndroid Build Coastguard Workerinitialization and completion code. Custom transfer handler implementations 102*61c4878aSAndroid Build Coastguard Workershould derive from ``ReadOnlyHandler``, ``WriteOnlyHandler``, or 103*61c4878aSAndroid Build Coastguard Worker``ReadWriteHandler`` as appropriate and override Prepare and Finalize methods 104*61c4878aSAndroid Build Coastguard Workerif necessary. 105*61c4878aSAndroid Build Coastguard Worker 106*61c4878aSAndroid Build Coastguard WorkerA transfer handler should be implemented and instantiated for each unique 107*61c4878aSAndroid Build Coastguard Workerresource that can be transferred to or from a device. Each instantiated handler 108*61c4878aSAndroid Build Coastguard Workermust have a globally-unique integer ID used to identify the resource. 109*61c4878aSAndroid Build Coastguard Worker 110*61c4878aSAndroid Build Coastguard WorkerHandlers are registered with the transfer service. This may be done during 111*61c4878aSAndroid Build Coastguard Workersystem initialization (for static resources), or dynamically at runtime to 112*61c4878aSAndroid Build Coastguard Workersupport ephemeral transfer resources. A boolean is returned with registration/ 113*61c4878aSAndroid Build Coastguard Workerunregistration to indicate success or failure. 114*61c4878aSAndroid Build Coastguard Worker 115*61c4878aSAndroid Build Coastguard Worker**Example transfer handler implementation** 116*61c4878aSAndroid Build Coastguard Worker 117*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 118*61c4878aSAndroid Build Coastguard Worker 119*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/memory_stream.h" 120*61c4878aSAndroid Build Coastguard Worker #include "pw_transfer/transfer.h" 121*61c4878aSAndroid Build Coastguard Worker 122*61c4878aSAndroid Build Coastguard Worker // A simple transfer handler which reads data from an in-memory buffer. 123*61c4878aSAndroid Build Coastguard Worker class SimpleBufferReadHandler : public pw::transfer::ReadOnlyHandler { 124*61c4878aSAndroid Build Coastguard Worker public: 125*61c4878aSAndroid Build Coastguard Worker SimpleReadTransfer(uint32_t resource_id, pw::ConstByteSpan data) 126*61c4878aSAndroid Build Coastguard Worker : ReadOnlyHandler(resource_id), reader_(data) { 127*61c4878aSAndroid Build Coastguard Worker set_reader(reader_); 128*61c4878aSAndroid Build Coastguard Worker } 129*61c4878aSAndroid Build Coastguard Worker 130*61c4878aSAndroid Build Coastguard Worker private: 131*61c4878aSAndroid Build Coastguard Worker pw::stream::MemoryReader reader_; 132*61c4878aSAndroid Build Coastguard Worker }; 133*61c4878aSAndroid Build Coastguard Worker 134*61c4878aSAndroid Build Coastguard WorkerHandlers may optionally implement a `GetStatus` method, which allows clients to 135*61c4878aSAndroid Build Coastguard Workerquery the status of a resource with a handler registered. The application layer 136*61c4878aSAndroid Build Coastguard Workerabove transfer can choose how to fill and interpret this information. The status 137*61c4878aSAndroid Build Coastguard Workerinformation is `readable_offset`, `writeable_offset`, `read_checksum`, and 138*61c4878aSAndroid Build Coastguard Worker`write_checksum`. 139*61c4878aSAndroid Build Coastguard Worker 140*61c4878aSAndroid Build Coastguard Worker**Example GetStatus implementation** 141*61c4878aSAndroid Build Coastguard Worker 142*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 143*61c4878aSAndroid Build Coastguard Worker 144*61c4878aSAndroid Build Coastguard Worker Status GetStatus(uint64_t& readable_offset, 145*61c4878aSAndroid Build Coastguard Worker uint64_t& writeable_offset, 146*61c4878aSAndroid Build Coastguard Worker uint64_t& read_checksum, 147*61c4878aSAndroid Build Coastguard Worker uint64_t& write_checksum) { 148*61c4878aSAndroid Build Coastguard Worker readable_offset = resource.get_size(); 149*61c4878aSAndroid Build Coastguard Worker writeable_offset = resource.get_writeable_offset(); 150*61c4878aSAndroid Build Coastguard Worker read_checksum = resource.get_crc(); 151*61c4878aSAndroid Build Coastguard Worker write_checksum = resource.calculate_crc(0, writeable_offset); 152*61c4878aSAndroid Build Coastguard Worker 153*61c4878aSAndroid Build Coastguard Worker return pw::OkStatus(); 154*61c4878aSAndroid Build Coastguard Worker } 155*61c4878aSAndroid Build Coastguard Worker 156*61c4878aSAndroid Build Coastguard WorkerThe transfer service is instantiated with a reference to the system's transfer 157*61c4878aSAndroid Build Coastguard Workerthread and registered with the system's RPC server. 158*61c4878aSAndroid Build Coastguard Worker 159*61c4878aSAndroid Build Coastguard Worker**Example transfer service initialization** 160*61c4878aSAndroid Build Coastguard Worker 161*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 162*61c4878aSAndroid Build Coastguard Worker 163*61c4878aSAndroid Build Coastguard Worker #include "pw_transfer/transfer.h" 164*61c4878aSAndroid Build Coastguard Worker 165*61c4878aSAndroid Build Coastguard Worker namespace { 166*61c4878aSAndroid Build Coastguard Worker 167*61c4878aSAndroid Build Coastguard Worker // In a write transfer, the maximum number of bytes to receive at one time 168*61c4878aSAndroid Build Coastguard Worker // (potentially across multiple chunks), unless specified otherwise by the 169*61c4878aSAndroid Build Coastguard Worker // transfer handler's stream::Writer. Should be set reasonably high; the 170*61c4878aSAndroid Build Coastguard Worker // transfer will attempt to determine an optimal window size based on the 171*61c4878aSAndroid Build Coastguard Worker // link. 172*61c4878aSAndroid Build Coastguard Worker constexpr size_t kDefaultMaxBytesToReceive = 16384; 173*61c4878aSAndroid Build Coastguard Worker 174*61c4878aSAndroid Build Coastguard Worker pw::transfer::TransferService transfer_service( 175*61c4878aSAndroid Build Coastguard Worker GetSystemTransferThread(), kDefaultMaxBytesToReceive); 176*61c4878aSAndroid Build Coastguard Worker 177*61c4878aSAndroid Build Coastguard Worker // Instantiate a handler for the data to be transferred. The resource ID will 178*61c4878aSAndroid Build Coastguard Worker // be used by the transfer client and server to identify the handler. 179*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t kMagicBufferResourceId = 1; 180*61c4878aSAndroid Build Coastguard Worker char magic_buffer_to_transfer[256] = { /* ... */ }; 181*61c4878aSAndroid Build Coastguard Worker SimpleBufferReadHandler magic_buffer_handler( 182*61c4878aSAndroid Build Coastguard Worker kMagicBufferResourceId, magic_buffer_to_transfer); 183*61c4878aSAndroid Build Coastguard Worker 184*61c4878aSAndroid Build Coastguard Worker } // namespace 185*61c4878aSAndroid Build Coastguard Worker 186*61c4878aSAndroid Build Coastguard Worker void InitTransferService() { 187*61c4878aSAndroid Build Coastguard Worker // Register the handler with the transfer service, then the transfer service 188*61c4878aSAndroid Build Coastguard Worker // with an RPC server. 189*61c4878aSAndroid Build Coastguard Worker bool success = transfer_service.RegisterHandler(magic_buffer_handler); 190*61c4878aSAndroid Build Coastguard Worker GetSystemRpcServer().RegisterService(transfer_service); 191*61c4878aSAndroid Build Coastguard Worker } 192*61c4878aSAndroid Build Coastguard Worker 193*61c4878aSAndroid Build Coastguard WorkerTransfer client 194*61c4878aSAndroid Build Coastguard Worker--------------- 195*61c4878aSAndroid Build Coastguard Worker``pw_transfer`` provides a transfer client capable of running transfers through 196*61c4878aSAndroid Build Coastguard Workeran RPC client. 197*61c4878aSAndroid Build Coastguard Worker 198*61c4878aSAndroid Build Coastguard Worker.. note:: 199*61c4878aSAndroid Build Coastguard Worker 200*61c4878aSAndroid Build Coastguard Worker Currently, a transfer client is only capable of running transfers on a single 201*61c4878aSAndroid Build Coastguard Worker RPC channel. This may be expanded in the future. 202*61c4878aSAndroid Build Coastguard Worker 203*61c4878aSAndroid Build Coastguard WorkerThe transfer client provides the following APIs for managing data transfers: 204*61c4878aSAndroid Build Coastguard Worker 205*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<pw::Transfer::Client::Handle> pw::transfer::Client::Read(uint32_t resource_id, pw::stream::Writer& output, CompletionFunc&& on_completion, pw::transfer::ProtocolVersion version = kDefaultProtocolVersion, pw::chrono::SystemClock::duration timeout = cfg::kDefaultClientTimeout, pw::chrono::SystemClock::duration initial_chunk_timeout = cfg::kDefaultInitialChunkTimeout, uint32_t initial_offset = 0u) 206*61c4878aSAndroid Build Coastguard Worker 207*61c4878aSAndroid Build Coastguard Worker Reads data from a transfer server to the specified ``pw::stream::Writer``. 208*61c4878aSAndroid Build Coastguard Worker Invokes the provided callback function with the overall status of the 209*61c4878aSAndroid Build Coastguard Worker transfer. 210*61c4878aSAndroid Build Coastguard Worker 211*61c4878aSAndroid Build Coastguard Worker Due to the asynchronous nature of transfer operations, this function will only 212*61c4878aSAndroid Build Coastguard Worker return a non-OK status if it is called with bad arguments. Otherwise, it will 213*61c4878aSAndroid Build Coastguard Worker return OK and errors will be reported through the completion callback. 214*61c4878aSAndroid Build Coastguard Worker 215*61c4878aSAndroid Build Coastguard Worker For using the offset parameter, please see :ref:`pw_transfer-nonzero-transfers`. 216*61c4878aSAndroid Build Coastguard Worker 217*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: Result<pw::Transfer::Client::Handle> pw::transfer::Client::Write(uint32_t resource_id, pw::stream::Reader& input, CompletionFunc&& on_completion, pw::transfer::ProtocolVersion version = kDefaultProtocolVersion, pw::chrono::SystemClock::duration timeout = cfg::kDefaultClientTimeout, pw::chrono::SystemClock::duration initial_chunk_timeout = cfg::kDefaultInitialChunkTimeout, uint32_t initial_offset = 0u) 218*61c4878aSAndroid Build Coastguard Worker 219*61c4878aSAndroid Build Coastguard Worker Writes data from a source ``pw::stream::Reader`` to a transfer server. 220*61c4878aSAndroid Build Coastguard Worker Invokes the provided callback function with the overall status of the 221*61c4878aSAndroid Build Coastguard Worker transfer. 222*61c4878aSAndroid Build Coastguard Worker 223*61c4878aSAndroid Build Coastguard Worker Due to the asynchronous nature of transfer operations, this function will only 224*61c4878aSAndroid Build Coastguard Worker return a non-OK status if it is called with bad arguments. Otherwise, it will 225*61c4878aSAndroid Build Coastguard Worker return OK and errors will be reported through the completion callback. 226*61c4878aSAndroid Build Coastguard Worker 227*61c4878aSAndroid Build Coastguard Worker For using the offset parameter, please see :ref:`pw_transfer-nonzero-transfers`. 228*61c4878aSAndroid Build Coastguard Worker 229*61c4878aSAndroid Build Coastguard WorkerTransfer handles 230*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^ 231*61c4878aSAndroid Build Coastguard WorkerEach transfer session initiated by a client returns a ``Handle`` object which 232*61c4878aSAndroid Build Coastguard Workeris used to manage the transfer. These handles support the following operations: 233*61c4878aSAndroid Build Coastguard Worker 234*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: pw::Transfer::Client::Handle::Cancel() 235*61c4878aSAndroid Build Coastguard Worker 236*61c4878aSAndroid Build Coastguard Worker Terminates the ongoing transfer. 237*61c4878aSAndroid Build Coastguard Worker 238*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: pw::Transfer::Client::Handle::SetTransferSize(size_t size_bytes) 239*61c4878aSAndroid Build Coastguard Worker 240*61c4878aSAndroid Build Coastguard Worker In a write transfer, indicates the total size of the transfer resource. 241*61c4878aSAndroid Build Coastguard Worker 242*61c4878aSAndroid Build Coastguard Worker**Example client setup** 243*61c4878aSAndroid Build Coastguard Worker 244*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 245*61c4878aSAndroid Build Coastguard Worker 246*61c4878aSAndroid Build Coastguard Worker #include "pw_transfer/client.h" 247*61c4878aSAndroid Build Coastguard Worker 248*61c4878aSAndroid Build Coastguard Worker namespace { 249*61c4878aSAndroid Build Coastguard Worker 250*61c4878aSAndroid Build Coastguard Worker // RPC channel on which transfers should be run. 251*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t kChannelId = 42; 252*61c4878aSAndroid Build Coastguard Worker 253*61c4878aSAndroid Build Coastguard Worker // In a read transfer, the maximum number of bytes to receive at one time 254*61c4878aSAndroid Build Coastguard Worker // (potentially across multiple chunks), unless specified otherwise by the 255*61c4878aSAndroid Build Coastguard Worker // transfer's stream. Should be set reasonably high; the transfer will 256*61c4878aSAndroid Build Coastguard Worker // attempt to determine an optimal window size based on the link. 257*61c4878aSAndroid Build Coastguard Worker constexpr size_t kDefaultMaxBytesToReceive = 16384; 258*61c4878aSAndroid Build Coastguard Worker 259*61c4878aSAndroid Build Coastguard Worker pw::transfer::Client transfer_client(GetSystemRpcClient(), 260*61c4878aSAndroid Build Coastguard Worker kChannelId, 261*61c4878aSAndroid Build Coastguard Worker GetSystemTransferThread(), 262*61c4878aSAndroid Build Coastguard Worker kDefaultMaxBytesToReceive); 263*61c4878aSAndroid Build Coastguard Worker 264*61c4878aSAndroid Build Coastguard Worker } // namespace 265*61c4878aSAndroid Build Coastguard Worker 266*61c4878aSAndroid Build Coastguard Worker Status ReadMagicBufferSync(pw::ByteSpan sink) { 267*61c4878aSAndroid Build Coastguard Worker pw::stream::Writer writer(sink); 268*61c4878aSAndroid Build Coastguard Worker 269*61c4878aSAndroid Build Coastguard Worker struct { 270*61c4878aSAndroid Build Coastguard Worker pw::sync::ThreadNotification notification; 271*61c4878aSAndroid Build Coastguard Worker pw::Status status; 272*61c4878aSAndroid Build Coastguard Worker } transfer_state; 273*61c4878aSAndroid Build Coastguard Worker 274*61c4878aSAndroid Build Coastguard Worker Result<pw::transfer::Client::Handle> handle = transfer_client.Read( 275*61c4878aSAndroid Build Coastguard Worker kMagicBufferResourceId, 276*61c4878aSAndroid Build Coastguard Worker writer, 277*61c4878aSAndroid Build Coastguard Worker [&transfer_state](pw::Status status) { 278*61c4878aSAndroid Build Coastguard Worker transfer_state.status = status; 279*61c4878aSAndroid Build Coastguard Worker transfer_state.notification.release(); 280*61c4878aSAndroid Build Coastguard Worker }); 281*61c4878aSAndroid Build Coastguard Worker if (!handle.ok()) { 282*61c4878aSAndroid Build Coastguard Worker return handle.status(); 283*61c4878aSAndroid Build Coastguard Worker } 284*61c4878aSAndroid Build Coastguard Worker 285*61c4878aSAndroid Build Coastguard Worker // Block until the transfer completes. 286*61c4878aSAndroid Build Coastguard Worker transfer_state.notification.acquire(); 287*61c4878aSAndroid Build Coastguard Worker return transfer_state.status; 288*61c4878aSAndroid Build Coastguard Worker } 289*61c4878aSAndroid Build Coastguard Worker 290*61c4878aSAndroid Build Coastguard WorkerSpecifying Resource Sizes 291*61c4878aSAndroid Build Coastguard Worker------------------------- 292*61c4878aSAndroid Build Coastguard WorkerTransfer data is sent and received through the ``pw::Stream`` interface, which 293*61c4878aSAndroid Build Coastguard Workerdoes not have a concept of overall stream size. Users of transfers that are 294*61c4878aSAndroid Build Coastguard Workerfixed-size may optionally indicate this to the transfer client and server, 295*61c4878aSAndroid Build Coastguard Workerwhich will be shared with the transfer peer to enable features such as progress 296*61c4878aSAndroid Build Coastguard Workerreporting. 297*61c4878aSAndroid Build Coastguard Worker 298*61c4878aSAndroid Build Coastguard WorkerThe transfer size can only be set on the transmitting side of the transfer; 299*61c4878aSAndroid Build Coastguard Workerthat is, the client in a ``Write`` transfer or the server in a ``Read`` 300*61c4878aSAndroid Build Coastguard Workertransfer. 301*61c4878aSAndroid Build Coastguard Worker 302*61c4878aSAndroid Build Coastguard WorkerIf the specified resource size is smaller than the available transferrable data, 303*61c4878aSAndroid Build Coastguard Workeronly a slice of the data up to the resource size will be transferred. If the 304*61c4878aSAndroid Build Coastguard Workerspecified size is equal to or larger than the data size, all of the data will 305*61c4878aSAndroid Build Coastguard Workerbe sent. 306*61c4878aSAndroid Build Coastguard Worker 307*61c4878aSAndroid Build Coastguard Worker**Setting a transfer size from a transmitting client** 308*61c4878aSAndroid Build Coastguard Worker 309*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 310*61c4878aSAndroid Build Coastguard Worker 311*61c4878aSAndroid Build Coastguard Worker Result<pw::transfer::Client::Handle> handle = client.Write(...); 312*61c4878aSAndroid Build Coastguard Worker if (handle.ok()) { 313*61c4878aSAndroid Build Coastguard Worker handle->SetTransferSize(kMyResourceSize); 314*61c4878aSAndroid Build Coastguard Worker } 315*61c4878aSAndroid Build Coastguard Worker 316*61c4878aSAndroid Build Coastguard Worker**Setting a transfer size on a server resource** 317*61c4878aSAndroid Build Coastguard Worker 318*61c4878aSAndroid Build Coastguard Worker The ``TransferHandler`` interface allows overriding its ``ResourceSize`` 319*61c4878aSAndroid Build Coastguard Worker function to return the size of its transfer resource. 320*61c4878aSAndroid Build Coastguard Worker 321*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 322*61c4878aSAndroid Build Coastguard Worker 323*61c4878aSAndroid Build Coastguard Worker class MyResourceHandler : public pw::transfer::ReadOnlyHandler { 324*61c4878aSAndroid Build Coastguard Worker public: 325*61c4878aSAndroid Build Coastguard Worker Status PrepareRead() final; 326*61c4878aSAndroid Build Coastguard Worker 327*61c4878aSAndroid Build Coastguard Worker virtual size_t ResourceSize() const final { 328*61c4878aSAndroid Build Coastguard Worker return kMyResourceSize; 329*61c4878aSAndroid Build Coastguard Worker } 330*61c4878aSAndroid Build Coastguard Worker 331*61c4878aSAndroid Build Coastguard Worker }; 332*61c4878aSAndroid Build Coastguard Worker 333*61c4878aSAndroid Build Coastguard WorkerAtomic File Transfer Handler 334*61c4878aSAndroid Build Coastguard Worker---------------------------- 335*61c4878aSAndroid Build Coastguard WorkerTransfers are handled using the generic `Handler` interface. A specialized 336*61c4878aSAndroid Build Coastguard Worker`Handler`, `AtomicFileTransferHandler` is available to handle file transfers 337*61c4878aSAndroid Build Coastguard Workerwith atomic semantics. It guarantees that the target file of the transfer is 338*61c4878aSAndroid Build Coastguard Workeralways in a correct state. A temporary file is written to prior to updating the 339*61c4878aSAndroid Build Coastguard Workertarget file. If any transfer failure occurs, the transfer is aborted and the 340*61c4878aSAndroid Build Coastguard Workertarget file is either not created or not updated. 341*61c4878aSAndroid Build Coastguard Worker 342*61c4878aSAndroid Build Coastguard Worker.. _module-pw_transfer-config: 343*61c4878aSAndroid Build Coastguard Worker 344*61c4878aSAndroid Build Coastguard WorkerModule Configuration Options 345*61c4878aSAndroid Build Coastguard Worker---------------------------- 346*61c4878aSAndroid Build Coastguard WorkerThe following configurations can be adjusted via compile-time configuration of 347*61c4878aSAndroid Build Coastguard Workerthis module, see the 348*61c4878aSAndroid Build Coastguard Worker:ref:`module documentation <module-structure-compile-time-configuration>` for 349*61c4878aSAndroid Build Coastguard Workermore details. 350*61c4878aSAndroid Build Coastguard Worker 351*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_DEFAULT_MAX_CLIENT_RETRIES 352*61c4878aSAndroid Build Coastguard Worker 353*61c4878aSAndroid Build Coastguard Worker The default maximum number of times a transfer client should retry sending a 354*61c4878aSAndroid Build Coastguard Worker chunk when no response is received. Can later be configured per-transfer when 355*61c4878aSAndroid Build Coastguard Worker starting one. 356*61c4878aSAndroid Build Coastguard Worker 357*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_DEFAULT_MAX_SERVER_RETRIES 358*61c4878aSAndroid Build Coastguard Worker 359*61c4878aSAndroid Build Coastguard Worker The default maximum number of times a transfer server should retry sending a 360*61c4878aSAndroid Build Coastguard Worker chunk when no response is received. 361*61c4878aSAndroid Build Coastguard Worker 362*61c4878aSAndroid Build Coastguard Worker In typical setups, retries are driven by the client, and timeouts on the 363*61c4878aSAndroid Build Coastguard Worker server are used only to clean up resources, so this defaults to 0. 364*61c4878aSAndroid Build Coastguard Worker 365*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_DEFAULT_MAX_LIFETIME_RETRIES 366*61c4878aSAndroid Build Coastguard Worker 367*61c4878aSAndroid Build Coastguard Worker The default maximum number of times a transfer should retry sending any chunk 368*61c4878aSAndroid Build Coastguard Worker over the course of its entire lifetime. 369*61c4878aSAndroid Build Coastguard Worker 370*61c4878aSAndroid Build Coastguard Worker This number should be high, particularly if long-running transfers are 371*61c4878aSAndroid Build Coastguard Worker expected. Its purpose is to prevent transfers from getting stuck in an 372*61c4878aSAndroid Build Coastguard Worker infinite loop. 373*61c4878aSAndroid Build Coastguard Worker 374*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS 375*61c4878aSAndroid Build Coastguard Worker 376*61c4878aSAndroid Build Coastguard Worker The default amount of time, in milliseconds, to wait for a chunk to arrive 377*61c4878aSAndroid Build Coastguard Worker in a transfer client before retrying. This can later be configured 378*61c4878aSAndroid Build Coastguard Worker per-transfer. 379*61c4878aSAndroid Build Coastguard Worker 380*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_DEFAULT_SERVER_TIMEOUT_MS 381*61c4878aSAndroid Build Coastguard Worker 382*61c4878aSAndroid Build Coastguard Worker The default amount of time, in milliseconds, to wait for a chunk to arrive 383*61c4878aSAndroid Build Coastguard Worker on the server before retrying. This can later be configured per-transfer. 384*61c4878aSAndroid Build Coastguard Worker 385*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_DEFAULT_INITIAL_TIMEOUT_MS 386*61c4878aSAndroid Build Coastguard Worker 387*61c4878aSAndroid Build Coastguard Worker The default amount of time, in milliseconds, to wait for an initial server 388*61c4878aSAndroid Build Coastguard Worker response to a transfer before retrying. This can later be configured 389*61c4878aSAndroid Build Coastguard Worker per-transfer. 390*61c4878aSAndroid Build Coastguard Worker 391*61c4878aSAndroid Build Coastguard Worker This is set separately to PW_TRANSFER_DEFAULT_TIMEOUT_MS as transfers may 392*61c4878aSAndroid Build Coastguard Worker require additional time for resource initialization (e.g. erasing a flash 393*61c4878aSAndroid Build Coastguard Worker region before writing to it). 394*61c4878aSAndroid Build Coastguard Worker 395*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_DEFAULT_EXTEND_WINDOW_DIVISOR 396*61c4878aSAndroid Build Coastguard Worker 397*61c4878aSAndroid Build Coastguard Worker The fractional position within a window at which a receive transfer should 398*61c4878aSAndroid Build Coastguard Worker extend its window size to minimize the amount of time the transmitter 399*61c4878aSAndroid Build Coastguard Worker spends blocked. 400*61c4878aSAndroid Build Coastguard Worker 401*61c4878aSAndroid Build Coastguard Worker For example, a divisor of 2 will extend the window when half of the 402*61c4878aSAndroid Build Coastguard Worker requested data has been received, a divisor of three will extend at a third 403*61c4878aSAndroid Build Coastguard Worker of the window, and so on. 404*61c4878aSAndroid Build Coastguard Worker 405*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_LOG_DEFAULT_CHUNKS_BEFORE_RATE_LIMIT 406*61c4878aSAndroid Build Coastguard Worker 407*61c4878aSAndroid Build Coastguard Worker Number of chunks to send repetitive logs at full rate before reducing to 408*61c4878aSAndroid Build Coastguard Worker rate_limit. Retransmit parameter chunks will restart at this chunk count 409*61c4878aSAndroid Build Coastguard Worker limit. 410*61c4878aSAndroid Build Coastguard Worker Default is first 10 parameter logs will be sent, then reduced to one log 411*61c4878aSAndroid Build Coastguard Worker every ``PW_TRANSFER_RATE_PERIOD_MS`` 412*61c4878aSAndroid Build Coastguard Worker 413*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_LOG_DEFAULT_RATE_PERIOD_MS 414*61c4878aSAndroid Build Coastguard Worker 415*61c4878aSAndroid Build Coastguard Worker The minimum time between repetative logs after the rate limit has been 416*61c4878aSAndroid Build Coastguard Worker applied (after CHUNKS_BEFORE_RATE_LIMIT parameter chunks). 417*61c4878aSAndroid Build Coastguard Worker Default is to reduce repetative logs to once every 10 seconds after 418*61c4878aSAndroid Build Coastguard Worker CHUNKS_BEFORE_RATE_LIMIT parameter chunks have been sent. 419*61c4878aSAndroid Build Coastguard Worker 420*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_CONFIG_LOG_LEVEL 421*61c4878aSAndroid Build Coastguard Worker 422*61c4878aSAndroid Build Coastguard Worker Configurable log level for the entire transfer module. 423*61c4878aSAndroid Build Coastguard Worker 424*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_CONFIG_DEBUG_CHUNKS 425*61c4878aSAndroid Build Coastguard Worker 426*61c4878aSAndroid Build Coastguard Worker Turns on logging of individual non-data or non-parameter chunks. Default is 427*61c4878aSAndroid Build Coastguard Worker false, to disable logging. 428*61c4878aSAndroid Build Coastguard Worker 429*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_CONFIG_DEBUG_DATA_CHUNKS 430*61c4878aSAndroid Build Coastguard Worker 431*61c4878aSAndroid Build Coastguard Worker Turns on logging of individual data and parameter chunks. Default is false to 432*61c4878aSAndroid Build Coastguard Worker disable logging. These chunks are moderated (rate-limited) by the same 433*61c4878aSAndroid Build Coastguard Worker ``PW_TRANSFER_RATE_PERIOD_MS`` as other repetitive logs. 434*61c4878aSAndroid Build Coastguard Worker 435*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_TRANSFER_EVENT_PROCESSING_TIMEOUT_MS 436*61c4878aSAndroid Build Coastguard Worker 437*61c4878aSAndroid Build Coastguard Worker Maximum time to wait for a transfer event to be processed before dropping 438*61c4878aSAndroid Build Coastguard Worker further queued events. In systems which can perform long-running operations 439*61c4878aSAndroid Build Coastguard Worker to process transfer data, this can be used to prevent threads from blocking 440*61c4878aSAndroid Build Coastguard Worker for extended periods. A value of 0 results in indefinite blocking. 441*61c4878aSAndroid Build Coastguard Worker 442*61c4878aSAndroid Build Coastguard Worker.. _pw_transfer-nonzero-transfers: 443*61c4878aSAndroid Build Coastguard Worker 444*61c4878aSAndroid Build Coastguard WorkerNon-zero Starting Offset Transfers 445*61c4878aSAndroid Build Coastguard Worker---------------------------------- 446*61c4878aSAndroid Build Coastguard Worker``pw_transfer`` provides for transfers which read from or 447*61c4878aSAndroid Build Coastguard Workerwrite to a server resource starting from a point after the beginning. 448*61c4878aSAndroid Build Coastguard WorkerHandling of read/write/erase boundaries of the resource storage backend must 449*61c4878aSAndroid Build Coastguard Workerbe handled by the user through the transfer handler interfaces of `GetStatus` 450*61c4878aSAndroid Build Coastguard Workerand `PrepareRead/Write(uint32_t offset)`. 451*61c4878aSAndroid Build Coastguard Worker 452*61c4878aSAndroid Build Coastguard WorkerA resource can be read or written from a non-zero starting offset simply by 453*61c4878aSAndroid Build Coastguard Workerhaving the transfer client calling `read()` or `write()` with an offset 454*61c4878aSAndroid Build Coastguard Workerparameter. The offset gets included in the starting handshake. 455*61c4878aSAndroid Build Coastguard Worker 456*61c4878aSAndroid Build Coastguard Worker.. note:: 457*61c4878aSAndroid Build Coastguard Worker The data or stream passed to `read()` or `write()` will be used as-is. I.e. 458*61c4878aSAndroid Build Coastguard Worker no seeking will be applied; the user is expected to seek to the desired 459*61c4878aSAndroid Build Coastguard Worker location. 460*61c4878aSAndroid Build Coastguard Worker 461*61c4878aSAndroid Build Coastguard WorkerOn the server side, the offset is accepted, and passed to the transfer 462*61c4878aSAndroid Build Coastguard Workerhandler's `Prepare(uint32_t)` method. This method must be implemented 463*61c4878aSAndroid Build Coastguard Workerspecifically by the handler in order to support the offset transfer. The 464*61c4878aSAndroid Build Coastguard Workertransfer handler confirms that the start offset is valid for the read/write 465*61c4878aSAndroid Build Coastguard Workeroperation, and the server responds with the offset to confirm the non-zero 466*61c4878aSAndroid Build Coastguard Workertransfer operation. Older server sw will ignore the offset, so the clients 467*61c4878aSAndroid Build Coastguard Workercheck that the server has accepted the non-zero offset during the handshake, so 468*61c4878aSAndroid Build Coastguard Workerusers may elect to catch such errors. Clients return `Status.UNIMPLEMENTED` in 469*61c4878aSAndroid Build Coastguard Workersuch cases. 470*61c4878aSAndroid Build Coastguard Worker 471*61c4878aSAndroid Build Coastguard WorkerDue to the need to seek streams by the handler to support the non-zero offset, 472*61c4878aSAndroid Build Coastguard Workerit is recommended to return `Status.RESOURCE_EXHAUSTED` if a seek is requested 473*61c4878aSAndroid Build Coastguard Workerpast the end of the stream. 474*61c4878aSAndroid Build Coastguard Worker 475*61c4878aSAndroid Build Coastguard WorkerSee the :ref:`transfer handler <pw_transfer-transfer-server>` documentation for 476*61c4878aSAndroid Build Coastguard Workerfurther information about configuring resources for non-zero transfers and the 477*61c4878aSAndroid Build Coastguard Workerinterface documentation in 478*61c4878aSAndroid Build Coastguard Worker``pw/transfer/public/pw_transfer/handler.h`` 479*61c4878aSAndroid Build Coastguard Worker 480*61c4878aSAndroid Build Coastguard WorkerPython 481*61c4878aSAndroid Build Coastguard Worker====== 482*61c4878aSAndroid Build Coastguard Worker.. automodule:: pw_transfer 483*61c4878aSAndroid Build Coastguard Worker :members: ProgressStats, ProtocolVersion, Manager, Error 484*61c4878aSAndroid Build Coastguard Worker 485*61c4878aSAndroid Build Coastguard Worker**Example** 486*61c4878aSAndroid Build Coastguard Worker 487*61c4878aSAndroid Build Coastguard Worker.. code-block:: python 488*61c4878aSAndroid Build Coastguard Worker 489*61c4878aSAndroid Build Coastguard Worker import pw_transfer 490*61c4878aSAndroid Build Coastguard Worker 491*61c4878aSAndroid Build Coastguard Worker # Initialize a Pigweed RPC client; see pw_rpc docs for more info. 492*61c4878aSAndroid Build Coastguard Worker rpc_client = CustomRpcClient() 493*61c4878aSAndroid Build Coastguard Worker rpcs = rpc_client.channel(1).rpcs 494*61c4878aSAndroid Build Coastguard Worker 495*61c4878aSAndroid Build Coastguard Worker transfer_service = rpcs.pw.transfer.Transfer 496*61c4878aSAndroid Build Coastguard Worker transfer_manager = pw_transfer.Manager(transfer_service) 497*61c4878aSAndroid Build Coastguard Worker 498*61c4878aSAndroid Build Coastguard Worker try: 499*61c4878aSAndroid Build Coastguard Worker # Read the transfer resource with ID 3 from the server. 500*61c4878aSAndroid Build Coastguard Worker data = transfer_manager.read(3) 501*61c4878aSAndroid Build Coastguard Worker except pw_transfer.Error as err: 502*61c4878aSAndroid Build Coastguard Worker print('Failed to read:', err.status) 503*61c4878aSAndroid Build Coastguard Worker 504*61c4878aSAndroid Build Coastguard Worker try: 505*61c4878aSAndroid Build Coastguard Worker # Send some data to the server. The transfer manager does not have to be 506*61c4878aSAndroid Build Coastguard Worker # reinitialized. 507*61c4878aSAndroid Build Coastguard Worker transfer_manager.write(2, b'hello, world') 508*61c4878aSAndroid Build Coastguard Worker except pw_transfer.Error as err: 509*61c4878aSAndroid Build Coastguard Worker print('Failed to write:', err.status) 510*61c4878aSAndroid Build Coastguard Worker 511*61c4878aSAndroid Build Coastguard WorkerTypescript 512*61c4878aSAndroid Build Coastguard Worker========== 513*61c4878aSAndroid Build Coastguard WorkerProvides a simple interface for transferring bulk data over pw_rpc. 514*61c4878aSAndroid Build Coastguard Worker 515*61c4878aSAndroid Build Coastguard Worker**Example** 516*61c4878aSAndroid Build Coastguard Worker 517*61c4878aSAndroid Build Coastguard Worker.. code-block:: typescript 518*61c4878aSAndroid Build Coastguard Worker 519*61c4878aSAndroid Build Coastguard Worker import { pw_transfer } from 'pigweedjs'; 520*61c4878aSAndroid Build Coastguard Worker const { Manager } from pw_transfer; 521*61c4878aSAndroid Build Coastguard Worker 522*61c4878aSAndroid Build Coastguard Worker const client = new CustomRpcClient(); 523*61c4878aSAndroid Build Coastguard Worker service = client.channel()!.service('pw.transfer.Transfer')!; 524*61c4878aSAndroid Build Coastguard Worker 525*61c4878aSAndroid Build Coastguard Worker const manager = new Manager(service, DEFAULT_TIMEOUT_S); 526*61c4878aSAndroid Build Coastguard Worker 527*61c4878aSAndroid Build Coastguard Worker manager.read(3, (stats: ProgressStats) => { 528*61c4878aSAndroid Build Coastguard Worker console.log(`Progress Update: ${stats}`); 529*61c4878aSAndroid Build Coastguard Worker }).then((data: Uint8Array) => { 530*61c4878aSAndroid Build Coastguard Worker console.log(`Completed read: ${data}`); 531*61c4878aSAndroid Build Coastguard Worker }).catch(error => { 532*61c4878aSAndroid Build Coastguard Worker console.log(`Failed to read: ${error.status}`); 533*61c4878aSAndroid Build Coastguard Worker }); 534*61c4878aSAndroid Build Coastguard Worker 535*61c4878aSAndroid Build Coastguard Worker manager.write(2, textEncoder.encode('hello world')) 536*61c4878aSAndroid Build Coastguard Worker .catch(error => { 537*61c4878aSAndroid Build Coastguard Worker console.log(`Failed to read: ${error.status}`); 538*61c4878aSAndroid Build Coastguard Worker }); 539*61c4878aSAndroid Build Coastguard Worker 540*61c4878aSAndroid Build Coastguard WorkerJava 541*61c4878aSAndroid Build Coastguard Worker==== 542*61c4878aSAndroid Build Coastguard Workerpw_transfer provides a Java client. The transfer client returns a 543*61c4878aSAndroid Build Coastguard Worker`ListenableFuture <https://guava.dev/releases/21.0/api/docs/com/google/common/util/concurrent/ListenableFuture>`_ 544*61c4878aSAndroid Build Coastguard Workerto represent the results of a read or write transfer. 545*61c4878aSAndroid Build Coastguard Worker 546*61c4878aSAndroid Build Coastguard Worker.. code-block:: java 547*61c4878aSAndroid Build Coastguard Worker 548*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_transfer.TransferClient; 549*61c4878aSAndroid Build Coastguard Worker 550*61c4878aSAndroid Build Coastguard Worker public class TheClass { 551*61c4878aSAndroid Build Coastguard Worker public void DoTransfer(MethodClient transferReadMethodClient, 552*61c4878aSAndroid Build Coastguard Worker MethodClient transferWriteMethodClient) { 553*61c4878aSAndroid Build Coastguard Worker // Create a new transfer client. 554*61c4878aSAndroid Build Coastguard Worker TransferClient client = new TransferClient( 555*61c4878aSAndroid Build Coastguard Worker transferReadMethodClient, 556*61c4878aSAndroid Build Coastguard Worker transferWriteMethodClient, 557*61c4878aSAndroid Build Coastguard Worker TransferTimeoutSettings.builder() 558*61c4878aSAndroid Build Coastguard Worker .setTimeoutMillis(TRANSFER_TIMEOUT_MS) 559*61c4878aSAndroid Build Coastguard Worker .setMaxRetries(MAX_RETRIES) 560*61c4878aSAndroid Build Coastguard Worker .build()); 561*61c4878aSAndroid Build Coastguard Worker 562*61c4878aSAndroid Build Coastguard Worker // Start a read transfer. 563*61c4878aSAndroid Build Coastguard Worker ListenableFuture<byte[]> readTransfer = client.read(123); 564*61c4878aSAndroid Build Coastguard Worker 565*61c4878aSAndroid Build Coastguard Worker // Start a write transfer. 566*61c4878aSAndroid Build Coastguard Worker ListenableFuture<Void> writeTransfer = client.write(123, dataToWrite); 567*61c4878aSAndroid Build Coastguard Worker 568*61c4878aSAndroid Build Coastguard Worker // Get the data from the read transfer. 569*61c4878aSAndroid Build Coastguard Worker byte[] readData = readTransfer.get(); 570*61c4878aSAndroid Build Coastguard Worker 571*61c4878aSAndroid Build Coastguard Worker // Wait for the write transfer to complete. 572*61c4878aSAndroid Build Coastguard Worker writeTransfer.get(); 573*61c4878aSAndroid Build Coastguard Worker } 574*61c4878aSAndroid Build Coastguard Worker } 575*61c4878aSAndroid Build Coastguard Worker 576*61c4878aSAndroid Build Coastguard Worker-------- 577*61c4878aSAndroid Build Coastguard WorkerProtocol 578*61c4878aSAndroid Build Coastguard Worker-------- 579*61c4878aSAndroid Build Coastguard Worker 580*61c4878aSAndroid Build Coastguard WorkerChunks 581*61c4878aSAndroid Build Coastguard Worker====== 582*61c4878aSAndroid Build Coastguard WorkerTransfers run as a series of *chunks* exchanged over an RPC stream. Chunks can 583*61c4878aSAndroid Build Coastguard Workercontain transferable data, metadata, and control parameters. Each chunk has an 584*61c4878aSAndroid Build Coastguard Workerassociated type, which determines what information it holds and the semantics of 585*61c4878aSAndroid Build Coastguard Workerits fields. 586*61c4878aSAndroid Build Coastguard Worker 587*61c4878aSAndroid Build Coastguard WorkerThe chunk is a protobuf message, whose definition can be found 588*61c4878aSAndroid Build Coastguard Worker:ref:`here <module-pw_transfer-proto-definition>`. 589*61c4878aSAndroid Build Coastguard Worker 590*61c4878aSAndroid Build Coastguard WorkerResources and sessions 591*61c4878aSAndroid Build Coastguard Worker====================== 592*61c4878aSAndroid Build Coastguard WorkerTransfers are run for a specific *resource* --- a stream of data which can be 593*61c4878aSAndroid Build Coastguard Workerread from or written to. Resources have a system-specific integral identifier 594*61c4878aSAndroid Build Coastguard Workerdefined by the implementers of the server-side transfer node. 595*61c4878aSAndroid Build Coastguard Worker 596*61c4878aSAndroid Build Coastguard WorkerThe series of chunks exchanged in an individual transfer operation for a 597*61c4878aSAndroid Build Coastguard Workerresource constitute a transfer *session*. The session runs from its opening 598*61c4878aSAndroid Build Coastguard Workerchunk until either a terminating chunk is received or the transfer times out. 599*61c4878aSAndroid Build Coastguard WorkerSessions are assigned IDs by the client that starts them, which are unique over 600*61c4878aSAndroid Build Coastguard Workerthe RPC channel between the client and server, allowing the server to identify 601*61c4878aSAndroid Build Coastguard Workertransfers across multiple clients. 602*61c4878aSAndroid Build Coastguard Worker 603*61c4878aSAndroid Build Coastguard WorkerReliability 604*61c4878aSAndroid Build Coastguard Worker=========== 605*61c4878aSAndroid Build Coastguard Worker``pw_transfer`` attempts to be a reliable data transfer protocol. 606*61c4878aSAndroid Build Coastguard Worker 607*61c4878aSAndroid Build Coastguard WorkerAs Pigweed RPC is considered an unreliable communications system, 608*61c4878aSAndroid Build Coastguard Worker``pw_transfer`` implements its own mechanisms for reliability. These include 609*61c4878aSAndroid Build Coastguard Workertimeouts, data retransmissions, and handshakes. 610*61c4878aSAndroid Build Coastguard Worker 611*61c4878aSAndroid Build Coastguard Worker.. note:: 612*61c4878aSAndroid Build Coastguard Worker 613*61c4878aSAndroid Build Coastguard Worker A transfer can only be reliable if its underlying data stream is seekable. 614*61c4878aSAndroid Build Coastguard Worker A non-seekable stream could prematurely terminate a transfer following a 615*61c4878aSAndroid Build Coastguard Worker packet drop. 616*61c4878aSAndroid Build Coastguard Worker 617*61c4878aSAndroid Build Coastguard WorkerAt present, ``pw_transfer`` requires in-order data transmission. If packets are 618*61c4878aSAndroid Build Coastguard Workerreceived out-of-order, the receiver will request that the transmitter re-send 619*61c4878aSAndroid Build Coastguard Workerdata from the last received position. 620*61c4878aSAndroid Build Coastguard Worker 621*61c4878aSAndroid Build Coastguard WorkerOpening handshake 622*61c4878aSAndroid Build Coastguard Worker================= 623*61c4878aSAndroid Build Coastguard WorkerTransfers begin with a three-way handshake, whose purpose is to identify the 624*61c4878aSAndroid Build Coastguard Workerresource being transferred, assign a session ID, and synchronize the protocol 625*61c4878aSAndroid Build Coastguard Workerversion to use. 626*61c4878aSAndroid Build Coastguard Worker 627*61c4878aSAndroid Build Coastguard WorkerA read or write transfer for a resource is initiated by a transfer client. The 628*61c4878aSAndroid Build Coastguard Workerclient sends the ID of the resource to the server alongside a unique session ID 629*61c4878aSAndroid Build Coastguard Workerin a ``START`` chunk, indicating that it wishes to begin a new transfer. This 630*61c4878aSAndroid Build Coastguard Workerchunk additionally encodes the protocol version which the client is configured 631*61c4878aSAndroid Build Coastguard Workerto use. 632*61c4878aSAndroid Build Coastguard Worker 633*61c4878aSAndroid Build Coastguard WorkerUpon receiving a ``START`` chunk, the transfer server checks whether the 634*61c4878aSAndroid Build Coastguard Workerrequested resource is available. If so, it prepares the resource for the 635*61c4878aSAndroid Build Coastguard Workeroperation, which typically involves opening a data stream, alongside any 636*61c4878aSAndroid Build Coastguard Workeradditional user-specified setup. The server accepts the client's session ID, 637*61c4878aSAndroid Build Coastguard Workerthen responds to the client with a ``START_ACK`` chunk containing the resource, 638*61c4878aSAndroid Build Coastguard Workersession, and configured protocol version for the transfer. 639*61c4878aSAndroid Build Coastguard Worker 640*61c4878aSAndroid Build Coastguard Worker.. _module-pw_transfer-windowing: 641*61c4878aSAndroid Build Coastguard Worker 642*61c4878aSAndroid Build Coastguard WorkerWindowing 643*61c4878aSAndroid Build Coastguard Worker========= 644*61c4878aSAndroid Build Coastguard WorkerThroughout a transfer, the receiver maintains a window of how much data it can 645*61c4878aSAndroid Build Coastguard Workerreceive at a given time. This window is a multiple of the maximum size of a 646*61c4878aSAndroid Build Coastguard Workersingle data chunk, and is adjusted dynamically in response to the ongoing status 647*61c4878aSAndroid Build Coastguard Workerof the transfer. 648*61c4878aSAndroid Build Coastguard Worker 649*61c4878aSAndroid Build Coastguard Workerpw_transfer uses a congestion control algorithm similar to that of TCP 650*61c4878aSAndroid Build Coastguard Worker`(RFC 5681 §3.1) <https://datatracker.ietf.org/doc/html/rfc5681#section-3.1>`_, 651*61c4878aSAndroid Build Coastguard Workeradapted to pw_transfer's mode of operation that tunes parameters per window. 652*61c4878aSAndroid Build Coastguard Worker 653*61c4878aSAndroid Build Coastguard WorkerOnce a portion of a window has successfully been received, it is acknowledged by 654*61c4878aSAndroid Build Coastguard Workerthe receiver and the window size is extended. Transfers begin in a "slow start" 655*61c4878aSAndroid Build Coastguard Workerphase, during which the window is doubled on each ACK. This continues until the 656*61c4878aSAndroid Build Coastguard Workertransfer detects a packet loss or times out. Once this occurs, the window size 657*61c4878aSAndroid Build Coastguard Workeris halved and the transfer enters a "congestion avoidance" phase for the 658*61c4878aSAndroid Build Coastguard Workerremainder of its run. During this phase, successful ACKs increase the window 659*61c4878aSAndroid Build Coastguard Workersize by a single chunk, whereas packet loss continues to half it. 660*61c4878aSAndroid Build Coastguard Worker 661*61c4878aSAndroid Build Coastguard WorkerTransfer completion 662*61c4878aSAndroid Build Coastguard Worker=================== 663*61c4878aSAndroid Build Coastguard WorkerEither side of a transfer can terminate the operation at any time by sending a 664*61c4878aSAndroid Build Coastguard Worker``COMPLETION`` chunk containing the final status of the transfer. When a 665*61c4878aSAndroid Build Coastguard Worker``COMPLETION`` chunk is sent, the terminator of the transfer performs local 666*61c4878aSAndroid Build Coastguard Workercleanup, then waits for its peer to acknowledge the completion. 667*61c4878aSAndroid Build Coastguard Worker 668*61c4878aSAndroid Build Coastguard WorkerUpon receving a ``COMPLETION`` chunk, the transfer peer cancels any pending 669*61c4878aSAndroid Build Coastguard Workeroperations, runs its set of cleanups, and responds with a ``COMPLETION_ACK``, 670*61c4878aSAndroid Build Coastguard Workerfully ending the session from the peer's side. 671*61c4878aSAndroid Build Coastguard Worker 672*61c4878aSAndroid Build Coastguard WorkerThe terminator's session remains active waiting for a ``COMPLETION_ACK``. If not 673*61c4878aSAndroid Build Coastguard Workerreceived after a timeout, it re-sends its ``COMPLETION`` chunk. The session ends 674*61c4878aSAndroid Build Coastguard Workereither following receipt of the acknowledgement or if a maximum number of 675*61c4878aSAndroid Build Coastguard Workerretries is hit. 676*61c4878aSAndroid Build Coastguard Worker 677*61c4878aSAndroid Build Coastguard Worker.. _module-pw_transfer-proto-definition: 678*61c4878aSAndroid Build Coastguard Worker 679*61c4878aSAndroid Build Coastguard WorkerServer to client transfer (read) 680*61c4878aSAndroid Build Coastguard Worker================================ 681*61c4878aSAndroid Build Coastguard Worker.. image:: read.svg 682*61c4878aSAndroid Build Coastguard Worker 683*61c4878aSAndroid Build Coastguard WorkerClient to server transfer (write) 684*61c4878aSAndroid Build Coastguard Worker================================= 685*61c4878aSAndroid Build Coastguard Worker.. image:: write.svg 686*61c4878aSAndroid Build Coastguard Worker 687*61c4878aSAndroid Build Coastguard WorkerProtocol buffer definition 688*61c4878aSAndroid Build Coastguard Worker========================== 689*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: transfer.proto 690*61c4878aSAndroid Build Coastguard Worker :language: protobuf 691*61c4878aSAndroid Build Coastguard Worker :lines: 14- 692*61c4878aSAndroid Build Coastguard Worker 693*61c4878aSAndroid Build Coastguard WorkerErrors 694*61c4878aSAndroid Build Coastguard Worker====== 695*61c4878aSAndroid Build Coastguard Worker 696*61c4878aSAndroid Build Coastguard WorkerProtocol errors 697*61c4878aSAndroid Build Coastguard Worker--------------- 698*61c4878aSAndroid Build Coastguard WorkerThe following table describes the meaning of each status code when sent by the 699*61c4878aSAndroid Build Coastguard Workersender or the receiver (see `Transfer roles`_). 700*61c4878aSAndroid Build Coastguard Worker 701*61c4878aSAndroid Build Coastguard Worker.. cpp:namespace-push:: pw::stream 702*61c4878aSAndroid Build Coastguard Worker 703*61c4878aSAndroid Build Coastguard Worker+-------------------------+-------------------------+-------------------------+ 704*61c4878aSAndroid Build Coastguard Worker| Status | Sent by sender | Sent by receiver | 705*61c4878aSAndroid Build Coastguard Worker+=========================+=========================+=========================+ 706*61c4878aSAndroid Build Coastguard Worker| ``OK`` | (not sent) | All data was received | 707*61c4878aSAndroid Build Coastguard Worker| | | and handled | 708*61c4878aSAndroid Build Coastguard Worker| | | successfully. | 709*61c4878aSAndroid Build Coastguard Worker+-------------------------+-------------------------+-------------------------+ 710*61c4878aSAndroid Build Coastguard Worker| ``ABORTED`` | The service aborted the transfer because the | 711*61c4878aSAndroid Build Coastguard Worker| | client restarted it. This status is passed to the | 712*61c4878aSAndroid Build Coastguard Worker| | transfer handler, but not sent to the client | 713*61c4878aSAndroid Build Coastguard Worker| | because it restarted the transfer. | 714*61c4878aSAndroid Build Coastguard Worker+-------------------------+---------------------------------------------------+ 715*61c4878aSAndroid Build Coastguard Worker| ``CANCELLED`` | The client cancelled the transfer. | 716*61c4878aSAndroid Build Coastguard Worker+-------------------------+-------------------------+-------------------------+ 717*61c4878aSAndroid Build Coastguard Worker| ``DATA_LOSS`` | Failed to read the data | Failed to write the | 718*61c4878aSAndroid Build Coastguard Worker| | to send. The | received data. The | 719*61c4878aSAndroid Build Coastguard Worker| | :cpp:class:`Reader` | :cpp:class:`Writer` | 720*61c4878aSAndroid Build Coastguard Worker| | returned an error. | returned an error. | 721*61c4878aSAndroid Build Coastguard Worker+-------------------------+-------------------------+-------------------------+ 722*61c4878aSAndroid Build Coastguard Worker| ``FAILED_PRECONDITION`` | Received chunk for transfer that is not active. | 723*61c4878aSAndroid Build Coastguard Worker+-------------------------+-------------------------+-------------------------+ 724*61c4878aSAndroid Build Coastguard Worker| ``INVALID_ARGUMENT`` | Received a malformed packet. | 725*61c4878aSAndroid Build Coastguard Worker+-------------------------+-------------------------+-------------------------+ 726*61c4878aSAndroid Build Coastguard Worker| ``INTERNAL`` | An assumption of the protocol was violated. | 727*61c4878aSAndroid Build Coastguard Worker| | Encountering ``INTERNAL`` indicates that there is | 728*61c4878aSAndroid Build Coastguard Worker| | a bug in the service or client implementation. | 729*61c4878aSAndroid Build Coastguard Worker+-------------------------+-------------------------+-------------------------+ 730*61c4878aSAndroid Build Coastguard Worker| ``PERMISSION_DENIED`` | The transfer does not support the requested | 731*61c4878aSAndroid Build Coastguard Worker| | operation (either reading or writing). | 732*61c4878aSAndroid Build Coastguard Worker+-------------------------+-------------------------+-------------------------+ 733*61c4878aSAndroid Build Coastguard Worker| ``RESOURCE_EXHAUSTED`` | The receiver requested | Storage is full. | 734*61c4878aSAndroid Build Coastguard Worker| | zero bytes, indicating | | 735*61c4878aSAndroid Build Coastguard Worker| | their storage is full, | | 736*61c4878aSAndroid Build Coastguard Worker| | but there is still data | | 737*61c4878aSAndroid Build Coastguard Worker| | to send. | | 738*61c4878aSAndroid Build Coastguard Worker+-------------------------+-------------------------+-------------------------+ 739*61c4878aSAndroid Build Coastguard Worker| ``UNAVAILABLE`` | The service is busy with other transfers and | 740*61c4878aSAndroid Build Coastguard Worker| | cannot begin a new transfer at this time. | 741*61c4878aSAndroid Build Coastguard Worker+-------------------------+-------------------------+-------------------------+ 742*61c4878aSAndroid Build Coastguard Worker| ``UNIMPLEMENTED`` | Out-of-order chunk was | (not sent) | 743*61c4878aSAndroid Build Coastguard Worker| | requested, but seeking | | 744*61c4878aSAndroid Build Coastguard Worker| | is not supported. | | 745*61c4878aSAndroid Build Coastguard Worker+-------------------------+-------------------------+-------------------------+ 746*61c4878aSAndroid Build Coastguard Worker 747*61c4878aSAndroid Build Coastguard Worker.. cpp:namespace-pop:: 748*61c4878aSAndroid Build Coastguard Worker 749*61c4878aSAndroid Build Coastguard Worker 750*61c4878aSAndroid Build Coastguard WorkerTransfer roles 751*61c4878aSAndroid Build Coastguard Worker============== 752*61c4878aSAndroid Build Coastguard WorkerEvery transfer has two participants: the sender and the receiver. The sender 753*61c4878aSAndroid Build Coastguard Workertransmits data to the receiver. The receiver controls how the data is 754*61c4878aSAndroid Build Coastguard Workertransferred and sends the final status when the transfer is complete. 755*61c4878aSAndroid Build Coastguard Worker 756*61c4878aSAndroid Build Coastguard WorkerIn read transfers, the client is the receiver and the service is the sender. In 757*61c4878aSAndroid Build Coastguard Workerwrite transfers, the client is the sender and the service is the receiver. 758*61c4878aSAndroid Build Coastguard Worker 759*61c4878aSAndroid Build Coastguard WorkerSender flow 760*61c4878aSAndroid Build Coastguard Worker----------- 761*61c4878aSAndroid Build Coastguard Worker.. mermaid:: 762*61c4878aSAndroid Build Coastguard Worker 763*61c4878aSAndroid Build Coastguard Worker graph TD 764*61c4878aSAndroid Build Coastguard Worker start([Client initiates<br>transfer]) -->data_request 765*61c4878aSAndroid Build Coastguard Worker data_request[Receive transfer<br>parameters]-->send_chunk 766*61c4878aSAndroid Build Coastguard Worker 767*61c4878aSAndroid Build Coastguard Worker send_chunk[Send chunk]-->sent_all 768*61c4878aSAndroid Build Coastguard Worker 769*61c4878aSAndroid Build Coastguard Worker sent_all{Sent final<br>chunk?} -->|yes|wait 770*61c4878aSAndroid Build Coastguard Worker sent_all-->|no|sent_requested 771*61c4878aSAndroid Build Coastguard Worker 772*61c4878aSAndroid Build Coastguard Worker sent_requested{Sent all<br>pending?}-->|yes|data_request 773*61c4878aSAndroid Build Coastguard Worker sent_requested-->|no|send_chunk 774*61c4878aSAndroid Build Coastguard Worker 775*61c4878aSAndroid Build Coastguard Worker wait[Wait for receiver]-->is_done 776*61c4878aSAndroid Build Coastguard Worker 777*61c4878aSAndroid Build Coastguard Worker is_done{Received<br>final chunk?}-->|yes|done 778*61c4878aSAndroid Build Coastguard Worker is_done-->|no|data_request 779*61c4878aSAndroid Build Coastguard Worker 780*61c4878aSAndroid Build Coastguard Worker done([Transfer complete]) 781*61c4878aSAndroid Build Coastguard Worker 782*61c4878aSAndroid Build Coastguard WorkerReceiver flow 783*61c4878aSAndroid Build Coastguard Worker------------- 784*61c4878aSAndroid Build Coastguard Worker.. mermaid:: 785*61c4878aSAndroid Build Coastguard Worker 786*61c4878aSAndroid Build Coastguard Worker graph TD 787*61c4878aSAndroid Build Coastguard Worker start([Client initiates<br>transfer]) -->request_bytes 788*61c4878aSAndroid Build Coastguard Worker request_bytes[Set transfer<br>parameters]-->wait 789*61c4878aSAndroid Build Coastguard Worker 790*61c4878aSAndroid Build Coastguard Worker wait[Wait for chunk]-->received_chunk 791*61c4878aSAndroid Build Coastguard Worker 792*61c4878aSAndroid Build Coastguard Worker received_chunk{Received<br>chunk by<br>deadline?}-->|no|request_bytes 793*61c4878aSAndroid Build Coastguard Worker received_chunk-->|yes|check_chunk 794*61c4878aSAndroid Build Coastguard Worker 795*61c4878aSAndroid Build Coastguard Worker check_chunk{Correct<br>offset?} -->|yes|process_chunk 796*61c4878aSAndroid Build Coastguard Worker check_chunk --> |no|request_bytes 797*61c4878aSAndroid Build Coastguard Worker 798*61c4878aSAndroid Build Coastguard Worker process_chunk[Process chunk]-->final_chunk 799*61c4878aSAndroid Build Coastguard Worker 800*61c4878aSAndroid Build Coastguard Worker final_chunk{Final<br>chunk?}-->|yes|signal_completion 801*61c4878aSAndroid Build Coastguard Worker final_chunk{Final<br>chunk?}-->|no|received_requested 802*61c4878aSAndroid Build Coastguard Worker 803*61c4878aSAndroid Build Coastguard Worker received_requested{Received all<br>pending?}-->|yes|request_bytes 804*61c4878aSAndroid Build Coastguard Worker received_requested-->|no|wait 805*61c4878aSAndroid Build Coastguard Worker 806*61c4878aSAndroid Build Coastguard Worker signal_completion[Signal completion]-->done 807*61c4878aSAndroid Build Coastguard Worker 808*61c4878aSAndroid Build Coastguard Worker done([Transfer complete]) 809*61c4878aSAndroid Build Coastguard Worker 810*61c4878aSAndroid Build Coastguard WorkerLegacy protocol 811*61c4878aSAndroid Build Coastguard Worker=============== 812*61c4878aSAndroid Build Coastguard Worker``pw_transfer`` was initially released into production prior to several of the 813*61c4878aSAndroid Build Coastguard Workerreliability improvements of its modern protocol. As a result of this, transfer 814*61c4878aSAndroid Build Coastguard Workerimplementations support a "legacy" protocol mode, in which transfers run without 815*61c4878aSAndroid Build Coastguard Workerutilizing these features. 816*61c4878aSAndroid Build Coastguard Worker 817*61c4878aSAndroid Build Coastguard WorkerThe primary differences between the legacy and modern protocols are listed 818*61c4878aSAndroid Build Coastguard Workerbelow. 819*61c4878aSAndroid Build Coastguard Worker 820*61c4878aSAndroid Build Coastguard Worker- There is no distinction between a transfer resource and session --- a single 821*61c4878aSAndroid Build Coastguard Worker ``transfer_id`` field represents both. Only one transfer for a given resource 822*61c4878aSAndroid Build Coastguard Worker can run at a time, and it is not possible to determine where one transfer for 823*61c4878aSAndroid Build Coastguard Worker a resource ends and the next begins. 824*61c4878aSAndroid Build Coastguard Worker- The legacy protocol has no opening handshake phase. The client initiates with 825*61c4878aSAndroid Build Coastguard Worker a transfer ID and starting transfer parameters (during a read), and the data 826*61c4878aSAndroid Build Coastguard Worker transfer phase begins immediately. 827*61c4878aSAndroid Build Coastguard Worker- The legacy protocol has no terminating handshake phase. When either end 828*61c4878aSAndroid Build Coastguard Worker completes a transfer by sending a status chunk, it does not wait for the peer 829*61c4878aSAndroid Build Coastguard Worker to acknowledge. Resources used by the transfer are immediately freed, and 830*61c4878aSAndroid Build Coastguard Worker there is no guarantee that the peer is notified of completion. 831*61c4878aSAndroid Build Coastguard Worker 832*61c4878aSAndroid Build Coastguard WorkerTransfer clients request the latest transfer protocol version by default, but 833*61c4878aSAndroid Build Coastguard Workermay be configured to request the legacy protocol. Transfer server and client 834*61c4878aSAndroid Build Coastguard Workerimplementations detect if their transfer peer is running the legacy protocol and 835*61c4878aSAndroid Build Coastguard Workerautomatically switch to it if required, even if they requested a newer protocol 836*61c4878aSAndroid Build Coastguard Workerversion. It is **strongly** unadvised to use the legacy protocol in new code. 837*61c4878aSAndroid Build Coastguard Worker 838*61c4878aSAndroid Build Coastguard Worker.. _module-pw_transfer-integration-tests: 839*61c4878aSAndroid Build Coastguard Worker 840*61c4878aSAndroid Build Coastguard Worker----------------- 841*61c4878aSAndroid Build Coastguard WorkerIntegration tests 842*61c4878aSAndroid Build Coastguard Worker----------------- 843*61c4878aSAndroid Build Coastguard WorkerThe ``pw_transfer`` module has a set of integration tests that verify the 844*61c4878aSAndroid Build Coastguard Workercorrectness of implementations in different languages. 845*61c4878aSAndroid Build Coastguard Worker`Test source code <https://cs.pigweed.dev/pigweed/+/main:pw_transfer/integration_test/>`_. 846*61c4878aSAndroid Build Coastguard Worker 847*61c4878aSAndroid Build Coastguard WorkerTo run the tests on your machine, run 848*61c4878aSAndroid Build Coastguard Worker 849*61c4878aSAndroid Build Coastguard Worker.. code-block:: bash 850*61c4878aSAndroid Build Coastguard Worker 851*61c4878aSAndroid Build Coastguard Worker $ bazel test \ 852*61c4878aSAndroid Build Coastguard Worker pw_transfer/integration_test:cross_language_small_test \ 853*61c4878aSAndroid Build Coastguard Worker pw_transfer/integration_test:cross_language_medium_test 854*61c4878aSAndroid Build Coastguard Worker 855*61c4878aSAndroid Build Coastguard Worker.. note:: There is a large test that tests transfers that are megabytes in size. 856*61c4878aSAndroid Build Coastguard Worker These are not run automatically, but can be run manually via the 857*61c4878aSAndroid Build Coastguard Worker ``pw_transfer/integration_test:cross_language_large_test`` test. These are 858*61c4878aSAndroid Build Coastguard Worker VERY slow, but exist for manual validation of real-world use cases. 859*61c4878aSAndroid Build Coastguard Worker 860*61c4878aSAndroid Build Coastguard WorkerThe integration tests permit injection of client/server/proxy binaries to use 861*61c4878aSAndroid Build Coastguard Workerwhen running the tests. This allows manual testing of older versions of 862*61c4878aSAndroid Build Coastguard Workerpw_transfer against newer versions. 863*61c4878aSAndroid Build Coastguard Worker 864*61c4878aSAndroid Build Coastguard Worker.. code-block:: bash 865*61c4878aSAndroid Build Coastguard Worker 866*61c4878aSAndroid Build Coastguard Worker # Test a newer version of pw_transfer against an old C++ client that was 867*61c4878aSAndroid Build Coastguard Worker # backed up to another directory. 868*61c4878aSAndroid Build Coastguard Worker $ bazel run pw_transfer/integration_test:cross_language_medium_test -- \ 869*61c4878aSAndroid Build Coastguard Worker --cpp-client-binary ../old_pw_transfer_version/cpp_client 870*61c4878aSAndroid Build Coastguard Worker 871*61c4878aSAndroid Build Coastguard WorkerBackwards compatibility tests 872*61c4878aSAndroid Build Coastguard Worker============================= 873*61c4878aSAndroid Build Coastguard Worker``pw_transfer`` includes a `suite of backwards-compatibility tests 874*61c4878aSAndroid Build Coastguard Worker<https://cs.pigweed.dev/pigweed/+/main:pw_transfer/integration_test/legacy_binaries_test.py>`_ 875*61c4878aSAndroid Build Coastguard Workerthat are intended to continuously validate a degree of backwards-compatibility 876*61c4878aSAndroid Build Coastguard Workerwith older pw_transfer servers and clients. This is done by retrieving older 877*61c4878aSAndroid Build Coastguard Workerbinaries hosted in CIPD and running tests between the older client/server 878*61c4878aSAndroid Build Coastguard Workerbinaries and the latest binaries. 879*61c4878aSAndroid Build Coastguard Worker 880*61c4878aSAndroid Build Coastguard WorkerThe CIPD package contents can be created with this command: 881*61c4878aSAndroid Build Coastguard Worker 882*61c4878aSAndroid Build Coastguard Worker.. code-block::bash 883*61c4878aSAndroid Build Coastguard Worker 884*61c4878aSAndroid Build Coastguard Worker $ bazel build pw_transfer/integration_test:server \ 885*61c4878aSAndroid Build Coastguard Worker pw_transfer/integration_test:cpp_client 886*61c4878aSAndroid Build Coastguard Worker $ mkdir pw_transfer_test_binaries 887*61c4878aSAndroid Build Coastguard Worker $ cp bazel-bin/pw_transfer/integration_test/server \ 888*61c4878aSAndroid Build Coastguard Worker pw_transfer_test_binaries 889*61c4878aSAndroid Build Coastguard Worker $ cp bazel-bin/pw_transfer/integration_test/cpp_client \ 890*61c4878aSAndroid Build Coastguard Worker pw_transfer_test_binaries 891*61c4878aSAndroid Build Coastguard Worker 892*61c4878aSAndroid Build Coastguard WorkerTo update the CIPD package itself, follow the `internal documentation for 893*61c4878aSAndroid Build Coastguard Workerupdating a CIPD package <http://go/pigweed-cipd#installing-packages-into-cipd>`_. 894*61c4878aSAndroid Build Coastguard Worker 895*61c4878aSAndroid Build Coastguard WorkerCI/CQ integration 896*61c4878aSAndroid Build Coastguard Worker================= 897*61c4878aSAndroid Build Coastguard Worker`Current status of the test in CI <https://ci.chromium.org/ui/p/pigweed/builders/luci.pigweed.pigweed.ci/pigweed-linux-bzl-integration>`_. 898*61c4878aSAndroid Build Coastguard Worker 899*61c4878aSAndroid Build Coastguard WorkerBy default, these tests are not run in CQ (on presubmit) because they are too 900*61c4878aSAndroid Build Coastguard Workerslow. However, you can request that the tests be run in presubmit on your 901*61c4878aSAndroid Build Coastguard Workerchange by adding to following line to the commit message footer: 902*61c4878aSAndroid Build Coastguard Worker 903*61c4878aSAndroid Build Coastguard Worker.. code-block:: 904*61c4878aSAndroid Build Coastguard Worker 905*61c4878aSAndroid Build Coastguard Worker Cq-Include-Trybots: luci.pigweed.try:pigweed-linux-bzl-integration 906*61c4878aSAndroid Build Coastguard Worker 907*61c4878aSAndroid Build Coastguard Worker.. _module-pw_transfer-parallel-tests: 908*61c4878aSAndroid Build Coastguard Worker 909*61c4878aSAndroid Build Coastguard WorkerRunning the tests many times 910*61c4878aSAndroid Build Coastguard Worker============================ 911*61c4878aSAndroid Build Coastguard WorkerBecause the tests bind to network ports, you cannot run more than one instance 912*61c4878aSAndroid Build Coastguard Workerof each test in parallel. However, you might want to do so, e.g. to debug 913*61c4878aSAndroid Build Coastguard Workerflakes. This section describes a manual process that makes this possible. 914*61c4878aSAndroid Build Coastguard Worker 915*61c4878aSAndroid Build Coastguard WorkerLinux 916*61c4878aSAndroid Build Coastguard Worker----- 917*61c4878aSAndroid Build Coastguard WorkerOn Linux, you can add the ``"block-network"`` tag to the tests (`example 918*61c4878aSAndroid Build Coastguard Worker<https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/181297>`_). This 919*61c4878aSAndroid Build Coastguard Workerenables network isolation for the tests, allowing you to run them in parallel 920*61c4878aSAndroid Build Coastguard Workervia, 921*61c4878aSAndroid Build Coastguard Worker 922*61c4878aSAndroid Build Coastguard Worker.. code-block:: 923*61c4878aSAndroid Build Coastguard Worker 924*61c4878aSAndroid Build Coastguard Worker bazel test --runs_per_test=10 //pw_transfer/integration_tests/... 925*61c4878aSAndroid Build Coastguard Worker 926*61c4878aSAndroid Build Coastguard WorkerMacOS 927*61c4878aSAndroid Build Coastguard Worker----- 928*61c4878aSAndroid Build Coastguard WorkerNetwork isolation is not supported on MacOS because the OS doesn't support 929*61c4878aSAndroid Build Coastguard Workernetwork virtualization (`gh#2669 930*61c4878aSAndroid Build Coastguard Worker<https://github.com/bazelbuild/bazel/issues/2669>`_). The best you can do is to 931*61c4878aSAndroid Build Coastguard Workertag the tests ``"exclusive"``. This allows you to use ``--runs_per_test``, but 932*61c4878aSAndroid Build Coastguard Workerwill force each test to run by itself, with no parallelism. 933*61c4878aSAndroid Build Coastguard Worker 934*61c4878aSAndroid Build Coastguard WorkerWhy is this manual? 935*61c4878aSAndroid Build Coastguard Worker------------------- 936*61c4878aSAndroid Build Coastguard WorkerIdeally, we would apply either the ``"block-network"`` or ``"exclusive"`` tag 937*61c4878aSAndroid Build Coastguard Workerto the tests depending on the OS. But this is not supported, `gh#2971 938*61c4878aSAndroid Build Coastguard Worker<https://github.com/bazelbuild/bazel/issues/2971>`_. 939*61c4878aSAndroid Build Coastguard Worker 940*61c4878aSAndroid Build Coastguard WorkerWe don't want to tag the tests ``"exclusive"`` by default because that will 941*61c4878aSAndroid Build Coastguard Workerprevent *different* tests from running in parallel, significantly slowing them 942*61c4878aSAndroid Build Coastguard Workerdown. 943*61c4878aSAndroid Build Coastguard Worker 944*61c4878aSAndroid Build Coastguard Worker.. toctree:: 945*61c4878aSAndroid Build Coastguard Worker :hidden: 946*61c4878aSAndroid Build Coastguard Worker 947*61c4878aSAndroid Build Coastguard Worker API reference <api> 948