Home | History | Annotate | Download | only in protocol
      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
     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
     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
     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*
     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*
    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
    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
    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
    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
    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
    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
    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*
    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
    354 core_connection_detach(CoreConnection* desc)
    355 {
    356     core_connection_write(desc, "\n", 1, NULL);
    357 }
    358 
    359 int
    360 core_connection_get_socket(CoreConnection* desc)
    361 {
    362     return (desc != NULL) ? syncsocket_get_socket(desc->ssocket) : -1;
    363 }
    364