1d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine/* Copyright (C) 2010 The Android Open Source Project 2d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine** 3d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine** This software is licensed under the terms of the GNU General Public 4d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine** License version 2, as published by the Free Software Foundation, and 5d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine** may be copied, distributed, and modified under those terms. 6d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine** 7d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine** This program is distributed in the hope that it will be useful, 8d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine** but WITHOUT ANY WARRANTY; without even the implied warranty of 9d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine** GNU General Public License for more details. 11d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine*/ 12d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 13d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine#include <unistd.h> 14d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 15d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine#include "sockets.h" 16d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine#include "qemu-common.h" 17d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine#include "errno.h" 18d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine#include "iolooper.h" 19d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine#include "android/android.h" 20d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine#include "android/utils/debug.h" 21d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine#include "android/globals.h" 22d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine#include "android/utils/system.h" 23e993126c6704029cb1c656922a66a32bd09b6089David 'Digit' Turner#include "android/protocol/core-connection.h" 24d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 25d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine/* Descriptor for a client, connected to the core via console port. */ 26d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinestruct CoreConnection { 27d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine /* Socket address of the console. */ 28d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine SockAddress console_address; 29d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 30d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // Helper for performing sync I/O on the console socket. 31d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine SyncSocket* ssocket; 32d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 33d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine /* Stream name. Can be: 34d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * - NULL for the console itself. 35a473d81826d44905bc0d7ec8c9b39aef1cf87fb7Vladimir Chtchetkine * - "attach-UI" for the attached UI client. 36d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine */ 37d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine char* stream_name; 38d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine}; 39d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 40d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine/* 41d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * Zero-terminates string buffer. 42d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * Param: 43d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * buf - Buffer containing the string. 44d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * buf_size - Buffer size. 45d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * eos - String size. 46d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine */ 47d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinestatic inline void 48d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine_zero_terminate(char* buf, size_t buf_size, size_t eos) 49d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 50d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (eos < buf_size) { 51d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine buf[eos] = '\0'; 52d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } else { 53d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine buf[buf_size - 1] = '\0'; 54d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 55d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 56d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 57d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine/* 58d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * Checks if console has replied with "OK" 59d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * Param: 60d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * reply - String containing console's reply 61d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * Return: 62d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * boolean: true if reply was "OK", or false otherwise. 63d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine */ 64d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinestatic int 65d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine_is_reply_ok(const char* reply, int reply_size) 66d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 67d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return (reply_size < 2) ? 0 : (reply[0] == 'O' && reply[1] == 'K'); 68d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 69d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 70d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine/* 71d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * Checks if console has replied with "KO" 72d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * Param: 73d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * reply - String containing console's reply 74d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * Return: 75d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine * boolean: true if reply was "KO", or false otherwise. 76d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine */ 77d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinestatic int 78d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine_is_reply_ko(const char* reply, int reply_size) 79d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 80d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return (reply_size < 2) ? 0 : (reply[0] == 'K' && reply[1] == 'O'); 81d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 82d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 83d87b080495e71ada650b165a1f06616b433e6073Vladimir ChtchetkineSyncSocket* 84d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinecore_connection_open_socket(SockAddress* sockaddr) 85d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 86d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine SyncSocket* ssocket; 87d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine int status; 88d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine int64_t deadline; 89d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine char buf[512]; 90d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 91d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine int fd = socket_create(sock_address_get_family(sockaddr), SOCKET_STREAM); 92d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (fd < 0) { 93d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return NULL; 94d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 95d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 96d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine socket_set_xreuseaddr(fd); 97d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 98d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // Create sync connection to the console. 99d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine ssocket = syncsocket_connect(fd, sockaddr, CORE_PORT_TIMEOUT_MS); 100d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (ssocket == NULL) { 101d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("syncsocket_connect has failed: %s\n", errno_str); 102d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine socket_close(fd); 103d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return NULL; 104d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 105d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 106d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // Upon successful connection the console will reply with two strings: 107d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // "Android Console....", and "OK\r\n". Read them and check. 108d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine status = syncsocket_start_read(ssocket); 109d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (status < 0) { 110d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("syncsocket_start_read has failed: %s\n", errno_str); 111d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_free(ssocket); 112d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return NULL; 113d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 114d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 115d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine deadline = iolooper_now() + CORE_PORT_TIMEOUT_MS; 116d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // Read first line. 117d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine status = syncsocket_read_line_absolute(ssocket, buf, sizeof(buf), deadline); 118d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (status <= 0) { 119d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("syncsocket_read_line_absolute has failed: %s\n", errno_str); 120d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_free(ssocket); 121d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return NULL; 122d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 123d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (status < 15 || memcmp(buf, "Android Console", 15)) { 124d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine _zero_terminate(buf, sizeof(buf), status); 125d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("console has failed the connection: %s\n", buf); 126d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_free(ssocket); 127d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return NULL; 128d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 129d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // Read second line 130d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine status = syncsocket_read_line_absolute(ssocket, buf, sizeof(buf), deadline); 131d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_stop_read(ssocket); 132d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (status < 2 || !_is_reply_ok(buf, status)) { 133d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine _zero_terminate(buf, sizeof(buf), status); 134d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("unexpected reply from the console: %s\n", buf); 135d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_free(ssocket); 136d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return NULL; 137d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 138d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 139d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return ssocket; 140d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 141d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 142d87b080495e71ada650b165a1f06616b433e6073Vladimir ChtchetkineCoreConnection* 143d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinecore_connection_create(SockAddress* console_address) 144d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 145d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine CoreConnection* desc; 146d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine ANEW0(desc); 147d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine desc->console_address = console_address[0]; 148d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine desc->ssocket = NULL; 149d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine desc->stream_name = NULL; 150d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 151d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return desc; 152d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 153d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 154d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinevoid 155d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinecore_connection_free(CoreConnection* desc) 156d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 157d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (desc == NULL) { 158d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return; 159d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 160d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (desc->ssocket != NULL) { 161d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_free(desc->ssocket); 162d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 163d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (desc->stream_name != NULL) { 164d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine free(desc->stream_name); 165d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 166d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine free(desc); 167d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 168d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 169d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkineint 170d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinecore_connection_open(CoreConnection* desc) 171d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 172d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (desc == NULL) { 173d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine errno = EINVAL; 174d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return -1; 175d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 176d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (desc->ssocket != NULL) { 177d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return 0; 178d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 179d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 180d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine desc->ssocket = core_connection_open_socket(&desc->console_address); 181d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 182d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return (desc->ssocket != NULL) ? 0 : -1; 183d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 184d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 185d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinevoid 186d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinecore_connection_close(CoreConnection* desc) 187d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 188d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (desc == NULL) { 189d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return; 190d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 191d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (desc->ssocket != NULL) { 192d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_close(desc->ssocket); 193d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 194d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 195d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 196d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkineint 197d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinecore_connection_write(CoreConnection* desc, 198d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine const void* buffer, 199d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine size_t to_write, 200d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine size_t* written_bytes) 201d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 202d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine ssize_t written; 203d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 204d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine int status = syncsocket_start_write(desc->ssocket); 205d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (status < 0) { 206d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("syncsocket_start_write failed: %s\n", errno_str); 207d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return status; 208d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 209d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 210d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine written = 211d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_write(desc->ssocket, buffer, to_write, CORE_PORT_TIMEOUT_MS); 212d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_stop_write(desc->ssocket); 213d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (written <= 0) { 214d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("syncsocket_write failed: %s\n", errno_str); 215d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return -1; 216d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 217d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (written_bytes != NULL) { 218d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine *written_bytes = written; 219d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 220d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 221d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return 0; 222d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 223d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 224d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkineint 225d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinecore_connection_read(CoreConnection* desc, 226d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine void* buffer, 227d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine size_t to_read, 228d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine size_t* read_bytes) 229d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 230d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine ssize_t read_size; 231d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 232d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine int status = syncsocket_start_read(desc->ssocket); 233d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (status < 0) { 234d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("syncsocket_start_read failed: %s\n", errno_str); 235d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return status; 236d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 237d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 238d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine read_size = 239d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_read(desc->ssocket, buffer, to_read, CORE_PORT_TIMEOUT_MS); 240d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_stop_read(desc->ssocket); 241d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (read_size <= 0) { 242d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("syncsocket_read failed: %s\n", errno_str); 243d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return -1; 244d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 245d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 246d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (read_bytes != NULL) { 247d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine *read_bytes = read_size; 248d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 249d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return 0; 250d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 251d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 252d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkineint 253d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinecore_connection_switch_stream(CoreConnection* desc, 254d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine const char* stream_name, 255d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine char** handshake) 256d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 257d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine char buf[4096]; 258d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine int handshake_len; 259d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine int status; 260d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine int64_t deadline; 261d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 262d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine *handshake = NULL; 263d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (desc == NULL || desc->stream_name != NULL || stream_name == NULL) { 264d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine errno = EINVAL; 265d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return -1; 266d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 267d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 268d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // Prepare and write "switch" command. 269d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine snprintf(buf, sizeof(buf), "qemu %s\r\n", stream_name); 270d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (core_connection_write(desc, buf, strlen(buf), NULL)) { 271d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return -1; 272d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 273d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 274d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // Read result / handshake 275d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine status = syncsocket_start_read(desc->ssocket); 276d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (status < 0) { 277d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return -1; 278d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 279d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine deadline = iolooper_now() + CORE_PORT_TIMEOUT_MS; 280d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine handshake_len = 281d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_read_line_absolute(desc->ssocket, buf, sizeof(buf), deadline); 282d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine _zero_terminate(buf, sizeof(buf), handshake_len); 283d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // Replace terminating "\r\n" with 0 284777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine if (handshake_len >= 1) { 285777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine if (buf[handshake_len - 1] == '\r' || buf[handshake_len - 1] == '\n') { 286777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine buf[handshake_len - 1] = '\0'; 287777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine if (handshake_len >= 2 && (buf[handshake_len - 2] == '\r' || 288777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine buf[handshake_len - 2] == '\n')) { 289777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine buf[handshake_len - 2] = '\0'; 290777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine } 291777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine } 292d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 293d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // Lets see what kind of response we've got here. 294d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (_is_reply_ok(buf, handshake_len)) { 295d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine *handshake = strdup(buf + 3); 296d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine desc->stream_name = strdup(stream_name); 297d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // We expect an "OK" string here 298d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine status = syncsocket_read_line_absolute(desc->ssocket, buf, sizeof(buf), 299d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine deadline); 300d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_stop_read(desc->ssocket); 301d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine if (status < 0) { 302d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("error reading console reply on stream switch: %s\n", errno_str); 303d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return -1; 304d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } else if (!_is_reply_ok(buf, status)) { 305d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine _zero_terminate(buf, sizeof(buf), status); 306d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("unexpected console reply when switching streams: %s\n", buf); 307d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return -1; 308d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 309d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return 0; 310d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } else if (_is_reply_ko(buf, handshake_len)) { 311d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("console has rejected stream switch: %s\n", buf); 312d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_stop_read(desc->ssocket); 313d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine *handshake = strdup(buf + 3); 314d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return -1; 315d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } else { 316d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine // No OK, no KO? Should be an error! 317d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine derror("unexpected console reply when switching streams: %s\n", buf); 318d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine syncsocket_stop_read(desc->ssocket); 319d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine *handshake = strdup(buf); 320d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine return -1; 321d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine } 322d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 323d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine 324777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir ChtchetkineCoreConnection* 325777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkinecore_connection_create_and_switch(SockAddress* console_socket, 326777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine const char* stream_name, 327777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine char** handshake) 328777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine{ 329777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine char switch_cmd[256]; 330777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine CoreConnection* connection = NULL; 331777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine 332777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine // Connect to the console service. 333777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine connection = core_connection_create(console_socket); 334777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine if (connection == NULL) { 335777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine return NULL; 336777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine } 337777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine if (core_connection_open(connection)) { 338777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine core_connection_free(connection); 339777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine return NULL; 340777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine } 341777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine 342777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine // Perform the switch. 343777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine snprintf(switch_cmd, sizeof(switch_cmd), "%s", stream_name); 344777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine if (core_connection_switch_stream(connection, switch_cmd, handshake)) { 345777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine core_connection_close(connection); 346777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine core_connection_free(connection); 347777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine return NULL; 348777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine } 349777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine 350777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine return connection; 351777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine} 352777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine 353d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinevoid 354d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkinecore_connection_detach(CoreConnection* desc) 355d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine{ 356d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine core_connection_write(desc, "\n", 1, NULL); 357d87b080495e71ada650b165a1f06616b433e6073Vladimir Chtchetkine} 358e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine 359e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkineint 360e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkinecore_connection_get_socket(CoreConnection* desc) 361e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine{ 362e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine return (desc != NULL) ? syncsocket_get_socket(desc->ssocket) : -1; 363e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine} 364