Merge changes I1a27459b,I3e9c53c3,I91082f58,I395e5361

* changes:
  Revert "Revert "Fastbootd: flashing certification""
  Fastbootd: auto ssh server start
  Fastbootd: network auto discovery
  Fastbootd: socket and network transport
diff --git a/fastbootd/Android.mk b/fastbootd/Android.mk
index f7c67a9..0f32dbf 100644
--- a/fastbootd/Android.mk
+++ b/fastbootd/Android.mk
@@ -18,6 +18,7 @@
 
 LOCAL_C_INCLUDES := \
     external/openssl/include \
+    external/mdnsresponder/mDNSShared \
     $(LOCAL_PATH)/include \
     external/zlib/ \
 
@@ -30,19 +31,25 @@
     commands/virtual_partitions.c \
     fastbootd.c \
     protocol.c \
+    network_discovery.c \
+    socket_client.c \
+    secure.c \
     transport.c \
+    transport_socket.c \
     trigger.c \
     usb_linux_client.c \
-    utils.c
+    utils.c \
 
 LOCAL_MODULE := fastbootd
 LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter -DFLASH_CERT
 LOCAL_LDFLAGS := -ldl
 
 LOCAL_SHARED_LIBRARIES := \
     libhardware \
-    libhardware_legacy
+    libcrypto \
+    libhardware_legacy \
+    libmdnssd
 
 LOCAL_STATIC_LIBRARIES := \
     libsparse_static \
diff --git a/fastbootd/commands.c b/fastbootd/commands.c
index 83e86b0..2f6e86a 100644
--- a/fastbootd/commands.c
+++ b/fastbootd/commands.c
@@ -52,6 +52,8 @@
 
 static void cmd_boot(struct protocol_handle *phandle, const char *arg)
 {
+    int sz, atags_sz, new_atags_sz;
+    int rv;
     unsigned kernel_actual;
     unsigned ramdisk_actual;
     unsigned second_actual;
@@ -59,9 +61,11 @@
     void *ramdisk_ptr;
     void *second_ptr;
     struct boot_img_hdr *hdr;
-    int sz, atags_sz, new_atags_sz;
-    int rv;
-    char *ptr = NULL, *atags_ptr = NULL, *new_atags = NULL;
+    char *ptr = NULL;
+    char *atags_ptr = NULL;
+    char *new_atags = NULL;
+    int data_fd = 0;
+
     D(DEBUG, "cmd_boot %s\n", arg);
 
     if (phandle->download_fd < 0) {
@@ -75,9 +79,18 @@
         goto error;
     }
 
-    sz = get_file_size(phandle->download_fd);
+    // TODO: With cms we can also verify partition name included as
+    // cms signed attribute
+    if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) {
+        fastboot_fail(phandle, "Access forbiden you need the certificate");
+        return;
+    }
+
+    sz = get_file_size(data_fd);
+
     ptr = (char *) mmap(NULL, sz, PROT_READ,
-                        MAP_POPULATE | MAP_PRIVATE, phandle->download_fd, 0);
+                        MAP_POPULATE | MAP_PRIVATE, data_fd, 0);
+
     hdr = (struct boot_img_hdr *) ptr;
 
     if (ptr == MAP_FAILED) {
@@ -130,6 +143,7 @@
     free(atags_ptr);
     munmap(ptr, sz);
     free(new_atags);
+    close(data_fd);
 
     D(INFO, "Kexec going to reboot");
     reboot(LINUX_REBOOT_CMD_KEXEC);
@@ -256,6 +270,7 @@
     char data[BOOT_MAGIC_SIZE];
     char path[PATH_MAX];
     ssize_t header_sz = 0;
+    int data_fd = 0;
 
     D(DEBUG, "cmd_flash %s\n", arg);
 
@@ -273,9 +288,14 @@
         return;
     }
 
+    if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) {
+        fastboot_fail(phandle, "Access forbiden you need certificate");
+        return;
+    }
+
     // TODO: Maybe its goot idea to check whether the partition is just bootable partition
     if (!strcmp(arg, "boot") || !strcmp(arg, "recovery")) {
-        if (read_data_once(phandle->download_fd, data, BOOT_MAGIC_SIZE) < BOOT_MAGIC_SIZE) {
+        if (read_data_once(data_fd, data, BOOT_MAGIC_SIZE) < BOOT_MAGIC_SIZE) {
             fastboot_fail(phandle, "incoming data read error, cannot read boot header");
             return;
         }
@@ -287,7 +307,10 @@
 
     partition = flash_get_partiton(path);
 
-    sz = get_file_size64(phandle->download_fd);
+    sz = get_file_size64(data_fd);
+
+    sz -= header_sz;
+
     if (sz > get_file_size64(partition)) {
         flash_close(partition);
         D(WARN, "size of file too large");
@@ -304,6 +327,8 @@
     D(INFO, "partition '%s' updated\n", arg);
 
     flash_close(partition);
+    close(data_fd);
+    //TODO: check who is closing phandle->download_fd
 
     fastboot_okay(phandle, "");
 }
diff --git a/fastbootd/commands/flash.c b/fastbootd/commands/flash.c
index 5f8b931..0954217 100644
--- a/fastbootd/commands/flash.c
+++ b/fastbootd/commands/flash.c
@@ -39,6 +39,9 @@
 #include "utils.h"
 #include "commands/partitions.h"
 
+#ifdef FLASH_CERT
+#include "secure.h"
+#endif
 
 #define ALLOWED_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-."
 #define BUFFER_SIZE 1024 * 1024
@@ -112,3 +115,47 @@
 
     return 0;
 }
+
+#ifdef FLASH_CERT
+
+int flash_validate_certificate(int signed_fd, int *data_fd) {
+    int ret = 0;
+    const char *cert_path;
+    X509_STORE *store = NULL;
+    CMS_ContentInfo *content_info;
+    BIO *content;
+
+    cert_path = fastboot_getvar("certificate-path");
+    if (!strcmp(cert_path, "")) {
+        D(ERR, "could not find cert-key value in config file");
+        goto finish;
+    }
+
+    store = cert_store_from_path(cert_path);
+    if (store == NULL) {
+        D(ERR, "unable to create certification store");
+        goto finish;
+    }
+
+    if (cert_read(signed_fd, &content_info, &content)) {
+        D(ERR, "reading data failed");
+        goto finish;
+    }
+
+    ret = cert_verify(content, content_info, store, data_fd);
+    cert_release(content, content_info);
+
+    return ret;
+
+finish:
+    if (store != NULL)
+        cert_release_store(store);
+
+    return ret;
+}
+
+#else
+int flash_validate_certificate(int signed_fd, int *data_fd) {
+    return 1;
+}
+#endif
diff --git a/fastbootd/commands/flash.h b/fastbootd/commands/flash.h
index 8ffd688..86dc811 100644
--- a/fastbootd/commands/flash.h
+++ b/fastbootd/commands/flash.h
@@ -58,5 +58,7 @@
     return readcount;
 }
 
+int flash_validate_certificate(int signed_fd, int *data_fd);
+
 #endif
 
diff --git a/fastbootd/fastbootd.c b/fastbootd/fastbootd.c
index 90b9ef9..9318c99 100644
--- a/fastbootd/fastbootd.c
+++ b/fastbootd/fastbootd.c
@@ -16,32 +16,75 @@
 
 #include <stdio.h>
 #include <unistd.h>
-
 #include <cutils/klog.h>
+#include <getopt.h>
+#include <stdlib.h>
 
 #include "debug.h"
 #include "trigger.h"
+#include "socket_client.h"
+#include "secure.h"
 
 unsigned int debug_level = DEBUG;
 
 void commands_init();
 void usb_init();
 void config_init();
+int transport_socket_init();
+int network_discovery_init();
+void ssh_server_start();
 
 int main(int argc, char **argv)
 {
+    int socket_client = 0;
+    int c;
+
+    klog_init();
+    klog_set_level(6);
+
+    const struct option longopts[] = {
+        {"socket", no_argument, 0, 'S'},
+        {0, 0, 0, 0}
+    };
+
+    while (1) {
+        c = getopt_long(argc, argv, "S", longopts, NULL);
+        /* Alphabetical cases */
+        if (c < 0)
+            break;
+        switch (c) {
+        case 'S':
+            socket_client = 1;
+            break;
+        case '?':
+            return 1;
+        default:
+            return 0;
+        }
+    }
+
     (void)argc;
     (void)argv;
 
     klog_init();
     klog_set_level(6);
 
-    config_init();
-    load_trigger();
-    commands_init();
-    usb_init();
-    while (1) {
-        sleep(1);
+    if (socket_client) {
+        run_socket_client();
+    }
+    else {
+        cert_init_crypto();
+        config_init();
+        load_trigger();
+        commands_init();
+        usb_init();
+        if (!transport_socket_init())
+            exit(1);
+        ssh_server_start();
+        network_discovery_init();
+        while (1) {
+            sleep(1);
+        }
     }
     return 0;
 }
diff --git a/fastbootd/network_discovery.c b/fastbootd/network_discovery.c
new file mode 100644
index 0000000..1cd3e48
--- /dev/null
+++ b/fastbootd/network_discovery.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dns_sd.h>
+#include <cutils/properties.h>
+#include <unistd.h>
+
+#include "debug.h"
+#include "network_discovery.h"
+#include "utils.h"
+
+#define MDNS_SERVICE_NAME "mdnsd"
+#define MDNS_SERVICE_STATUS "init.svc.mdnsd"
+#define FASTBOOTD_TYPE "_fastbootd._tcp"
+#define FASTBOOTD_DOMAIN "local."
+#define FASTBOOTD_NAME "fastbootd"
+
+
+static void reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode,
+    const char *name, const char *regtype, const char *domain, void *context)
+{
+    (void)sdref;    // Unused
+    (void)flags;    // Unused
+    (void)context;  // Unused
+    if (errorCode == kDNSServiceErr_ServiceNotRunning) {
+        fprintf(stderr, "Error code %d\n", errorCode);
+    }
+
+
+    printf("Got a reply for service %s.%s%s: ", name, regtype, domain);
+
+    if (errorCode == kDNSServiceErr_NoError)
+    {
+        if (flags & kDNSServiceFlagsAdd)
+            printf("Name now registered and active\n");
+        else
+            printf("Name registration removed\n");
+        if (errorCode == kDNSServiceErr_NameConflict)
+            printf("Name in use, please choose another\n");
+        else
+            printf("Error %d\n", errorCode);
+
+        if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
+    }
+}
+
+static int register_service() {
+    DNSServiceRef sdref = NULL;
+    const char *domain = FASTBOOTD_DOMAIN;
+    const char *type = FASTBOOTD_TYPE;
+    const char *host = NULL;
+    char name[PROP_VALUE_MAX];
+    uint16_t port = 22;
+    int flags = 0;
+    DNSServiceErrorType result;
+    property_get("ro.serialno", name, "");
+    if (!strcmp(name, "")) {
+        D(ERR, "No property serialno");
+        return -1;
+    }
+
+    result = DNSServiceRegister(&sdref, flags, kDNSServiceInterfaceIndexAny,
+                       name, type, domain, host, port,
+                       0, NULL, reg_reply, NULL);
+    if (result != kDNSServiceErr_NoError) {
+        D(ERR, "Unable to register service");
+        return -1;
+    }
+    return 0;
+}
+
+
+int network_discovery_init()
+{
+    D(INFO, "Starting discovery");
+    if (service_start(MDNS_SERVICE_NAME)) {
+        D(ERR, "Unable to start discovery");
+        return -1;
+    }
+
+    if (register_service()) {
+        D(ERR, "Unable to register service");
+        return -1;
+    }
+
+    return 0;
+}
+
diff --git a/fastbootd/network_discovery.h b/fastbootd/network_discovery.h
new file mode 100644
index 0000000..75fda63
--- /dev/null
+++ b/fastbootd/network_discovery.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _FASTBOOTD_NETWORK_DISCOVERY_H
+#define _FASTBOOTD_NETWORK_DISCOVERY_H
+
+int network_discovery_init();
+
+#endif
diff --git a/fastbootd/other/gptedit.c b/fastbootd/other/gptedit.c
index 020b8ce..16d34a5 100644
--- a/fastbootd/other/gptedit.c
+++ b/fastbootd/other/gptedit.c
@@ -154,9 +154,6 @@
         return 1;
     }
 
-    fprintf(stderr, "entries %d, name %s\n", table->header->entries_count, (char *) table->header->signature);
-
-
     if (add_cmd)
         addGPT(table, new_partition, partition_guid, type_guid);
     if (del_cmd)
diff --git a/fastbootd/other/sign/src/SignImg.java b/fastbootd/other/sign/src/SignImg.java
new file mode 100644
index 0000000..338d427
--- /dev/null
+++ b/fastbootd/other/sign/src/SignImg.java
@@ -0,0 +1,181 @@
+package signtool;
+
+import java.io.*;
+import java.util.Properties;
+import java.util.ArrayList;
+
+import javax.mail.internet.*;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.activation.MailcapCommandMap;
+import javax.activation.CommandMap;
+
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateEncodingException;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSSignedGenerator;
+import org.bouncycastle.cms.CMSSignedDataGenerator;
+import org.bouncycastle.cms.CMSSignedGenerator;
+import org.bouncycastle.cms.CMSProcessable;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.CMSTypedData;
+import org.bouncycastle.cert.jcajce.JcaCertStore;
+import org.bouncycastle.util.Store;
+import org.bouncycastle.asn1.ASN1InputStream;    
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.ASN1Object;
+
+
+public class SignImg {
+
+    /* It reads private key in pkcs#8 formate
+     * Conversion:
+     * openssl pkcs8 -topk8 -nocrypt -outform DER < inkey.pem > outkey.pk8
+     */
+    private static PrivateKey getPrivateKey(String path) throws IOException, FileNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException {
+        File file = new File(path);
+        FileInputStream fis = new FileInputStream(file);
+        byte[] data = new byte[(int)file.length()];
+        fis.read(data);
+        fis.close();
+
+        PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(data);
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        PrivateKey privateKey = kf.generatePrivate(kspec);
+
+        return privateKey;
+    }
+
+    private static MimeBodyPart getContent(String path) throws IOException, FileNotFoundException, MessagingException {
+        MimeBodyPart body = new MimeBodyPart();
+
+        File file = new File(path);
+        FileInputStream fis = new FileInputStream(file);
+        byte[] data = new byte[(int)file.length()];
+        fis.read(data);
+        fis.close();
+
+        body.setContent(data, "application/octet-stream");
+
+        return body;
+    }
+
+    private static CMSProcessableByteArray getCMSContent(String path) throws IOException, FileNotFoundException, MessagingException {
+        File file = new File(path);
+        FileInputStream fis = new FileInputStream(file);
+        byte[] data = new byte[(int)file.length()];
+        fis.read(data);
+        fis.close();
+        CMSProcessableByteArray cms = new CMSProcessableByteArray(data);
+
+        return cms;
+    }
+
+    private static X509Certificate readCert(String path) throws IOException, FileNotFoundException, CertificateException {
+        File file = new File(path);
+        FileInputStream is = new FileInputStream(file);
+
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        Certificate cert = cf.generateCertificate(is);
+        is.close();
+
+        return (X509Certificate) cert;
+    }
+
+    private static void save(MimeBodyPart content, String path) throws IOException, FileNotFoundException, MessagingException {
+        File file = new File(path);
+        FileOutputStream os = new FileOutputStream(file);
+
+        content.writeTo(os);
+
+        os.close();
+    }
+
+    private static Store certToStore(X509Certificate certificate) throws CertificateEncodingException {
+        ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
+        certList.add(certificate);
+        return new JcaCertStore(certList);
+    }
+
+    public static void setDefaultMailcap()
+    {
+        MailcapCommandMap _mailcap =
+            (MailcapCommandMap)CommandMap.getDefaultCommandMap();
+
+        _mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
+        _mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
+        _mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
+        _mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
+        _mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
+
+        CommandMap.setDefaultCommandMap(_mailcap);
+    } 
+
+    public static void main(String[] args) {
+        try {
+            if (args.length < 4) {
+                System.out.println("Usage: signimg data private_key certificate output");
+                return;
+            }
+            System.out.println("Signing the image");
+            setDefaultMailcap();
+
+            Security.addProvider(new BouncyCastleProvider());
+
+            PrivateKey key = getPrivateKey(args[1]);
+            System.out.println("File read sucessfully");
+
+            CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
+
+            CMSTypedData body = getCMSContent(args[0]);
+            System.out.println("Content read sucessfully");
+
+            X509Certificate cert = (X509Certificate) readCert(args[2]);
+            System.out.println("Certificate read sucessfully");
+
+            ContentSigner sha256Signer = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(key);
+
+            Store certs = certToStore(cert);
+
+            generator.addCertificates(certs);
+            generator.addSignerInfoGenerator(
+                          new JcaSignerInfoGeneratorBuilder(
+                                new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
+                          .build(sha256Signer, cert));
+
+            CMSSignedData signed = generator.generate(body, true);
+            System.out.println("Signed");
+
+            Properties props = System.getProperties();
+            Session session = Session.getDefaultInstance(props, null);
+            
+            File file = new File(args[3]);
+            FileOutputStream os = new FileOutputStream(file);
+
+            ASN1InputStream asn1 = new ASN1InputStream(signed.getEncoded());
+            ByteArrayOutputStream out = new ByteArrayOutputStream(); 
+            DEROutputStream dOut = new DEROutputStream(os); 
+            dOut.writeObject(ASN1Object.fromByteArray(signed.getEncoded()));
+
+        }
+        catch (Exception ex) {
+            System.out.println("Exception during programm execution: " + ex.getMessage());
+        }
+    }
+}
diff --git a/fastbootd/secure.c b/fastbootd/secure.c
new file mode 100644
index 0000000..75a6f3c
--- /dev/null
+++ b/fastbootd/secure.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <openssl/pem.h>
+#include <openssl/engine.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+#include <openssl/cms.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "secure.h"
+#include "debug.h"
+#include "utils.h"
+
+
+void cert_init_crypto() {
+    CRYPTO_malloc_init();
+    ERR_load_crypto_strings();
+    OpenSSL_add_all_algorithms();
+    ENGINE_load_builtin_engines();
+}
+
+X509_STORE *cert_store_from_path(const char *path) {
+
+    X509_STORE *store;
+    struct stat st;
+    X509_LOOKUP *lookup;
+
+    if (stat(path, &st)) {
+        D(ERR, "Unable to stat cert path");
+        goto error;
+    }
+
+    if (!(store = X509_STORE_new())) {
+        goto error;
+    }
+
+    if (S_ISDIR(st.st_mode)) {
+        lookup = X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
+        if (lookup == NULL)
+            goto error;
+        if (!X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM)) {
+            D(ERR, "Error loading cert directory %s", path);
+            goto error;
+        }
+    }
+    else if(S_ISREG(st.st_mode)) {
+        lookup = X509_STORE_add_lookup(store,X509_LOOKUP_file());
+        if (lookup == NULL)
+            goto error;
+        if (!X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM)) {
+            D(ERR, "Error loading cert directory %s", path);
+            goto error;
+        }
+    }
+    else {
+        D(ERR, "cert path is not directory or regular file");
+        goto error;
+    }
+
+    return store;
+
+error:
+    return NULL;
+}
+
+
+int cert_read(int fd, CMS_ContentInfo **content, BIO **output) {
+    BIO *input;
+    *output = NULL;
+
+
+    input = BIO_new_fd(fd, BIO_NOCLOSE);
+    if (input == NULL) {
+        D(ERR, "Unable to open input");
+        goto error;
+    }
+
+    *content = SMIME_read_CMS(input, output);
+    if (*content == NULL) {
+        unsigned long err = ERR_peek_last_error();
+        D(ERR, "Unable to parse input file: %s", ERR_lib_error_string(err));
+        goto error_read;
+    }
+
+    BIO_free(input);
+
+    return 0;
+
+error_read:
+    BIO_free(input);
+error:
+    return 1;
+}
+
+int cert_verify(BIO *content, CMS_ContentInfo *content_info, X509_STORE *store, int *out_fd) {
+    BIO *output_temp;
+    int ret;
+
+    *out_fd = create_temp_file();
+    if (*out_fd < 0) {
+        D(ERR, "unable to create temporary file");
+        return -1;
+    }
+
+    output_temp = BIO_new_fd(*out_fd, BIO_NOCLOSE);
+    if (output_temp == NULL) {
+        D(ERR, "unable to create temporary bio");
+        close(*out_fd);
+        return -1;
+    }
+
+    ret = CMS_verify(content_info, NULL ,store, content, output_temp, 0);
+
+    if (ret == 0) {
+        char buf[256];
+        unsigned long err = ERR_peek_last_error();
+        D(ERR, "Verification failed with reason: %s, %s", ERR_lib_error_string(err),  ERR_error_string(err, buf));
+        D(ERR, "Data used: content %d", (int) content);
+    }
+
+    ERR_clear_error();
+    ERR_remove_state(0);
+
+    BIO_free(output_temp);
+
+    return ret;
+}
+
+void cert_release(BIO *content, CMS_ContentInfo *info) {
+    BIO_free(content);
+    CMS_ContentInfo_free(info);
+}
+
diff --git a/fastbootd/secure.h b/fastbootd/secure.h
new file mode 100644
index 0000000..878a643
--- /dev/null
+++ b/fastbootd/secure.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _FASTBOOTD_SECURE_H
+#define _FASTBOOTD_SECURE_H
+
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+#include <openssl/cms.h>
+
+void cert_init_crypto();
+
+X509_STORE *cert_store_from_path(const char*stream);
+
+static inline void cert_release_store(X509_STORE *store) {
+    X509_STORE_free(store);
+}
+
+int cert_read(int fd, CMS_ContentInfo **content, BIO **output);
+int cert_verify(BIO *content, CMS_ContentInfo *content_info, X509_STORE *store, int *out_fd);
+void cert_release(BIO *content, CMS_ContentInfo *info);
+
+#endif
diff --git a/fastbootd/socket_client.c b/fastbootd/socket_client.c
new file mode 100644
index 0000000..da636db
--- /dev/null
+++ b/fastbootd/socket_client.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <cutils/sockets.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+#define BUFFER_SIZE 256
+
+#define STDIN_FD 0
+#define STDOUT_FD 1
+#define STDERR_FD 2
+
+void run_socket_client() {
+    int fd;
+    char buffer[BUFFER_SIZE];
+    int n;
+    struct pollfd fds[2];
+
+    fd = socket_local_client("fastbootd",
+                         ANDROID_SOCKET_NAMESPACE_RESERVED,
+                         SOCK_STREAM);
+
+    if (fd < 0) {
+        fprintf(stderr, "ERROR: Unable to open fastbootd socket\n");
+        return;
+    }
+
+    fds[0].fd = STDIN_FD;
+    fds[0].events = POLLIN;
+    fds[1].fd = fd;
+    fds[1].events = POLLIN;
+
+    while(true) {
+        if (poll(fds, 2, -1) <= 0) {
+            fprintf(stderr, "ERROR: socket error");
+            return;
+        }
+
+        if (fds[0].revents & POLLIN) {
+            if ((n = read(STDIN_FD, buffer, BUFFER_SIZE)) < 0) {
+                goto error;
+            }
+
+            if (bulk_write(fd, buffer, n) < 0) {
+                goto error;
+            }
+        }
+
+        if (fds[1].revents & POLLIN) {
+            if ((n = read(fd, buffer, BUFFER_SIZE)) < 0) {
+                goto error;
+            }
+
+            if (bulk_write(STDOUT_FD, buffer, n) < 0) {
+                goto error;
+            }
+        }
+    }
+
+error:
+    fprintf(stderr, "Transport error\n");
+}
diff --git a/fastbootd/socket_client.h b/fastbootd/socket_client.h
new file mode 100644
index 0000000..4481ff2
--- /dev/null
+++ b/fastbootd/socket_client.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _FASTBOOTD_SOCKET_CLIENT_H
+#define _FASTBOOTD_SOCKET_CLIENT_H
+
+void run_socket_client();
+
+#endif
diff --git a/fastbootd/transport.c b/fastbootd/transport.c
index 01a5a8a..19a705c 100644
--- a/fastbootd/transport.c
+++ b/fastbootd/transport.c
@@ -99,6 +99,7 @@
         }
         if (ret > 0) {
             buffer[ret] = 0;
+            //TODO: multiple threads
             protocol_handle_command(phandle, buffer);
         }
     }
diff --git a/fastbootd/transport_socket.c b/fastbootd/transport_socket.c
new file mode 100644
index 0000000..801b8d6
--- /dev/null
+++ b/fastbootd/transport_socket.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <cutils/sockets.h>
+
+#include "debug.h"
+#include "transport.h"
+#include "utils.h"
+
+
+#define container_of(ptr, type, member) \
+    ((type*)((char*)(ptr) - offsetof(type, member)))
+
+#define SOCKET_WORKING 0
+#define SOCKET_STOPPED -1
+
+
+struct socket_transport {
+    struct transport transport;
+
+    int fd;
+};
+
+struct socket_handle {
+    struct transport_handle handle;
+
+    int fd;
+};
+
+void socket_close(struct transport_handle *thandle)
+{
+    struct socket_handle * handle = container_of(thandle, struct socket_handle, handle);
+    close(handle->fd);
+}
+
+struct transport_handle *socket_connect(struct transport *transport)
+{
+    struct socket_handle *handle = calloc(sizeof(struct socket_handle), 1);
+    struct socket_transport *socket_transport = container_of(transport, struct socket_transport, transport);
+    struct sockaddr addr;
+    socklen_t alen = sizeof(addr);
+
+    handle->fd = accept(socket_transport->fd, &addr, &alen);
+
+    if (handle->fd < 0) {
+        D(WARN, "socket connect error");
+        return NULL;
+    }
+
+    D(DEBUG, "[ socket_thread - registering device ]");
+    return &handle->handle;
+}
+
+ssize_t socket_write(struct transport_handle *thandle, const void *data, size_t len)
+{
+    ssize_t ret;
+    struct socket_handle *handle = container_of(thandle, struct socket_handle, handle);
+
+    D(DEBUG, "about to write (fd=%d, len=%d)", handle->fd, len);
+    ret = bulk_write(handle->fd, data, len);
+    if (ret < 0) {
+        D(ERR, "ERROR: fd = %d, ret = %zd", handle->fd, ret);
+        return -1;
+    }
+    D(DEBUG, "[ socket_write done fd=%d ]", handle->fd);
+    return ret;
+}
+
+ssize_t socket_read(struct transport_handle *thandle, void *data, size_t len)
+{
+    ssize_t ret;
+    struct socket_handle *handle = container_of(thandle, struct socket_handle, handle);
+
+    D(DEBUG, "about to read (fd=%d, len=%d)", handle->fd, len);
+    ret = bulk_read(handle->fd, data, len);
+    if (ret < 0) {
+        D(ERR, "ERROR: fd = %d, ret = %zd", handle->fd, ret);
+        return -1;
+    }
+    D(DEBUG, "[ socket_read done fd=%d ret=%zd]", handle->fd, ret);
+    return ret;
+}
+
+static int listen_socket_init(struct socket_transport *socket_transport)
+{
+    int s = android_get_control_socket("fastbootd");
+
+    if (s < 0) {
+        D(WARN, "android_get_control_socket(fastbootd): %s\n", strerror(errno));
+        return 0;
+    }
+
+    if (listen(s, 4) < 0) {
+        D(WARN, "listen(control socket): %s\n", strerror(errno));
+        return 0;
+    }
+
+    socket_transport->fd = s;
+
+    return 1;
+}
+
+
+int transport_socket_init()
+{
+    struct socket_transport *socket_transport = malloc(sizeof(struct socket_transport));
+    
+    socket_transport->transport.connect = socket_connect;
+    socket_transport->transport.close = socket_close;
+    socket_transport->transport.read = socket_read;
+    socket_transport->transport.write = socket_write;
+    // TODO: create sshd key pair if necessary
+    
+    if (!listen_socket_init(socket_transport)) {
+        D(ERR, "socket transport init failed");
+        free(socket_transport);
+        return 0;
+    }
+
+    transport_register(&socket_transport->transport);
+    return 1;
+}
+
diff --git a/fastbootd/usb_linux_client.c b/fastbootd/usb_linux_client.c
index 111cf35..7a8e46f 100644
--- a/fastbootd/usb_linux_client.c
+++ b/fastbootd/usb_linux_client.c
@@ -30,6 +30,7 @@
 
 #include "debug.h"
 #include "transport.h"
+#include "utils.h"
 
 #define   TRACE_TAG  TRACE_USB
 
@@ -50,8 +51,6 @@
 #define USB_FFS_FASTBOOT_OUT   USB_FFS_FASTBOOT_EP(ep1)
 #define USB_FFS_FASTBOOT_IN    USB_FFS_FASTBOOT_EP(ep2)
 
-#define READ_BUF_SIZE (16*1024)
-
 #define container_of(ptr, type, member) \
     ((type*)((char*)(ptr) - offsetof(type, member)))
 
@@ -212,26 +211,6 @@
     return -1;
 }
 
-static ssize_t bulk_write(int bulk_in, const char *buf, size_t length)
-{
-    size_t count = 0;
-    ssize_t ret;
-
-    do {
-        ret = TEMP_FAILURE_RETRY(write(bulk_in, buf + count, length - count));
-        if (ret < 0) {
-            D(WARN, "[ bulk_read failed fd=%d length=%d errno=%d %s ]",
-                    bulk_in, length, errno, strerror(errno));
-            return -1;
-        } else {
-            count += ret;
-        }
-    } while (count < length);
-
-    D(VERBOSE, "[ bulk_write done fd=%d ]", bulk_in);
-    return count;
-}
-
 static ssize_t usb_write(struct transport_handle *thandle, const void *data, size_t len)
 {
     ssize_t ret;
@@ -248,30 +227,6 @@
     return ret;
 }
 
-static ssize_t bulk_read(int bulk_out, char *buf, size_t length)
-{
-    ssize_t ret;
-    size_t n = 0;
-
-    while (n < length) {
-        size_t to_read = (length - n > READ_BUF_SIZE) ? READ_BUF_SIZE : length - n;
-        ret = TEMP_FAILURE_RETRY(read(bulk_out, buf + n, to_read));
-        if (ret < 0) {
-            D(WARN, "[ bulk_read failed fd=%d length=%d errno=%d %s ]",
-                    bulk_out, length, errno, strerror(errno));
-            return ret;
-        }
-        n += ret;
-        if (ret < (ssize_t)to_read) {
-            D(VERBOSE, "bulk_read short read, ret=%zd to_read=%u n=%u length=%u",
-                    ret, to_read, n, length);
-            break;
-        }
-    }
-
-    return n;
-}
-
 ssize_t usb_read(struct transport_handle *thandle, void *data, size_t len)
 {
     ssize_t ret;
diff --git a/fastbootd/utils.c b/fastbootd/utils.c
index 16e1c09..fe3f0f8 100644
--- a/fastbootd/utils.c
+++ b/fastbootd/utils.c
@@ -34,6 +34,8 @@
 #include <stdio.h>
 #include <sys/ioctl.h>
 #include <linux/fs.h>
+#include <stdlib.h>
+#include <cutils/properties.h>
 
 #include "utils.h"
 #include "debug.h"
@@ -46,6 +48,7 @@
 #define BLKSECDISCARD _IO(0x12,125)
 #endif
 
+#define READ_BUF_SIZE (16*1024)
 
 int get_stream_size(FILE *stream) {
     int size;
@@ -145,3 +148,113 @@
     return 0;
 }
 
+int create_temp_file() {
+    char tempname[] = "/dev/fastboot_data_XXXXXX";
+    int fd;
+
+    fd = mkstemp(tempname);
+    if (fd < 0)
+        return -1;
+
+    unlink(tempname);
+
+    return fd;
+}
+
+ssize_t bulk_write(int bulk_in, const char *buf, size_t length)
+{
+    size_t count = 0;
+    ssize_t ret;
+
+    do {
+        ret = TEMP_FAILURE_RETRY(write(bulk_in, buf + count, length - count));
+        if (ret < 0) {
+            D(WARN, "[ bulk_write failed fd=%d length=%d errno=%d %s ]",
+                    bulk_in, length, errno, strerror(errno));
+            return -1;
+        } else {
+            count += ret;
+        }
+    } while (count < length);
+
+    D(VERBOSE, "[ bulk_write done fd=%d ]", bulk_in);
+    return count;
+}
+
+ssize_t bulk_read(int bulk_out, char *buf, size_t length)
+{
+    ssize_t ret;
+    size_t n = 0;
+
+    while (n < length) {
+        size_t to_read = (length - n > READ_BUF_SIZE) ? READ_BUF_SIZE : length - n;
+        ret = TEMP_FAILURE_RETRY(read(bulk_out, buf + n, to_read));
+        if (ret < 0) {
+            D(WARN, "[ bulk_read failed fd=%d length=%d errno=%d %s ]",
+                    bulk_out, length, errno, strerror(errno));
+            return ret;
+        }
+        n += ret;
+        if (ret < (ssize_t)to_read) {
+            D(VERBOSE, "bulk_read short read, ret=%zd to_read=%u n=%u length=%u",
+                    ret, to_read, n, length);
+            break;
+        }
+    }
+
+    return n;
+}
+
+#define NAP_TIME 200  // 200 ms between polls
+static int wait_for_property(const char *name, const char *desired_value, int maxwait)
+{
+    char value[PROPERTY_VALUE_MAX] = {'\0'};
+    int maxnaps = (maxwait * 1000) / NAP_TIME;
+
+    if (maxnaps < 1) {
+        maxnaps = 1;
+    }
+
+    while (maxnaps-- > 0) {
+        usleep(NAP_TIME * 1000);
+        if (property_get(name, value, NULL)) {
+            if (desired_value == NULL || strcmp(value, desired_value) == 0) {
+                return 0;
+            }
+        }
+    }
+    return -1; /* failure */
+}
+
+int service_start(const char *service_name)
+{
+    int result = 0;
+    char property_value[PROPERTY_VALUE_MAX];
+
+    property_get(service_name, property_value, "");
+    if (strcmp("running", property_value) != 0) {
+        D(INFO, "Starting %s", service_name);
+        property_set("ctl.start", service_name);
+        if (wait_for_property(service_name, "running", 5))
+            result = -1;
+    }
+
+    return result;
+}
+
+int service_stop(const char *service_name)
+{
+    int result = 0;
+
+    D(INFO, "Stopping MDNSD");
+    property_set("ctl.stop", service_name);
+    if (wait_for_property(service_name, "stopped", 5))
+        result = -1;
+
+    return result;
+}
+
+int ssh_server_start()
+{
+    return service_start("sshd");
+}
diff --git a/fastbootd/utils.h b/fastbootd/utils.h
index a553a25..3d98699 100644
--- a/fastbootd/utils.h
+++ b/fastbootd/utils.h
@@ -42,6 +42,12 @@
 uint64_t get_file_size(int fd);
 uint64_t get_block_device_size(int fd);
 int wipe_block_device(int fd, int64_t len);
+int create_temp_file();
+ssize_t bulk_read(int bulk_out, char *buf, size_t length);
+ssize_t bulk_write(int bulk_in, const char *buf, size_t length);
+int service_start(const char *service_name);
+int service_stop(const char *service_name);
+int ssh_server_start();
 
 #define ROUND_TO_PAGE(address,pagesize) ((address + pagesize - 1) & (~(pagesize - 1)))