transport.c revision 2a656c332b792c84fa6e96d8b40e2c8c0fe94ef9
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <pthread.h>
18#include <stddef.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <sys/mman.h>
23
24#include "debug.h"
25#include "protocol.h"
26#include "transport.h"
27
28#define COMMAND_BUF_SIZE 64
29
30ssize_t transport_handle_write(struct transport_handle *thandle, char *buffer, size_t len)
31{
32    return thandle->transport->write(thandle, buffer, len);
33}
34
35void transport_handle_close(struct transport_handle *thandle)
36{
37    thandle->transport->close(thandle);
38}
39
40int transport_handle_download(struct transport_handle *thandle, size_t len)
41{
42    ssize_t ret;
43    size_t n = 0;
44    int fd;
45    // TODO: move out of /dev
46    char tempname[] = "/dev/fastboot_download_XXXXXX";
47    char *buffer;
48
49    fd = mkstemp(tempname);
50    if (fd < 0)
51        return -1;
52
53    unlink(tempname);
54
55    ftruncate(fd, len);
56
57    buffer = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
58    if (buffer == NULL) {
59        D(ERR, "mmap(%u) failed: %d %s", len, errno, strerror(errno));
60        goto err;
61    }
62
63    while (n < len) {
64        ret = thandle->transport->read(thandle, buffer + n, len - n);
65        if (ret <= 0) {
66            D(WARN, "transport read failed, ret=%d %s", ret, strerror(-ret));
67            break;
68        }
69        n += ret;
70    }
71
72    munmap(buffer, len);
73
74    if (n != len)
75        goto err;
76
77    return fd;
78
79err:
80    close(fd);
81    transport_handle_close(thandle);
82    return -1;
83}
84
85static void *transport_data_thread(void *arg)
86{
87    struct transport_handle *thandle = arg;
88    struct protocol_handle *phandle = create_protocol_handle(thandle);
89
90    while (!thandle->stopped) {
91        int ret;
92        char buffer[COMMAND_BUF_SIZE + 1];
93        D(VERBOSE, "transport_data_thread\n");
94
95        ret = thandle->transport->read(thandle, buffer, COMMAND_BUF_SIZE);
96        if (ret <= 0) {
97            D(DEBUG, "ret = %d\n", ret);
98            break;
99        }
100        if (ret > 0) {
101            buffer[ret] = 0;
102            //TODO: multiple threads
103            protocol_handle_command(phandle, buffer);
104        }
105    }
106
107    transport_handle_close(thandle);
108    free(thandle);
109
110    return NULL;
111}
112
113static void *transport_connect_thread(void *arg)
114{
115    struct transport *transport = arg;
116    while (!transport->stopped) {
117        struct transport_handle *thandle;
118        pthread_t thread;
119        pthread_attr_t attr;
120
121        D(VERBOSE, "transport_connect_thread\n");
122        thandle = transport->connect(transport);
123        if (thandle == NULL) {
124            D(ERR, "transport connect failed\n");
125            sleep(1);
126            continue;
127        }
128        thandle->transport = transport;
129
130        pthread_attr_init(&attr);
131        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
132
133        pthread_create(&thread, &attr, transport_data_thread, thandle);
134
135        sleep(1);
136    }
137
138    return NULL;
139}
140
141void transport_register(struct transport *transport)
142{
143    pthread_t thread;
144    pthread_attr_t attr;
145
146    pthread_attr_init(&attr);
147    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
148
149    pthread_create(&thread, &attr, transport_connect_thread, transport);
150}
151