KeyStore.java revision 5423e68d5dbe048ec6f042cce52a33f94184e9fb
144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh/*
244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * Copyright (C) 2009 The Android Open Source Project
344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh *
444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License");
544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * you may not use this file except in compliance with the License.
644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * You may obtain a copy of the License at
744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh *
844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh *      http://www.apache.org/licenses/LICENSE-2.0
944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh *
1044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software
1144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS,
1244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * See the License for the specific language governing permissions and
1444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * limitations under the License.
1544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh */
1644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
1744039172627d1c15737ea73836ad375559d76211Chia-chi Yehpackage android.security;
1844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
1944039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport android.net.LocalSocketAddress;
2044039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport android.net.LocalSocket;
2144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
2244039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport java.io.InputStream;
2344039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport java.io.IOException;
2444039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport java.io.OutputStream;
2534c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevichimport java.io.UnsupportedEncodingException;
2646703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstromimport java.nio.charset.Charsets;
2744039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport java.util.ArrayList;
2844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
2944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh/**
3046703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom * @hide This should not be made public in its present form because it
3146703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom * assumes that private and secret key bytes are available and would
3246703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom * preclude the use of hardware crypto.
3344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh */
3444039172627d1c15737ea73836ad375559d76211Chia-chi Yehpublic class KeyStore {
355cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom
365cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    // ResponseCodes
377e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int NO_ERROR = 1;
387e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int LOCKED = 2;
397e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int UNINITIALIZED = 3;
407e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int SYSTEM_ERROR = 4;
417e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int PROTOCOL_ERROR = 5;
427e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int PERMISSION_DENIED = 6;
437e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int KEY_NOT_FOUND = 7;
447e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int VALUE_CORRUPTED = 8;
457e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int UNDEFINED_ACTION = 9;
467e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int WRONG_PASSWORD = 10;
475cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom
485cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    // States
495cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
5044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
5144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    private static final LocalSocketAddress sAddress = new LocalSocketAddress(
5244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            "keystore", LocalSocketAddress.Namespace.RESERVED);
5344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
5444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    private int mError = NO_ERROR;
5544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
5644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    private KeyStore() {}
5744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
5844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public static KeyStore getInstance() {
5944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return new KeyStore();
6044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
6144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
625cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    public State state() {
6344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('t');
645cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        switch (mError) {
655cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom            case NO_ERROR: return State.UNLOCKED;
665cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom            case LOCKED: return State.LOCKED;
675cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom            case UNINITIALIZED: return State.UNINITIALIZED;
685cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom            default: throw new AssertionError(mError);
695cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        }
7044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
7144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
725cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private byte[] get(byte[] key) {
73d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh        ArrayList<byte[]> values = execute('g', key);
7434c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return (values == null || values.isEmpty()) ? null : values.get(0);
7544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
7644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
775cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    public byte[] get(String key) {
785cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        return get(getBytes(key));
7944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
8044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
815cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private boolean put(byte[] key, byte[] value) {
8244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('i', key, value);
8344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
8444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
8544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
865cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    public boolean put(String key, byte[] value) {
875cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        return put(getBytes(key), value);
8844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
8944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
905cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private boolean delete(byte[] key) {
9144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('d', key);
9244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
9344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
9444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
9544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean delete(String key) {
9634c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return delete(getBytes(key));
9744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
9844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
995cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private boolean contains(byte[] key) {
10044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('e', key);
10144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
10244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
10344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
10444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean contains(String key) {
10534c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return contains(getBytes(key));
10644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
10744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
108613fcc850686dfe71cec9809c3694be9cf02cdc7Chia-chi Yeh    public byte[][] saw(byte[] prefix) {
109d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh        ArrayList<byte[]> values = execute('s', prefix);
110d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh        return (values == null) ? null : values.toArray(new byte[values.size()][]);
11144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
11244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
113613fcc850686dfe71cec9809c3694be9cf02cdc7Chia-chi Yeh    public String[] saw(String prefix) {
11434c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        byte[][] values = saw(getBytes(prefix));
11544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        if (values == null) {
11644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            return null;
11744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
11844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        String[] strings = new String[values.length];
11944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        for (int i = 0; i < values.length; ++i) {
12034c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich            strings[i] = toString(values[i]);
12144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
12244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return strings;
12344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
12444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
12544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean reset() {
12644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('r');
12744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
12844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
12944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
1305cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private boolean password(byte[] password) {
1315cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        execute('p', password);
13244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
13344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
13444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
13544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean password(String password) {
13634c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return password(getBytes(password));
13744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
13844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
13944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean lock() {
14044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('l');
14144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
14244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
14344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
1445cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private boolean unlock(byte[] password) {
14544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('u', password);
14644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
14744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
14844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
14944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean unlock(String password) {
15034c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return unlock(getBytes(password));
15144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
15244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
1535cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    public boolean isEmpty() {
1545cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        execute('z');
1555cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        return mError == KEY_NOT_FOUND;
1565cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    }
1575cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom
1585423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    private boolean generate(byte[] key) {
1595423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        execute('a', key);
1605423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return mError == NO_ERROR;
1615423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
1625423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
1635423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    public boolean generate(String key) {
1645423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return generate(getBytes(key));
1655423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
1665423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
1675423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    private boolean importKey(byte[] keyName, byte[] key) {
1685423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        execute('m', keyName, key);
1695423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return mError == NO_ERROR;
1705423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
1715423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
1725423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    public boolean importKey(String keyName, byte[] key) {
1735423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return importKey(getBytes(keyName), key);
1745423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
1755423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
1765423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    private byte[] getPubkey(byte[] key) {
1775423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        ArrayList<byte[]> values = execute('b', key);
1785423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return (values == null || values.isEmpty()) ? null : values.get(0);
1795423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
1805423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
1815423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    public byte[] getPubkey(String key) {
1825423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return getPubkey(getBytes(key));
1835423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
1845423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
1855423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    private boolean delKey(byte[] key) {
1865423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        execute('k', key);
1875423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return mError == NO_ERROR;
1885423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
1895423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
1905423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    public boolean delKey(String key) {
1915423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return delKey(getBytes(key));
1925423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
1935423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
1945423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    private byte[] sign(byte[] keyName, byte[] data) {
1955423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        final ArrayList<byte[]> values = execute('n', keyName, data);
1965423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return (values == null || values.isEmpty()) ? null : values.get(0);
1975423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
1985423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
1995423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    public byte[] sign(String key, byte[] data) {
2005423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return sign(getBytes(key), data);
2015423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
2025423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
2035423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    private boolean verify(byte[] keyName, byte[] data, byte[] signature) {
2045423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        execute('v', keyName, data, signature);
2055423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return mError == NO_ERROR;
2065423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
2075423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
2085423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    public boolean verify(String key, byte[] data, byte[] signature) {
2095423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return verify(getBytes(key), data, signature);
2105423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
2115423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
2125423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    private boolean grant(byte[] key, byte[] uid) {
2135423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        execute('x', key, uid);
2145423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return mError == NO_ERROR;
2155423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
2165423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
2175423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    public boolean grant(String key, int uid) {
2185423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return grant(getBytes(key), Integer.toString(uid).getBytes());
2195423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
2205423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
2215423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    private boolean ungrant(byte[] key, byte[] uid) {
2225423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        execute('y', key, uid);
2235423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return mError == NO_ERROR;
2245423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
2255423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
2265423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    public boolean ungrant(String key, int uid) {
2275423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root        return ungrant(getBytes(key), Integer.toString(uid).getBytes());
2285423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root    }
2295423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root
23044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public int getLastError() {
23144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError;
23244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
23344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
234d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    private ArrayList<byte[]> execute(int code, byte[]... parameters) {
23544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        mError = PROTOCOL_ERROR;
23644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
23744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        for (byte[] parameter : parameters) {
23844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            if (parameter == null || parameter.length > 65535) {
23944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                return null;
24044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
24144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
24244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
24344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        LocalSocket socket = new LocalSocket();
24444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        try {
24544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            socket.connect(sAddress);
24644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
24744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            OutputStream out = socket.getOutputStream();
24844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            out.write(code);
24944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            for (byte[] parameter : parameters) {
25044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                out.write(parameter.length >> 8);
25144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                out.write(parameter.length);
25244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                out.write(parameter);
25344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
25444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            out.flush();
25544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            socket.shutdownOutput();
25644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
25744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            InputStream in = socket.getInputStream();
258f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh            if ((code = in.read()) != NO_ERROR) {
259f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh                if (code != -1) {
260f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh                    mError = code;
261f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh                }
26244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                return null;
26344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
26444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
265d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh            ArrayList<byte[]> values = new ArrayList<byte[]>();
26644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            while (true) {
26744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                int i, j;
26844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                if ((i = in.read()) == -1) {
26944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                    break;
27044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                }
27144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                if ((j = in.read()) == -1) {
27244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                    return null;
27344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                }
274d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                byte[] value = new byte[i << 8 | j];
275d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                for (i = 0; i < value.length; i += j) {
276d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                    if ((j = in.read(value, i, value.length - i)) == -1) {
27744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                        return null;
27844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                    }
27944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                }
280d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                values.add(value);
28144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
282f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh            mError = NO_ERROR;
283d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh            return values;
28444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        } catch (IOException e) {
28544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            // ignore
28644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        } finally {
28744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            try {
28844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                socket.close();
28944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            } catch (IOException e) {}
29044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
29144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return null;
29244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
29334c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich
29434c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    private static byte[] getBytes(String string) {
29546703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom        return string.getBytes(Charsets.UTF_8);
29634c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    }
29734c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich
29834c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    private static String toString(byte[] bytes) {
29946703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom        return new String(bytes, Charsets.UTF_8);
30034c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    }
30144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh}
302