[System Monitor] Add grpc to harvester and dockyard_host

This CL adds a dockyard_host test application and demonstrates a round-trip
communication between the host and fuchsia device over grpc.

Test: see bin/system_monitor/dockyard_host/README.md
Change-Id: I165bda8da3d21f39f64090b2424916f7d5764a72
diff --git a/bin/system_monitor/dockyard_host/BUILD.gn b/bin/system_monitor/dockyard_host/BUILD.gn
new file mode 100644
index 0000000..c19b4ac
--- /dev/null
+++ b/bin/system_monitor/dockyard_host/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/host.gni")
+
+if (current_toolchain == host_toolchain) {
+executable("dockyard_host") {
+  sources = [
+    "dockyard_host.cc",
+  ]
+
+  deps = [
+    "//third_party/grpc:grpc++",
+    "//garnet/lib/system_monitor/dockyard:lib",
+  ]
+}
+}
+
+install_host_tools("host_tools") {
+  deps = [
+    ":dockyard_host",
+  ]
+  outputs = [
+    "dockyard_host",
+  ]
+}
diff --git a/bin/system_monitor/dockyard_host/README.md b/bin/system_monitor/dockyard_host/README.md
new file mode 100644
index 0000000..a31a4fa
--- /dev/null
+++ b/bin/system_monitor/dockyard_host/README.md
@@ -0,0 +1,32 @@
+# Dockyard Host
+
+The `dockyard_host` is a host (developer machine) server that runs the Fuchsia
+System Monitor Dockyard without a GUI. The initial development is primarily for
+testing, though this could evolve into an independent host Dockyard.
+
+To be effective, a dockyard needs a connection to a running harvester. The
+harvester will transmit sample data to the dockyard for storage.
+
+## To test
+
+In one terminal window run
+```
+$ out/x64/host_x64/dockyard_host
+Starting dockyard host
+Server listening on 0.0.0.0:50051
+```
+
+In a second terminal window run
+```
+$ killall -r qemu-; fx run -N -u $FUCHSIA_DIR/scripts/start-dhcp-server.sh
+<there will be a lot of output, after it calms down>
+$ system_monitor_harvester 192.168.3.53:50051
+harvester received: Hello world
+```
+If the harvester is not able to connect to the dockyard_host, try using your
+host's local IP instead of 192.168.3.53 (see `ifconfig` for your IP addresses).
+
+The message `Hello world` means that a connection and round-trip communication
+was done (which all the dockyard_host and harvester do so far).
+
+See also: ../README.md
diff --git a/bin/system_monitor/dockyard_host/dockyard_host.cc b/bin/system_monitor/dockyard_host/dockyard_host.cc
new file mode 100644
index 0000000..592c6e1
--- /dev/null
+++ b/bin/system_monitor/dockyard_host/dockyard_host.cc
@@ -0,0 +1,59 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include <grpc++/grpc++.h>
+
+#include "garnet/lib/system_monitor/protos/dockyard.grpc.pb.h"
+
+using dockyard::Greeter;
+using dockyard::HelloReply;
+using dockyard::HelloRequest;
+using grpc::Server;
+using grpc::ServerBuilder;
+using grpc::ServerContext;
+using grpc::Status;
+
+constexpr char DEFAULT_SERVER_ADDRESS[] = "0.0.0.0:50051";
+
+// Logic and data behind the server's behavior.
+class DockyardServiceImpl final : public Greeter::Service {
+  Status SayHello(ServerContext* context, const HelloRequest* request,
+                  HelloReply* reply) override {
+    std::string prefix("Hello ");
+    reply->set_message(prefix + request->name());
+    return Status::OK;
+  }
+};
+
+// Listen for Harvester connections from the Fuchsia device.
+void RunGrpcServer(const char* listen_at) {
+  // This is an arbitrary default port.
+  std::string server_address(listen_at);
+  DockyardServiceImpl service;
+
+  ServerBuilder builder;
+  // Listen on the given address without any authentication mechanism.
+  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+  // Register "service" as the instance through which we'll communicate with
+  // clients. In this case it corresponds to a *synchronous* service.
+  builder.RegisterService(&service);
+  // Finally assemble the server.
+  std::unique_ptr<Server> server(builder.BuildAndStart());
+  std::cout << "Server listening on " << server_address << std::endl;
+
+  // Wait for the server to shutdown. Note that some other thread must be
+  // responsible for shutting down the server for this call to ever return.
+  server->Wait();
+}
+
+int main(int argc, char** argv) {
+  std::cout << "Starting dockyard host" << std::endl;
+  RunGrpcServer(DEFAULT_SERVER_ADDRESS);
+
+  return 0;
+}
diff --git a/bin/system_monitor/harvester/BUILD.gn b/bin/system_monitor/harvester/BUILD.gn
index 70845d0..874e92f 100644
--- a/bin/system_monitor/harvester/BUILD.gn
+++ b/bin/system_monitor/harvester/BUILD.gn
@@ -12,6 +12,9 @@
   ]
 
   deps = [
+    "//third_party/grpc:grpc++",
+    "//garnet/lib/system_monitor/dockyard:protos",
+    "//garnet/lib/system_monitor/dockyard:lib",
   ]
 }
 
diff --git a/bin/system_monitor/harvester/README.md b/bin/system_monitor/harvester/README.md
index da4b8f5..699ed51b 100644
--- a/bin/system_monitor/harvester/README.md
+++ b/bin/system_monitor/harvester/README.md
@@ -6,3 +6,11 @@
 The Harvester should not unduly impact the Fuchsia device being monitored.
 So the Harvester does not store samples. Instead the samples are moved to
 the Dockyard as soon as reasonable.
+
+## qemu
+
+On the host, run
+$ fx run -N -u $FUCHSIA_DIR/scripts/start-dhcp-server.sh
+
+Tip: If you're doing edit-compile-run development, you might prefer this:
+$ killall -r qemu-; fx build && fx run -N -u $FUCHSIA_DIR/scripts/start-dhcp-server.sh
diff --git a/bin/system_monitor/harvester/harvester.cc b/bin/system_monitor/harvester/harvester.cc
index 1bbb3e1..21fc171 100644
--- a/bin/system_monitor/harvester/harvester.cc
+++ b/bin/system_monitor/harvester/harvester.cc
@@ -2,17 +2,77 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <stdio.h>
-
 /*
     Hey, so there's not a whole lot here. That's because this is a work in
     progress. Starting from something like a hello world program, this will
     progress into a System Monitor for Fuchsia.
 
+    The code below is largely straight out of the grpc hello world example.
+
     See also: ./README.md
 */
 
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include <grpc++/grpc++.h>
+
+#include "garnet/lib/system_monitor/protos/dockyard.grpc.pb.h"
+
+using dockyard::Greeter;
+using dockyard::HelloReply;
+using dockyard::HelloRequest;
+using grpc::Channel;
+using grpc::ClientContext;
+using grpc::Status;
+
+class Harvester {
+ public:
+  Harvester(std::shared_ptr<Channel> channel)
+      : stub_(Greeter::NewStub(channel)) {}
+
+  std::string SayHello(const std::string& user) {
+    // Data we are sending to the server.
+    HelloRequest request;
+    request.set_name(user);
+
+    // Container for the data we expect from the server.
+    HelloReply reply;
+
+    // Context for the client. It could be used to convey extra information to
+    // the server and/or tweak certain RPC behaviors.
+    ClientContext context;
+
+    // The actual RPC.
+    Status status = stub_->SayHello(&context, request, &reply);
+    if (status.ok()) {
+      return reply.message();
+    } else {
+      std::cout << status.error_code() << ": " << status.error_message()
+                << std::endl;
+      return "Unable to send to dockyard.";
+    }
+  }
+
+ private:
+  std::unique_ptr<Greeter::Stub> stub_;
+};
+
 int main(int argc, char** argv) {
-  printf("System Monitor Harvester - wip\n");
+  printf("System Monitor Harvester - wip 5\n");
+  if (argc < 2) {
+    std::cout << "Please specify an IP:Port, such as localhost:50051"
+              << std::endl;
+    exit(1);
+  }
+  // TODO(dschuyler): This channel isn't authenticated
+  // (InsecureChannelCredentials()).
+  Harvester harvester(
+      grpc::CreateChannel(argv[1], grpc::InsecureChannelCredentials()));
+  std::string user("world");
+  std::string reply = harvester.SayHello(user);
+  std::cout << "harvester received: " << reply << std::endl;
+
   return 0;
-}
\ No newline at end of file
+}
diff --git a/lib/system_monitor/dockyard/BUILD.gn b/lib/system_monitor/dockyard/BUILD.gn
index 85020c0..67b5899 100644
--- a/lib/system_monitor/dockyard/BUILD.gn
+++ b/lib/system_monitor/dockyard/BUILD.gn
@@ -2,13 +2,36 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-source_set("system_monitor_dockyard") {
+import("//third_party/protobuf/proto_library.gni")
+
+source_set("lib") {
   sources = [
     "dockyard.cc",
     "dockyard.h",
     "test_sample_generator.cc",
     "test_sample_generator.h",
   ]
+  public_deps = [
+    ":protos",
+  ]
+}
+
+proto_library("protos") {
+  sources = [
+    "../protos/dockyard.proto",
+  ]
+
+  generate_python = false
+  cc_generator_options = "lite"
+  generator_plugin_suffix = ".grpc.pb"
+  generator_plugin_label = "//third_party/grpc:grpc_cpp_plugin"
+
+  import_dirs = [
+    #"//garnet/lib/system_monitor/protos",
+  ]
+  deps = [
+    "//third_party/grpc:grpc++",
+  ]
 }
 
 source_set("tests") {
@@ -19,7 +42,7 @@
   ]
 
   deps = [
-     ":system_monitor_dockyard",
+     ":lib",
      "//third_party/googletest:gtest",
   ]
 }
diff --git a/lib/system_monitor/protos/dockyard.proto b/lib/system_monitor/protos/dockyard.proto
new file mode 100644
index 0000000..00385a4
--- /dev/null
+++ b/lib/system_monitor/protos/dockyard.proto
@@ -0,0 +1,28 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "io.grpc.system_monitor.dockyard";
+option java_outer_classname = "DockyardProto";
+option objc_class_prefix = "HLW";
+
+package dockyard;
+
+// The greeting service definition.
+service Greeter {
+  // Sends a greeting
+  rpc SayHello (HelloRequest) returns (HelloReply) {}
+}
+
+// The request message containing the user's name.
+message HelloRequest {
+  string name = 1;
+}
+
+// The response message containing the greetings
+message HelloReply {
+  string message = 1;
+}
diff --git a/packages/products/devtools b/packages/products/devtools
index a656e84..1117440 100644
--- a/packages/products/devtools
+++ b/packages/products/devtools
@@ -10,6 +10,7 @@
     "garnet/packages/prod/ssh",
     "garnet/packages/prod/tracing",
     "garnet/packages/products/base",
+    "garnet/packages/tools/dockyard_host",
     "garnet/packages/tools/zxdb"
   ]
 }
diff --git a/packages/tools/all b/packages/tools/all
index a2720d7..a2e0cdd 100644
--- a/packages/tools/all
+++ b/packages/tools/all
@@ -3,6 +3,7 @@
         "garnet/packages/tools/audio",
         "garnet/packages/tools/bluetooth",
         "garnet/packages/tools/curl",
+        "garnet/packages/tools/dockyard_host",
         "garnet/packages/tools/fidlmerge",
         "garnet/packages/tools/iperf",
         "garnet/packages/tools/make-efi",
diff --git a/packages/tools/dockyard_host b/packages/tools/dockyard_host
new file mode 100644
index 0000000..19383a6
--- /dev/null
+++ b/packages/tools/dockyard_host
@@ -0,0 +1,5 @@
+{
+    "labels": [
+        "//garnet/bin/system_monitor/dockyard_host:host_tools"
+    ]
+}