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