1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "tools/android/forwarder2/command.h"
6
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "base/logging.h"
13 #include "base/safe_strerror_posix.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_piece.h"
16 #include "tools/android/forwarder2/socket.h"
17
18 using base::StringPiece;
19
20 namespace {
21
22
23 // Command format:
24 // <port>:<type>
25 //
26 // Where:
27 // <port> is a 5-chars zero-padded ASCII decimal integer
28 // matching the target port for the command (e.g.
29 // '08080' for port 8080)
30 // <type> is a 3-char zero-padded ASCII decimal integer
31 // matching a command::Type value (e.g. 002 for
32 // ACK).
33 // The column (:) is used as a separator for easier reading.
34 const int kPortStringSize = 5;
35 const int kCommandTypeStringSize = 2;
36 // Command string size also includes the ':' separator char.
37 const int kCommandStringSize = kPortStringSize + kCommandTypeStringSize + 1;
38
39 } // namespace
40
41 namespace forwarder2 {
42
ReadCommand(Socket * socket,int * port_out,command::Type * command_type_out)43 bool ReadCommand(Socket* socket,
44 int* port_out,
45 command::Type* command_type_out) {
46 char command_buffer[kCommandStringSize + 1];
47 // To make logging easier.
48 command_buffer[kCommandStringSize] = '\0';
49
50 int bytes_read = socket->ReadNumBytes(command_buffer, kCommandStringSize);
51 if (bytes_read != kCommandStringSize) {
52 if (bytes_read < 0)
53 LOG(ERROR) << "Read() error: " << safe_strerror(errno);
54 else if (!bytes_read)
55 LOG(ERROR) << "Read() error, endpoint was unexpectedly closed.";
56 else
57 LOG(ERROR) << "Read() error, not enough data received from the socket.";
58 return false;
59 }
60
61 StringPiece port_str(command_buffer, kPortStringSize);
62 if (!StringToInt(port_str, port_out)) {
63 LOG(ERROR) << "Could not parse the command port string: "
64 << port_str;
65 return false;
66 }
67
68 StringPiece command_type_str(
69 &command_buffer[kPortStringSize + 1], kCommandTypeStringSize);
70 int command_type;
71 if (!StringToInt(command_type_str, &command_type)) {
72 LOG(ERROR) << "Could not parse the command type string: "
73 << command_type_str;
74 return false;
75 }
76 *command_type_out = static_cast<command::Type>(command_type);
77 return true;
78 }
79
SendCommand(command::Type command,int port,Socket * socket)80 bool SendCommand(command::Type command, int port, Socket* socket) {
81 char buffer[kCommandStringSize + 1];
82 int len = snprintf(buffer, sizeof(buffer), "%05d:%02d", port, command);
83 CHECK_EQ(len, kCommandStringSize);
84 // Write the full command minus the leading \0 char.
85 return socket->WriteNumBytes(buffer, len) == len;
86 }
87
ReceivedCommand(command::Type command,Socket * socket)88 bool ReceivedCommand(command::Type command, Socket* socket) {
89 int port;
90 command::Type received_command;
91 if (!ReadCommand(socket, &port, &received_command))
92 return false;
93 return received_command == command;
94 }
95
96 } // namespace forwarder
97