1 /* 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
15 #include "sockets.h"
16 #include "qemu-common.h"
17 #include "errno.h"
18 #include "iolooper.h"
19 #include "android/android.h"
20 #include "android/utils/debug.h"
21 #include "android/globals.h"
22 #include "android/utils/system.h"
23 #include "android/protocol/core-connection.h"
24
25 /* Descriptor for a client, connected to the core via console port. */
26 struct 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.
35 * - "attach-UI" for the attached UI client.
36 */
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 */
47 static inline void
_zero_terminate(char * buf,size_t buf_size,size_t eos)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 */
64 static int
_is_reply_ok(const char * reply,int reply_size)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 */
77 static int
_is_reply_ko(const char * reply,int reply_size)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
83 SyncSocket*
core_connection_open_socket(SockAddress * sockaddr)84 core_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
142 CoreConnection*
core_connection_create(SockAddress * console_address)143 core_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
154 void
core_connection_free(CoreConnection * desc)155 core_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
169 int
core_connection_open(CoreConnection * desc)170 core_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
185 void
core_connection_close(CoreConnection * desc)186 core_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
196 int
core_connection_write(CoreConnection * desc,const void * buffer,size_t to_write,size_t * written_bytes)197 core_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
224 int
core_connection_read(CoreConnection * desc,void * buffer,size_t to_read,size_t * read_bytes)225 core_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
252 int
core_connection_switch_stream(CoreConnection * desc,const char * stream_name,char ** handshake)253 core_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
284 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 }
292 }
293 // 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
324 CoreConnection*
core_connection_create_and_switch(SockAddress * console_socket,const char * stream_name,char ** handshake)325 core_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
353 void
core_connection_detach(CoreConnection * desc)354 core_connection_detach(CoreConnection* desc)
355 {
356 core_connection_write(desc, "\n", 1, NULL);
357 }
358
359 int
core_connection_get_socket(CoreConnection * desc)360 core_connection_get_socket(CoreConnection* desc)
361 {
362 return (desc != NULL) ? syncsocket_get_socket(desc->ssocket) : -1;
363 }
364