Fastbootd: socket and network transport

Change-Id: I395e5361d0484bd11421225c152f9aec00305f11
This commit is contained in:
Szymon Starzycki 2013-09-05 14:26:28 -07:00 committed by Colin Cross
parent 00f4e93730
commit 2a656c332b
9 changed files with 396 additions and 53 deletions

View file

@ -30,7 +30,9 @@ LOCAL_SRC_FILES := \
commands/virtual_partitions.c \
fastbootd.c \
protocol.c \
socket_client.c \
transport.c \
transport_socket.c \
trigger.c \
usb_linux_client.c \
utils.c

View file

@ -16,32 +16,69 @@
#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"
unsigned int debug_level = DEBUG;
void commands_init();
void usb_init();
void config_init();
int transport_socket_init();
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 {
config_init();
load_trigger();
commands_init();
usb_init();
if (!transport_socket_init())
exit(1);
while (1) {
sleep(1);
}
}
return 0;
}

94
fastbootd/socket_client.c Normal file
View file

@ -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");
}

37
fastbootd/socket_client.h Normal file
View file

@ -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

View file

@ -99,6 +99,7 @@ static void *transport_data_thread(void *arg)
}
if (ret > 0) {
buffer[ret] = 0;
//TODO: multiple threads
protocol_handle_command(phandle, buffer);
}
}

View file

@ -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;
}

View file

@ -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 @@ err:
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 @@ static ssize_t usb_write(struct transport_handle *thandle, const void *data, siz
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;

View file

@ -34,6 +34,7 @@
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <stdlib.h>
#include "utils.h"
#include "debug.h"
@ -46,6 +47,7 @@
#define BLKSECDISCARD _IO(0x12,125)
#endif
#define READ_BUF_SIZE (16*1024)
int get_stream_size(FILE *stream) {
int size;
@ -145,3 +147,60 @@ int wipe_block_device(int fd, int64_t len)
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;
}

View file

@ -42,6 +42,9 @@ uint64_t get_file_size64(int fd);
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);
#define ROUND_TO_PAGE(address,pagesize) ((address + pagesize - 1) & (~(pagesize - 1)))