1*61c4878aSAndroid Build Coastguard Worker // Copyright 2022 The Pigweed Authors 2*61c4878aSAndroid Build Coastguard Worker // 3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of 5*61c4878aSAndroid Build Coastguard Worker // the License at 6*61c4878aSAndroid Build Coastguard Worker // 7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0 8*61c4878aSAndroid Build Coastguard Worker // 9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under 13*61c4878aSAndroid Build Coastguard Worker // the License. 14*61c4878aSAndroid Build Coastguard Worker 15*61c4878aSAndroid Build Coastguard Worker import com.google.common.collect.ImmutableList; 16*61c4878aSAndroid Build Coastguard Worker import com.google.protobuf.TextFormat; 17*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_hdlc.Decoder; 18*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_hdlc.Encoder; 19*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_hdlc.Frame; 20*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_log.Logger; 21*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_rpc.Channel; 22*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_rpc.ChannelOutputException; 23*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_rpc.Client; 24*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_rpc.Status; 25*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_transfer.ProtocolVersion; 26*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_transfer.TransferClient; 27*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_transfer.TransferError; 28*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_transfer.TransferService; 29*61c4878aSAndroid Build Coastguard Worker import dev.pigweed.pw_transfer.TransferTimeoutSettings; 30*61c4878aSAndroid Build Coastguard Worker import java.io.IOException; 31*61c4878aSAndroid Build Coastguard Worker import java.io.InputStream; 32*61c4878aSAndroid Build Coastguard Worker import java.io.OutputStream; 33*61c4878aSAndroid Build Coastguard Worker import java.net.Socket; 34*61c4878aSAndroid Build Coastguard Worker import java.net.SocketException; 35*61c4878aSAndroid Build Coastguard Worker import java.nio.ByteBuffer; 36*61c4878aSAndroid Build Coastguard Worker import java.nio.charset.StandardCharsets; 37*61c4878aSAndroid Build Coastguard Worker import java.nio.file.Files; 38*61c4878aSAndroid Build Coastguard Worker import java.nio.file.Path; 39*61c4878aSAndroid Build Coastguard Worker import java.nio.file.Paths; 40*61c4878aSAndroid Build Coastguard Worker import java.util.concurrent.ExecutionException; 41*61c4878aSAndroid Build Coastguard Worker import pw.transfer.ConfigProtos; 42*61c4878aSAndroid Build Coastguard Worker import pw.transfer.ConfigProtos.TransferAction; 43*61c4878aSAndroid Build Coastguard Worker 44*61c4878aSAndroid Build Coastguard Worker public class JavaClient { 45*61c4878aSAndroid Build Coastguard Worker private static final String SERVICE = "pw.transfer.Transfer"; 46*61c4878aSAndroid Build Coastguard Worker private static final Logger logger = Logger.forClass(Client.class); 47*61c4878aSAndroid Build Coastguard Worker 48*61c4878aSAndroid Build Coastguard Worker private static final int CHANNEL_ID = 1; 49*61c4878aSAndroid Build Coastguard Worker private static final long RPC_HDLC_ADDRESS = 'R'; 50*61c4878aSAndroid Build Coastguard Worker private static final String HOSTNAME = "localhost"; 51*61c4878aSAndroid Build Coastguard Worker 52*61c4878aSAndroid Build Coastguard Worker // This is the maximum size of the socket send buffers. Ideally, this is set 53*61c4878aSAndroid Build Coastguard Worker // to the lowest allowed value to minimize buffering between the proxy and 54*61c4878aSAndroid Build Coastguard Worker // clients so rate limiting causes the client to block and wait for the 55*61c4878aSAndroid Build Coastguard Worker // integration test proxy to drain rather than allowing OS buffers to backlog 56*61c4878aSAndroid Build Coastguard Worker // large quantities of data. 57*61c4878aSAndroid Build Coastguard Worker // 58*61c4878aSAndroid Build Coastguard Worker // Note that the OS may chose to not strictly follow this requested buffer 59*61c4878aSAndroid Build Coastguard Worker // size. Still, setting this value to be as small as possible does reduce 60*61c4878aSAndroid Build Coastguard Worker // bufer sizes significantly enough to better reflect typical inter-device 61*61c4878aSAndroid Build Coastguard Worker // communication. 62*61c4878aSAndroid Build Coastguard Worker // 63*61c4878aSAndroid Build Coastguard Worker // For this to be effective, servers should also configure their sockets to a 64*61c4878aSAndroid Build Coastguard Worker // smaller receive buffer size. 65*61c4878aSAndroid Build Coastguard Worker private static final int MAX_SOCKET_SEND_BUFFER_SIZE = 1; 66*61c4878aSAndroid Build Coastguard Worker 67*61c4878aSAndroid Build Coastguard Worker private final HdlcRpcChannelOutput channelOutput; 68*61c4878aSAndroid Build Coastguard Worker private final Client rpcClient; 69*61c4878aSAndroid Build Coastguard Worker private final HdlcParseThread parseThread; 70*61c4878aSAndroid Build Coastguard Worker JavaClient(OutputStream writer, InputStream reader)71*61c4878aSAndroid Build Coastguard Worker public JavaClient(OutputStream writer, InputStream reader) { 72*61c4878aSAndroid Build Coastguard Worker this.channelOutput = new HdlcRpcChannelOutput(writer, RPC_HDLC_ADDRESS); 73*61c4878aSAndroid Build Coastguard Worker 74*61c4878aSAndroid Build Coastguard Worker this.rpcClient = Client.create(ImmutableList.of(new Channel(CHANNEL_ID, this.channelOutput)), 75*61c4878aSAndroid Build Coastguard Worker ImmutableList.of(TransferService.get())); 76*61c4878aSAndroid Build Coastguard Worker 77*61c4878aSAndroid Build Coastguard Worker this.parseThread = new HdlcParseThread(reader, this.rpcClient); 78*61c4878aSAndroid Build Coastguard Worker } 79*61c4878aSAndroid Build Coastguard Worker startClient()80*61c4878aSAndroid Build Coastguard Worker void startClient() { 81*61c4878aSAndroid Build Coastguard Worker parseThread.start(); 82*61c4878aSAndroid Build Coastguard Worker } 83*61c4878aSAndroid Build Coastguard Worker getRpcClient()84*61c4878aSAndroid Build Coastguard Worker Client getRpcClient() { 85*61c4878aSAndroid Build Coastguard Worker return this.rpcClient; 86*61c4878aSAndroid Build Coastguard Worker } 87*61c4878aSAndroid Build Coastguard Worker 88*61c4878aSAndroid Build Coastguard Worker private class HdlcRpcChannelOutput implements Channel.Output { 89*61c4878aSAndroid Build Coastguard Worker private final OutputStream writer; 90*61c4878aSAndroid Build Coastguard Worker private final long address; 91*61c4878aSAndroid Build Coastguard Worker HdlcRpcChannelOutput(OutputStream writer, long address)92*61c4878aSAndroid Build Coastguard Worker public HdlcRpcChannelOutput(OutputStream writer, long address) { 93*61c4878aSAndroid Build Coastguard Worker this.writer = writer; 94*61c4878aSAndroid Build Coastguard Worker this.address = address; 95*61c4878aSAndroid Build Coastguard Worker } 96*61c4878aSAndroid Build Coastguard Worker send(byte[] packet)97*61c4878aSAndroid Build Coastguard Worker public void send(byte[] packet) throws ChannelOutputException { 98*61c4878aSAndroid Build Coastguard Worker try { 99*61c4878aSAndroid Build Coastguard Worker Encoder.writeUiFrame(this.address, ByteBuffer.wrap(packet), this.writer); 100*61c4878aSAndroid Build Coastguard Worker } catch (IOException e) { 101*61c4878aSAndroid Build Coastguard Worker throw new ChannelOutputException("Failed to write HDLC UI Frame", e); 102*61c4878aSAndroid Build Coastguard Worker } 103*61c4878aSAndroid Build Coastguard Worker } 104*61c4878aSAndroid Build Coastguard Worker } 105*61c4878aSAndroid Build Coastguard Worker 106*61c4878aSAndroid Build Coastguard Worker private class HdlcParseThread extends Thread { 107*61c4878aSAndroid Build Coastguard Worker private final InputStream reader; 108*61c4878aSAndroid Build Coastguard Worker private final RpcOnComplete frame_handler; 109*61c4878aSAndroid Build Coastguard Worker private final Decoder decoder; 110*61c4878aSAndroid Build Coastguard Worker 111*61c4878aSAndroid Build Coastguard Worker private class RpcOnComplete implements Decoder.OnCompleteFrame { 112*61c4878aSAndroid Build Coastguard Worker private final Client rpc_client; 113*61c4878aSAndroid Build Coastguard Worker RpcOnComplete(Client rpc_client)114*61c4878aSAndroid Build Coastguard Worker public RpcOnComplete(Client rpc_client) { 115*61c4878aSAndroid Build Coastguard Worker this.rpc_client = rpc_client; 116*61c4878aSAndroid Build Coastguard Worker } 117*61c4878aSAndroid Build Coastguard Worker onCompleteFrame(Frame frame)118*61c4878aSAndroid Build Coastguard Worker public void onCompleteFrame(Frame frame) { 119*61c4878aSAndroid Build Coastguard Worker if (frame.getAddress() == RPC_HDLC_ADDRESS) { 120*61c4878aSAndroid Build Coastguard Worker this.rpc_client.processPacket(frame.getPayload()); 121*61c4878aSAndroid Build Coastguard Worker } 122*61c4878aSAndroid Build Coastguard Worker } 123*61c4878aSAndroid Build Coastguard Worker } 124*61c4878aSAndroid Build Coastguard Worker HdlcParseThread(InputStream reader, Client rpc_client)125*61c4878aSAndroid Build Coastguard Worker public HdlcParseThread(InputStream reader, Client rpc_client) { 126*61c4878aSAndroid Build Coastguard Worker this.reader = reader; 127*61c4878aSAndroid Build Coastguard Worker this.frame_handler = new RpcOnComplete(rpc_client); 128*61c4878aSAndroid Build Coastguard Worker this.decoder = new Decoder(this.frame_handler); 129*61c4878aSAndroid Build Coastguard Worker } 130*61c4878aSAndroid Build Coastguard Worker run()131*61c4878aSAndroid Build Coastguard Worker public void run() { 132*61c4878aSAndroid Build Coastguard Worker while (true) { 133*61c4878aSAndroid Build Coastguard Worker int val = 0; 134*61c4878aSAndroid Build Coastguard Worker try { 135*61c4878aSAndroid Build Coastguard Worker val = this.reader.read(); 136*61c4878aSAndroid Build Coastguard Worker } catch (IOException e) { 137*61c4878aSAndroid Build Coastguard Worker logger.atSevere().log("HDLC parse thread read failed"); 138*61c4878aSAndroid Build Coastguard Worker System.exit(1); 139*61c4878aSAndroid Build Coastguard Worker } 140*61c4878aSAndroid Build Coastguard Worker this.decoder.process((byte) val); 141*61c4878aSAndroid Build Coastguard Worker } 142*61c4878aSAndroid Build Coastguard Worker } 143*61c4878aSAndroid Build Coastguard Worker } 144*61c4878aSAndroid Build Coastguard Worker ParseConfigFrom(InputStream reader)145*61c4878aSAndroid Build Coastguard Worker public static ConfigProtos.ClientConfig ParseConfigFrom(InputStream reader) throws IOException { 146*61c4878aSAndroid Build Coastguard Worker byte[] buffer = new byte[reader.available()]; 147*61c4878aSAndroid Build Coastguard Worker reader.read(buffer); 148*61c4878aSAndroid Build Coastguard Worker ConfigProtos.ClientConfig.Builder config_builder = ConfigProtos.ClientConfig.newBuilder(); 149*61c4878aSAndroid Build Coastguard Worker TextFormat.merge(new String(buffer, StandardCharsets.UTF_8), config_builder); 150*61c4878aSAndroid Build Coastguard Worker if (config_builder.getChunkTimeoutMs() == 0) { 151*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("chunk_timeout_ms may not be 0"); 152*61c4878aSAndroid Build Coastguard Worker } 153*61c4878aSAndroid Build Coastguard Worker if (config_builder.getInitialChunkTimeoutMs() == 0) { 154*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("initial_chunk_timeout_ms may not be 0"); 155*61c4878aSAndroid Build Coastguard Worker } 156*61c4878aSAndroid Build Coastguard Worker if (config_builder.getMaxRetries() == 0) { 157*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("max_retries may not be 0"); 158*61c4878aSAndroid Build Coastguard Worker } 159*61c4878aSAndroid Build Coastguard Worker if (config_builder.getMaxLifetimeRetries() == 0) { 160*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("max_lifetime_retries may not be 0"); 161*61c4878aSAndroid Build Coastguard Worker } 162*61c4878aSAndroid Build Coastguard Worker return config_builder.build(); 163*61c4878aSAndroid Build Coastguard Worker } 164*61c4878aSAndroid Build Coastguard Worker ReadFromServer(int resourceId, Path fileName, TransferClient client, Status expected_status, int initial_offset)165*61c4878aSAndroid Build Coastguard Worker public static void ReadFromServer(int resourceId, 166*61c4878aSAndroid Build Coastguard Worker Path fileName, 167*61c4878aSAndroid Build Coastguard Worker TransferClient client, 168*61c4878aSAndroid Build Coastguard Worker Status expected_status, 169*61c4878aSAndroid Build Coastguard Worker int initial_offset) { 170*61c4878aSAndroid Build Coastguard Worker byte[] data; 171*61c4878aSAndroid Build Coastguard Worker try { 172*61c4878aSAndroid Build Coastguard Worker data = client.read(resourceId, initial_offset).get(); 173*61c4878aSAndroid Build Coastguard Worker } catch (ExecutionException e) { 174*61c4878aSAndroid Build Coastguard Worker if (((TransferError) e.getCause()).status() != expected_status) { 175*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Unexpected transfer read failure", e); 176*61c4878aSAndroid Build Coastguard Worker } 177*61c4878aSAndroid Build Coastguard Worker // Expected failure occurred, skip trying to write the data knowing that 178*61c4878aSAndroid Build Coastguard Worker // it is missing. 179*61c4878aSAndroid Build Coastguard Worker return; 180*61c4878aSAndroid Build Coastguard Worker } catch (InterruptedException e) { 181*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Read from server failed", e); 182*61c4878aSAndroid Build Coastguard Worker } 183*61c4878aSAndroid Build Coastguard Worker 184*61c4878aSAndroid Build Coastguard Worker if (expected_status != Status.OK) { 185*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Transfer succeeded unexpectedly"); 186*61c4878aSAndroid Build Coastguard Worker } 187*61c4878aSAndroid Build Coastguard Worker 188*61c4878aSAndroid Build Coastguard Worker try { 189*61c4878aSAndroid Build Coastguard Worker Files.write(fileName, data); 190*61c4878aSAndroid Build Coastguard Worker } catch (IOException e) { 191*61c4878aSAndroid Build Coastguard Worker logger.atSevere().log("Failed to write to output file `%s`", fileName); 192*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Failed to write output file from server", e); 193*61c4878aSAndroid Build Coastguard Worker } 194*61c4878aSAndroid Build Coastguard Worker } 195*61c4878aSAndroid Build Coastguard Worker WriteToServer(int resourceId, Path fileName, TransferClient client, Status expected_status, int initial_offset)196*61c4878aSAndroid Build Coastguard Worker public static void WriteToServer(int resourceId, 197*61c4878aSAndroid Build Coastguard Worker Path fileName, 198*61c4878aSAndroid Build Coastguard Worker TransferClient client, 199*61c4878aSAndroid Build Coastguard Worker Status expected_status, 200*61c4878aSAndroid Build Coastguard Worker int initial_offset) { 201*61c4878aSAndroid Build Coastguard Worker if (Files.notExists(fileName)) { 202*61c4878aSAndroid Build Coastguard Worker logger.atSevere().log("Input file `%s` does not exist", fileName); 203*61c4878aSAndroid Build Coastguard Worker } 204*61c4878aSAndroid Build Coastguard Worker 205*61c4878aSAndroid Build Coastguard Worker byte[] data; 206*61c4878aSAndroid Build Coastguard Worker try { 207*61c4878aSAndroid Build Coastguard Worker data = Files.readAllBytes(fileName); 208*61c4878aSAndroid Build Coastguard Worker } catch (IOException e) { 209*61c4878aSAndroid Build Coastguard Worker logger.atSevere().log("Failed to read input file `%s`", fileName); 210*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Failed to read input file on write to server", e); 211*61c4878aSAndroid Build Coastguard Worker } 212*61c4878aSAndroid Build Coastguard Worker 213*61c4878aSAndroid Build Coastguard Worker try { 214*61c4878aSAndroid Build Coastguard Worker client.write(resourceId, data, initial_offset).get(); 215*61c4878aSAndroid Build Coastguard Worker } catch (ExecutionException e) { 216*61c4878aSAndroid Build Coastguard Worker if (((TransferError) e.getCause()).status() != expected_status) { 217*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Unexpected transfer write failure", e); 218*61c4878aSAndroid Build Coastguard Worker } 219*61c4878aSAndroid Build Coastguard Worker return; 220*61c4878aSAndroid Build Coastguard Worker } catch (InterruptedException e) { 221*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Write to server failed", e); 222*61c4878aSAndroid Build Coastguard Worker } 223*61c4878aSAndroid Build Coastguard Worker 224*61c4878aSAndroid Build Coastguard Worker if (expected_status != Status.OK) { 225*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Transfer succeeded unexpectedly"); 226*61c4878aSAndroid Build Coastguard Worker } 227*61c4878aSAndroid Build Coastguard Worker } 228*61c4878aSAndroid Build Coastguard Worker main(String[] args)229*61c4878aSAndroid Build Coastguard Worker public static void main(String[] args) { 230*61c4878aSAndroid Build Coastguard Worker if (args.length != 1) { 231*61c4878aSAndroid Build Coastguard Worker logger.atSevere().log("Usage: PORT"); 232*61c4878aSAndroid Build Coastguard Worker System.exit(1); 233*61c4878aSAndroid Build Coastguard Worker } 234*61c4878aSAndroid Build Coastguard Worker 235*61c4878aSAndroid Build Coastguard Worker // The port is provided directly as a commandline argument. 236*61c4878aSAndroid Build Coastguard Worker int port = Integer.parseInt(args[0]); 237*61c4878aSAndroid Build Coastguard Worker 238*61c4878aSAndroid Build Coastguard Worker ConfigProtos.ClientConfig config; 239*61c4878aSAndroid Build Coastguard Worker try { 240*61c4878aSAndroid Build Coastguard Worker config = ParseConfigFrom(System.in); 241*61c4878aSAndroid Build Coastguard Worker } catch (IOException e) { 242*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Failed to parse config file from stdin", e); 243*61c4878aSAndroid Build Coastguard Worker } 244*61c4878aSAndroid Build Coastguard Worker 245*61c4878aSAndroid Build Coastguard Worker Socket socket; 246*61c4878aSAndroid Build Coastguard Worker try { 247*61c4878aSAndroid Build Coastguard Worker socket = new Socket(HOSTNAME, port); 248*61c4878aSAndroid Build Coastguard Worker } catch (IOException e) { 249*61c4878aSAndroid Build Coastguard Worker logger.atSevere().log("Failed to connect to %s:%d", HOSTNAME, port); 250*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Failed to connect to server/proxy port", e); 251*61c4878aSAndroid Build Coastguard Worker } 252*61c4878aSAndroid Build Coastguard Worker try { 253*61c4878aSAndroid Build Coastguard Worker socket.setSendBufferSize(MAX_SOCKET_SEND_BUFFER_SIZE); 254*61c4878aSAndroid Build Coastguard Worker } catch (SocketException e) { 255*61c4878aSAndroid Build Coastguard Worker logger.atSevere().log("Invalid socket buffer size %d", MAX_SOCKET_SEND_BUFFER_SIZE); 256*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Invalid socket buffer size", e); 257*61c4878aSAndroid Build Coastguard Worker } 258*61c4878aSAndroid Build Coastguard Worker InputStream reader; 259*61c4878aSAndroid Build Coastguard Worker OutputStream writer; 260*61c4878aSAndroid Build Coastguard Worker 261*61c4878aSAndroid Build Coastguard Worker try { 262*61c4878aSAndroid Build Coastguard Worker writer = socket.getOutputStream(); 263*61c4878aSAndroid Build Coastguard Worker reader = socket.getInputStream(); 264*61c4878aSAndroid Build Coastguard Worker } catch (IOException e) { 265*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Failed to open socket streams", e); 266*61c4878aSAndroid Build Coastguard Worker } 267*61c4878aSAndroid Build Coastguard Worker 268*61c4878aSAndroid Build Coastguard Worker JavaClient hdlc_rpc_client = new JavaClient(writer, reader); 269*61c4878aSAndroid Build Coastguard Worker 270*61c4878aSAndroid Build Coastguard Worker hdlc_rpc_client.startClient(); 271*61c4878aSAndroid Build Coastguard Worker 272*61c4878aSAndroid Build Coastguard Worker TransferClient client = new TransferClient( 273*61c4878aSAndroid Build Coastguard Worker hdlc_rpc_client.getRpcClient().method(CHANNEL_ID, TransferService.get().name() + "/Read"), 274*61c4878aSAndroid Build Coastguard Worker hdlc_rpc_client.getRpcClient().method(CHANNEL_ID, TransferService.get().name() + "/Write"), 275*61c4878aSAndroid Build Coastguard Worker TransferTimeoutSettings.builder() 276*61c4878aSAndroid Build Coastguard Worker .setTimeoutMillis(config.getChunkTimeoutMs()) 277*61c4878aSAndroid Build Coastguard Worker .setInitialTimeoutMillis(config.getInitialChunkTimeoutMs()) 278*61c4878aSAndroid Build Coastguard Worker .setMaxRetries(config.getMaxRetries()) 279*61c4878aSAndroid Build Coastguard Worker .setMaxLifetimeRetries(config.getMaxLifetimeRetries()) 280*61c4878aSAndroid Build Coastguard Worker .build()); 281*61c4878aSAndroid Build Coastguard Worker 282*61c4878aSAndroid Build Coastguard Worker for (ConfigProtos.TransferAction action : config.getTransferActionsList()) { 283*61c4878aSAndroid Build Coastguard Worker int resourceId = action.getResourceId(); 284*61c4878aSAndroid Build Coastguard Worker Path fileName = Paths.get(action.getFilePath()); 285*61c4878aSAndroid Build Coastguard Worker 286*61c4878aSAndroid Build Coastguard Worker if (action.getProtocolVersion() != TransferAction.ProtocolVersion.UNKNOWN_VERSION) { 287*61c4878aSAndroid Build Coastguard Worker client.setProtocolVersion(ProtocolVersion.values()[action.getProtocolVersionValue()]); 288*61c4878aSAndroid Build Coastguard Worker } else { 289*61c4878aSAndroid Build Coastguard Worker client.setProtocolVersion(ProtocolVersion.latest()); 290*61c4878aSAndroid Build Coastguard Worker } 291*61c4878aSAndroid Build Coastguard Worker try { 292*61c4878aSAndroid Build Coastguard Worker if (action.getTransferType() == ConfigProtos.TransferAction.TransferType.WRITE_TO_SERVER) { 293*61c4878aSAndroid Build Coastguard Worker WriteToServer(resourceId, 294*61c4878aSAndroid Build Coastguard Worker fileName, 295*61c4878aSAndroid Build Coastguard Worker client, 296*61c4878aSAndroid Build Coastguard Worker Status.fromCode(action.getExpectedStatus().getNumber()), 297*61c4878aSAndroid Build Coastguard Worker action.getInitialOffset()); 298*61c4878aSAndroid Build Coastguard Worker } else if (action.getTransferType() 299*61c4878aSAndroid Build Coastguard Worker == ConfigProtos.TransferAction.TransferType.READ_FROM_SERVER) { 300*61c4878aSAndroid Build Coastguard Worker ReadFromServer(resourceId, 301*61c4878aSAndroid Build Coastguard Worker fileName, 302*61c4878aSAndroid Build Coastguard Worker client, 303*61c4878aSAndroid Build Coastguard Worker Status.fromCode(action.getExpectedStatus().getNumber()), 304*61c4878aSAndroid Build Coastguard Worker action.getInitialOffset()); 305*61c4878aSAndroid Build Coastguard Worker } else { 306*61c4878aSAndroid Build Coastguard Worker throw new AssertionError("Unknown transfer action type"); 307*61c4878aSAndroid Build Coastguard Worker } 308*61c4878aSAndroid Build Coastguard Worker } catch (AssertionError e) { 309*61c4878aSAndroid Build Coastguard Worker System.exit(1); 310*61c4878aSAndroid Build Coastguard Worker } 311*61c4878aSAndroid Build Coastguard Worker } 312*61c4878aSAndroid Build Coastguard Worker 313*61c4878aSAndroid Build Coastguard Worker logger.atInfo().log("Transfer completed successfully"); 314*61c4878aSAndroid Build Coastguard Worker 315*61c4878aSAndroid Build Coastguard Worker System.exit(0); 316*61c4878aSAndroid Build Coastguard Worker } 317*61c4878aSAndroid Build Coastguard Worker } 318