Create common utilities for allocd clients/servers

Adds utilities for sending and receiving data from SharedFds
that checks for socket errors and logs failures.
Also provides a set of convenience APIs for sending/receiving
JSON mesages through a SharedFd.

SendAll() API will send the entire contents of a string
message on the provided socket. In case of error, the send
operation will abort, and SendAll will return false.

Similarly, RecvAll() Reads a string message of size 'count'
on the provided socket. On failure, it returns an empty
string, and on success it returns a new std::string with the
sent message.

Bug: 148823285
Test: make -j
Change-Id: I0cefc74cb68bc3e489d7d10cdfbfa742e54b07d9
diff --git a/common/libs/fs/shared_buf.cc b/common/libs/fs/shared_buf.cc
index 574d837..61ff51e 100644
--- a/common/libs/fs/shared_buf.cc
+++ b/common/libs/fs/shared_buf.cc
@@ -94,4 +94,36 @@
   return WriteAll(fd, buf.data(), buf.size());
 }
 
+bool SendAll(SharedFD sock, const std::string& msg) {
+  ssize_t total_written{};
+  if (!sock->IsOpen()) {
+    return false;
+  }
+  while (total_written < static_cast<ssize_t>(msg.size())) {
+    auto just_written = sock->Send(msg.c_str() + total_written,
+                                   msg.size() - total_written, MSG_NOSIGNAL);
+    if (just_written <= 0) {
+      return false;
+    }
+    total_written += just_written;
+  }
+  return true;
+}
+
+std::string RecvAll(SharedFD sock, const size_t count) {
+  size_t total_read{};
+  if (!sock->IsOpen()) {
+    return {};
+  }
+  std::unique_ptr<char[]> data(new char[count]);
+  while (total_read < count) {
+    auto just_read = sock->Read(data.get() + total_read, count - total_read);
+    if (just_read <= 0) {
+      return {};
+    }
+    total_read += just_read;
+  }
+  return {data.get(), count};
+}
+
 } // namespace cuttlefish
diff --git a/common/libs/fs/shared_buf.h b/common/libs/fs/shared_buf.h
index c61222f..0b47bd9 100644
--- a/common/libs/fs/shared_buf.h
+++ b/common/libs/fs/shared_buf.h
@@ -118,4 +118,23 @@
   return WriteAll(fd, (const char*) binary_data, sizeof(*binary_data));
 }
 
+/**
+ * Sends contents of msg through sock, checking for socket error conditions
+ *
+ * On successful Send, returns true
+ *
+ * If a Send error is encountered, returns false. Some data may have already
+ * been written to 'sock' at that point.
+ */
+bool SendAll(SharedFD sock, const std::string& msg);
+
+/**
+ * Receives 'count' bytes from sock, checking for socket error conditions
+ *
+ * On successful Recv, returns a string containing the received data
+ *
+ * If a Recv error is encountered, returns the empty string
+ */
+std::string RecvAll(SharedFD sock, const size_t count);
+
 } // namespace cuttlefish
diff --git a/host/libs/allocd/utils.cpp b/host/libs/allocd/utils.cpp
new file mode 100644
index 0000000..d90f48c
--- /dev/null
+++ b/host/libs/allocd/utils.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "host/libs/allocd/utils.h"
+
+#include <cstdint>
+#include <optional>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/fs/shared_buf.h"
+#include "host/libs/allocd/request.h"
+
+namespace cuttlefish {
+
+constexpr uint16_t kCurHeaderVersion = 1;
+constexpr uint16_t kMinHeaderVersion = 1;
+
+bool SendJsonMsg(SharedFD client_socket, const Json::Value& resp) {
+  LOG(INFO) << "Sending JSON message";
+  Json::FastWriter writer;
+  auto resp_str = writer.write(resp);
+
+  std::string header_buff(sizeof(RequestHeader), 0);
+
+  // fill in header
+  RequestHeader* header = reinterpret_cast<RequestHeader*>(header_buff.data());
+  header->len = resp_str.size();
+  header->version = kCurHeaderVersion;
+
+  auto payload = header_buff + resp_str;
+
+  return SendAll(client_socket, payload);
+}
+
+std::optional<Json::Value> RecvJsonMsg(SharedFD client_socket) {
+  LOG(INFO) << "Receiving JSON message";
+  RequestHeader header;
+  client_socket->Recv(&header, sizeof(header), recv_flags);
+
+  if (header.version < kMinHeaderVersion) {
+    LOG(WARNING) << "bad request header version: " << header.version;
+    return std::nullopt;
+  }
+
+  std::string payload = RecvAll(client_socket, header.len);
+
+  JsonRequestReader reader;
+  return reader.parse(payload);
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/allocd/utils.h b/host/libs/allocd/utils.h
new file mode 100644
index 0000000..e426dae
--- /dev/null
+++ b/host/libs/allocd/utils.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <json/json.h>
+
+#include <optional>
+#include <string>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/allocd/request.h"
+#include "host/libs/config/logging.h"
+
+namespace cuttlefish {
+
+static constexpr int send_flags = 0;
+static constexpr int recv_flags = 0;
+
+// returns true if successfully sent the whole message
+bool SendJsonMsg(cuttlefish::SharedFD client_socket, const Json::Value& resp);
+
+std::optional<Json::Value> RecvJsonMsg(cuttlefish::SharedFD client_socket);
+
+}  // namespace cuttlefish