• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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