15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "tools/android/forwarder2/command.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/safe_strerror_posix.h"
145e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "tools/android/forwarder2/socket.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::StringPiece;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Command format:
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//      <port>:<type>
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Where:
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   <port> is a 5-chars zero-padded ASCII decimal integer
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//          matching the target port for the command (e.g.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//          '08080' for port 8080)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   <type> is a 3-char zero-padded ASCII decimal integer
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//          matching a command::Type value (e.g. 002 for
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//          ACK).
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The column (:) is used as a separator for easier reading.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kPortStringSize = 5;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kCommandTypeStringSize = 2;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Command string size also includes the ':' separator char.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kCommandStringSize = kPortStringSize + kCommandTypeStringSize + 1;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace forwarder2 {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReadCommand(Socket* socket,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 int* port_out,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 command::Type* command_type_out) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char command_buffer[kCommandStringSize + 1];
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To make logging easier.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_buffer[kCommandStringSize] = '\0';
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bytes_read = socket->ReadNumBytes(command_buffer, kCommandStringSize);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bytes_read != kCommandStringSize) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bytes_read < 0)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Read() error: " << safe_strerror(errno);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (!bytes_read)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Read() error, endpoint was unexpectedly closed.";
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Read() error, not enough data received from the socket.";
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringPiece port_str(command_buffer, kPortStringSize);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!StringToInt(port_str, port_out)) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Could not parse the command port string: "
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << port_str;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringPiece command_type_str(
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &command_buffer[kPortStringSize + 1], kCommandTypeStringSize);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int command_type;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!StringToInt(command_type_str, &command_type)) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Could not parse the command type string: "
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << command_type_str;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *command_type_out = static_cast<command::Type>(command_type);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SendCommand(command::Type command, int port, Socket* socket) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buffer[kCommandStringSize + 1];
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int len = snprintf(buffer, sizeof(buffer), "%05d:%02d", port, command);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(len, kCommandStringSize);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Write the full command minus the leading \0 char.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return socket->WriteNumBytes(buffer, len) == len;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReceivedCommand(command::Type command, Socket* socket) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int port;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command::Type received_command;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadCommand(socket, &port, &received_command))
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return received_command == command;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace forwarder
97