keystore_client shared library

Add a libkeystore_client.so library for clients to use.

Add const-correctness to the keystore.cpp classes.

Increase maximum arguments for future work.

Change-Id: Ia22f8b893aea3115a7b4a0543ad392c17c8528f2
diff --git a/keystore/keystore_client.cpp b/keystore/keystore_client.cpp
new file mode 100644
index 0000000..db9eb68
--- /dev/null
+++ b/keystore/keystore_client.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2012 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 <keystore.h>
+#include <keystore_client.h>
+
+#include <cutils/sockets.h>
+
+#define LOG_TAG "keystore_client"
+#include <cutils/log.h>
+
+ResponseCode keystore_cmd(command_code_t cmd, Keystore_Reply* reply, int numArgs, ...) {
+    int sock;
+
+    sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+    if (sock == -1) {
+        return SYSTEM_ERROR;
+    }
+
+    if (TEMP_FAILURE_RETRY(send(sock, &cmd, 1, MSG_NOSIGNAL)) != 1) {
+        close(sock);
+        return SYSTEM_ERROR;
+    }
+
+    va_list vl;
+    va_start(vl, numArgs);
+    for (int i = 0; i < numArgs; i++) {
+        size_t argLen = va_arg(vl, size_t);
+        uint8_t* arg = va_arg(vl, uint8_t*);
+
+        if (argLen > KEYSTORE_MESSAGE_SIZE) {
+            ALOGE("code called us with an argLen out of bounds: %llu", (unsigned long long) argLen);
+            close(sock);
+            return SYSTEM_ERROR;
+        }
+
+        uint8_t bytes[2] = { argLen >> 8, argLen };
+        if (TEMP_FAILURE_RETRY(send(sock, bytes, 2, MSG_NOSIGNAL)) != 2
+                || TEMP_FAILURE_RETRY(send(sock, arg, argLen, MSG_NOSIGNAL))
+                        != static_cast<ssize_t>(argLen)) {
+            ALOGW("truncated write to keystore");
+            close(sock);
+            return SYSTEM_ERROR;
+        }
+    }
+    va_end(vl);
+
+    uint8_t code = 0;
+    if (shutdown(sock, SHUT_WR) != 0
+            || TEMP_FAILURE_RETRY(recv(sock, &code, 1, 0)) != 1
+            || code != NO_ERROR) {
+        ALOGW("Error from keystore: %d", code);
+        close(sock);
+        return SYSTEM_ERROR;
+    }
+
+    if (reply != NULL) {
+        reply->setCode(static_cast<ResponseCode>(code));
+
+        uint8_t bytes[2];
+        uint8_t* data = reply->get();
+        if (TEMP_FAILURE_RETRY(recv(sock, &bytes[0], 1, 0)) == 1
+                && TEMP_FAILURE_RETRY(recv(sock, &bytes[1], 1, 0)) == 1) {
+            int offset = 0;
+            int length = bytes[0] << 8 | bytes[1];
+            while (offset < length) {
+                int n = TEMP_FAILURE_RETRY(recv(sock, &data[offset], length - offset, 0));
+                if (n <= 0) {
+                    ALOGW("truncated read from keystore for data");
+                    code = SYSTEM_ERROR;
+                    break;
+                }
+                offset += n;
+            }
+            reply->setLength(length);
+        } else {
+            ALOGW("truncated read from keystore for length");
+            code = SYSTEM_ERROR;
+        }
+    }
+
+    close(sock);
+    return static_cast<ResponseCode>(code);
+}
+
+Keystore_Reply::Keystore_Reply()
+        : mCode(SYSTEM_ERROR)
+        , mLength(-1) {
+    mData = new uint8_t[KEYSTORE_MESSAGE_SIZE];
+}
+
+Keystore_Reply::~Keystore_Reply() {
+    delete[] mData;
+}
+
+uint8_t* Keystore_Reply::get() {
+    return mData;
+}
+
+void Keystore_Reply::setLength(size_t length) {
+    mLength = length;
+}
+
+size_t Keystore_Reply::length() const {
+    return mLength;
+}
+
+void Keystore_Reply::setCode(ResponseCode code) {
+    mCode = code;
+}
+
+ResponseCode Keystore_Reply::code() const {
+    return mCode;
+}
+
+uint8_t* Keystore_Reply::release() {
+    uint8_t* data = mData;
+    mData = NULL;
+    return data;
+}