blob: 68831d44eab0bac5f12526e531ab714d89baa68d [file] [log] [blame]
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -08001/* Copyright (C) 2010 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10** GNU General Public License for more details.
11*/
12
13#include <unistd.h>
14
David 'Digit' Turnercc330d42013-12-14 23:26:42 +010015#include "android/sockets.h"
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -080016#include "qemu-common.h"
17#include "errno.h"
David 'Digit' Turnerd413fa52013-12-14 23:35:20 +010018#include "android/iolooper.h"
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -080019#include "android/android.h"
20#include "android/utils/debug.h"
21#include "android/globals.h"
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -080022#include "android/utils/system.h"
David 'Digit' Turnere9931262011-02-02 14:05:23 +010023#include "android/protocol/core-connection.h"
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -080024
25/* Descriptor for a client, connected to the core via console port. */
26struct CoreConnection {
27 /* Socket address of the console. */
28 SockAddress console_address;
29
30 // Helper for performing sync I/O on the console socket.
31 SyncSocket* ssocket;
32
33 /* Stream name. Can be:
34 * - NULL for the console itself.
Vladimir Chtchetkinea473d812011-01-26 08:53:05 -080035 * - "attach-UI" for the attached UI client.
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -080036 */
37 char* stream_name;
38};
39
40/*
41 * Zero-terminates string buffer.
42 * Param:
43 * buf - Buffer containing the string.
44 * buf_size - Buffer size.
45 * eos - String size.
46 */
47static inline void
48_zero_terminate(char* buf, size_t buf_size, size_t eos)
49{
50 if (eos < buf_size) {
51 buf[eos] = '\0';
52 } else {
53 buf[buf_size - 1] = '\0';
54 }
55}
56
57/*
58 * Checks if console has replied with "OK"
59 * Param:
60 * reply - String containing console's reply
61 * Return:
62 * boolean: true if reply was "OK", or false otherwise.
63 */
64static int
65_is_reply_ok(const char* reply, int reply_size)
66{
67 return (reply_size < 2) ? 0 : (reply[0] == 'O' && reply[1] == 'K');
68}
69
70/*
71 * Checks if console has replied with "KO"
72 * Param:
73 * reply - String containing console's reply
74 * Return:
75 * boolean: true if reply was "KO", or false otherwise.
76 */
77static int
78_is_reply_ko(const char* reply, int reply_size)
79{
80 return (reply_size < 2) ? 0 : (reply[0] == 'K' && reply[1] == 'O');
81}
82
83SyncSocket*
84core_connection_open_socket(SockAddress* sockaddr)
85{
86 SyncSocket* ssocket;
87 int status;
88 int64_t deadline;
89 char buf[512];
90
91 int fd = socket_create(sock_address_get_family(sockaddr), SOCKET_STREAM);
92 if (fd < 0) {
93 return NULL;
94 }
95
96 socket_set_xreuseaddr(fd);
97
98 // Create sync connection to the console.
99 ssocket = syncsocket_connect(fd, sockaddr, CORE_PORT_TIMEOUT_MS);
100 if (ssocket == NULL) {
101 derror("syncsocket_connect has failed: %s\n", errno_str);
102 socket_close(fd);
103 return NULL;
104 }
105
106 // Upon successful connection the console will reply with two strings:
107 // "Android Console....", and "OK\r\n". Read them and check.
108 status = syncsocket_start_read(ssocket);
109 if (status < 0) {
110 derror("syncsocket_start_read has failed: %s\n", errno_str);
111 syncsocket_free(ssocket);
112 return NULL;
113 }
114
115 deadline = iolooper_now() + CORE_PORT_TIMEOUT_MS;
116 // Read first line.
117 status = syncsocket_read_line_absolute(ssocket, buf, sizeof(buf), deadline);
118 if (status <= 0) {
119 derror("syncsocket_read_line_absolute has failed: %s\n", errno_str);
120 syncsocket_free(ssocket);
121 return NULL;
122 }
123 if (status < 15 || memcmp(buf, "Android Console", 15)) {
124 _zero_terminate(buf, sizeof(buf), status);
125 derror("console has failed the connection: %s\n", buf);
126 syncsocket_free(ssocket);
127 return NULL;
128 }
129 // Read second line
130 status = syncsocket_read_line_absolute(ssocket, buf, sizeof(buf), deadline);
131 syncsocket_stop_read(ssocket);
132 if (status < 2 || !_is_reply_ok(buf, status)) {
133 _zero_terminate(buf, sizeof(buf), status);
134 derror("unexpected reply from the console: %s\n", buf);
135 syncsocket_free(ssocket);
136 return NULL;
137 }
138
139 return ssocket;
140}
141
142CoreConnection*
143core_connection_create(SockAddress* console_address)
144{
145 CoreConnection* desc;
146 ANEW0(desc);
147 desc->console_address = console_address[0];
148 desc->ssocket = NULL;
149 desc->stream_name = NULL;
150
151 return desc;
152}
153
154void
155core_connection_free(CoreConnection* desc)
156{
157 if (desc == NULL) {
158 return;
159 }
160 if (desc->ssocket != NULL) {
161 syncsocket_free(desc->ssocket);
162 }
163 if (desc->stream_name != NULL) {
164 free(desc->stream_name);
165 }
166 free(desc);
167}
168
169int
170core_connection_open(CoreConnection* desc)
171{
172 if (desc == NULL) {
173 errno = EINVAL;
174 return -1;
175 }
176 if (desc->ssocket != NULL) {
177 return 0;
178 }
179
180 desc->ssocket = core_connection_open_socket(&desc->console_address);
181
182 return (desc->ssocket != NULL) ? 0 : -1;
183}
184
185void
186core_connection_close(CoreConnection* desc)
187{
188 if (desc == NULL) {
189 return;
190 }
191 if (desc->ssocket != NULL) {
192 syncsocket_close(desc->ssocket);
193 }
194}
195
196int
197core_connection_write(CoreConnection* desc,
198 const void* buffer,
199 size_t to_write,
200 size_t* written_bytes)
201{
202 ssize_t written;
203
204 int status = syncsocket_start_write(desc->ssocket);
205 if (status < 0) {
206 derror("syncsocket_start_write failed: %s\n", errno_str);
207 return status;
208 }
209
210 written =
211 syncsocket_write(desc->ssocket, buffer, to_write, CORE_PORT_TIMEOUT_MS);
212 syncsocket_stop_write(desc->ssocket);
213 if (written <= 0) {
214 derror("syncsocket_write failed: %s\n", errno_str);
215 return -1;
216 }
217 if (written_bytes != NULL) {
218 *written_bytes = written;
219 }
220
221 return 0;
222}
223
224int
225core_connection_read(CoreConnection* desc,
226 void* buffer,
227 size_t to_read,
228 size_t* read_bytes)
229{
230 ssize_t read_size;
231
232 int status = syncsocket_start_read(desc->ssocket);
233 if (status < 0) {
234 derror("syncsocket_start_read failed: %s\n", errno_str);
235 return status;
236 }
237
238 read_size =
239 syncsocket_read(desc->ssocket, buffer, to_read, CORE_PORT_TIMEOUT_MS);
240 syncsocket_stop_read(desc->ssocket);
241 if (read_size <= 0) {
242 derror("syncsocket_read failed: %s\n", errno_str);
243 return -1;
244 }
245
246 if (read_bytes != NULL) {
247 *read_bytes = read_size;
248 }
249 return 0;
250}
251
252int
253core_connection_switch_stream(CoreConnection* desc,
254 const char* stream_name,
255 char** handshake)
256{
257 char buf[4096];
258 int handshake_len;
259 int status;
260 int64_t deadline;
261
262 *handshake = NULL;
263 if (desc == NULL || desc->stream_name != NULL || stream_name == NULL) {
264 errno = EINVAL;
265 return -1;
266 }
267
268 // Prepare and write "switch" command.
269 snprintf(buf, sizeof(buf), "qemu %s\r\n", stream_name);
270 if (core_connection_write(desc, buf, strlen(buf), NULL)) {
271 return -1;
272 }
273
274 // Read result / handshake
275 status = syncsocket_start_read(desc->ssocket);
276 if (status < 0) {
277 return -1;
278 }
279 deadline = iolooper_now() + CORE_PORT_TIMEOUT_MS;
280 handshake_len =
281 syncsocket_read_line_absolute(desc->ssocket, buf, sizeof(buf), deadline);
282 _zero_terminate(buf, sizeof(buf), handshake_len);
283 // Replace terminating "\r\n" with 0
Vladimir Chtchetkine777eb682011-01-26 11:19:19 -0800284 if (handshake_len >= 1) {
285 if (buf[handshake_len - 1] == '\r' || buf[handshake_len - 1] == '\n') {
286 buf[handshake_len - 1] = '\0';
287 if (handshake_len >= 2 && (buf[handshake_len - 2] == '\r' ||
288 buf[handshake_len - 2] == '\n')) {
289 buf[handshake_len - 2] = '\0';
290 }
291 }
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800292 }
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800293 // Lets see what kind of response we've got here.
294 if (_is_reply_ok(buf, handshake_len)) {
295 *handshake = strdup(buf + 3);
296 desc->stream_name = strdup(stream_name);
297 // We expect an "OK" string here
298 status = syncsocket_read_line_absolute(desc->ssocket, buf, sizeof(buf),
299 deadline);
300 syncsocket_stop_read(desc->ssocket);
301 if (status < 0) {
302 derror("error reading console reply on stream switch: %s\n", errno_str);
303 return -1;
304 } else if (!_is_reply_ok(buf, status)) {
305 _zero_terminate(buf, sizeof(buf), status);
306 derror("unexpected console reply when switching streams: %s\n", buf);
307 return -1;
308 }
309 return 0;
310 } else if (_is_reply_ko(buf, handshake_len)) {
311 derror("console has rejected stream switch: %s\n", buf);
312 syncsocket_stop_read(desc->ssocket);
313 *handshake = strdup(buf + 3);
314 return -1;
315 } else {
316 // No OK, no KO? Should be an error!
317 derror("unexpected console reply when switching streams: %s\n", buf);
318 syncsocket_stop_read(desc->ssocket);
319 *handshake = strdup(buf);
320 return -1;
321 }
322}
323
Vladimir Chtchetkine777eb682011-01-26 11:19:19 -0800324CoreConnection*
325core_connection_create_and_switch(SockAddress* console_socket,
326 const char* stream_name,
327 char** handshake)
328{
329 char switch_cmd[256];
330 CoreConnection* connection = NULL;
331
332 // Connect to the console service.
333 connection = core_connection_create(console_socket);
334 if (connection == NULL) {
335 return NULL;
336 }
337 if (core_connection_open(connection)) {
338 core_connection_free(connection);
339 return NULL;
340 }
341
342 // Perform the switch.
343 snprintf(switch_cmd, sizeof(switch_cmd), "%s", stream_name);
344 if (core_connection_switch_stream(connection, switch_cmd, handshake)) {
345 core_connection_close(connection);
346 core_connection_free(connection);
347 return NULL;
348 }
349
350 return connection;
351}
352
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800353void
354core_connection_detach(CoreConnection* desc)
355{
356 core_connection_write(desc, "\n", 1, NULL);
357}
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800358
359int
360core_connection_get_socket(CoreConnection* desc)
361{
362 return (desc != NULL) ? syncsocket_get_socket(desc->ssocket) : -1;
363}