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. */ 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. 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 */ 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 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 324CoreConnection* 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 353void 354core_connection_detach(CoreConnection* desc) 355{ 356 core_connection_write(desc, "\n", 1, NULL); 357} 358 359int 360core_connection_get_socket(CoreConnection* desc) 361{ 362 return (desc != NULL) ? syncsocket_get_socket(desc->ssocket) : -1; 363} 364