blob: 9435b7d643a13ea543dc617420c91f77872e78d4 [file] [log] [blame]
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001/*
2 * QEMU System Emulator
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
Markus Armbruster922a01a2018-02-01 12:18:46 +010024
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030025#include "qemu/osdep.h"
Marc-André Lureau8228e352017-01-26 17:19:46 +040026#include "chardev/char.h"
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030027#include "io/channel-socket.h"
28#include "io/channel-tls.h"
Julia Suvorova981b06e2018-10-19 01:35:00 +030029#include "io/channel-websock.h"
Daniel P. Berrange194b7f02017-12-18 13:54:17 +000030#include "io/net-listener.h"
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030031#include "qemu/error-report.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020032#include "qemu/module.h"
Markus Armbruster922a01a2018-02-01 12:18:46 +010033#include "qemu/option.h"
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030034#include "qapi/error.h"
35#include "qapi/clone-visitor.h"
Markus Armbruster9af23982018-02-11 10:36:01 +010036#include "qapi/qapi-visit-sockets.h"
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030037
Marc-André Lureau8228e352017-01-26 17:19:46 +040038#include "chardev/char-io.h"
Eduardo Habkostdb1015e2020-09-03 16:43:22 -040039#include "qom/object.h"
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030040
41/***********************************************************/
42/* TCP Net console */
43
44#define TCP_MAX_FDS 16
45
46typedef struct {
Peter Xuce1230c2018-03-06 13:33:15 +080047 char buf[21];
48 size_t buflen;
49} TCPChardevTelnetInit;
50
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +000051typedef enum {
52 TCP_CHARDEV_STATE_DISCONNECTED,
53 TCP_CHARDEV_STATE_CONNECTING,
54 TCP_CHARDEV_STATE_CONNECTED,
55} TCPChardevState;
56
Eduardo Habkostdb1015e2020-09-03 16:43:22 -040057struct SocketChardev {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030058 Chardev parent;
59 QIOChannel *ioc; /* Client I/O channel */
60 QIOChannelSocket *sioc; /* Client master channel */
Daniel P. Berrange194b7f02017-12-18 13:54:17 +000061 QIONetListener *listener;
Klim Kireeva8aa6192018-01-25 16:51:29 +030062 GSource *hup_source;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030063 QCryptoTLSCreds *tls_creds;
Daniel P. Berrangefd4a5fd2019-03-08 15:21:50 +000064 char *tls_authz;
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +000065 TCPChardevState state;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030066 int max_size;
67 int do_telnetopt;
68 int do_nodelay;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030069 int *read_msgfds;
70 size_t read_msgfds_num;
71 int *write_msgfds;
72 size_t write_msgfds_num;
73
74 SocketAddress *addr;
75 bool is_listen;
76 bool is_telnet;
Jing Liuae92cbd2016-09-23 08:06:11 +020077 bool is_tn3270;
Peter Xuce1230c2018-03-06 13:33:15 +080078 GSource *telnet_source;
79 TCPChardevTelnetInit *telnet_init;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030080
Julia Suvorova981b06e2018-10-19 01:35:00 +030081 bool is_websock;
82
Peter Xu2c716ba2018-01-04 22:18:35 +080083 GSource *reconnect_timer;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030084 int64_t reconnect_time;
85 bool connect_err_reported;
Daniel P. Berrangé4b473732019-02-11 18:24:40 +000086
87 QIOTask *connect_task;
Eduardo Habkostdb1015e2020-09-03 16:43:22 -040088};
89typedef struct SocketChardev SocketChardev;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030090
91#define SOCKET_CHARDEV(obj) \
92 OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
93
94static gboolean socket_reconnect_timeout(gpointer opaque);
Peter Xuce1230c2018-03-06 13:33:15 +080095static void tcp_chr_telnet_init(Chardev *chr);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +030096
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +000097static void tcp_chr_change_state(SocketChardev *s, TCPChardevState state)
98{
99 switch (state) {
100 case TCP_CHARDEV_STATE_DISCONNECTED:
101 break;
102 case TCP_CHARDEV_STATE_CONNECTING:
103 assert(s->state == TCP_CHARDEV_STATE_DISCONNECTED);
104 break;
105 case TCP_CHARDEV_STATE_CONNECTED:
106 assert(s->state == TCP_CHARDEV_STATE_CONNECTING);
107 break;
108 }
109 s->state = state;
110}
111
Peter Xu2c716ba2018-01-04 22:18:35 +0800112static void tcp_chr_reconn_timer_cancel(SocketChardev *s)
113{
114 if (s->reconnect_timer) {
115 g_source_destroy(s->reconnect_timer);
116 g_source_unref(s->reconnect_timer);
117 s->reconnect_timer = NULL;
118 }
119}
120
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300121static void qemu_chr_socket_restart_timer(Chardev *chr)
122{
123 SocketChardev *s = SOCKET_CHARDEV(chr);
124 char *name;
125
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000126 assert(s->state == TCP_CHARDEV_STATE_DISCONNECTED);
Daniel P. Berrangé4b473732019-02-11 18:24:40 +0000127 assert(!s->reconnect_timer);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300128 name = g_strdup_printf("chardev-socket-reconnect-%s", chr->label);
Peter Xu2c716ba2018-01-04 22:18:35 +0800129 s->reconnect_timer = qemu_chr_timeout_add_ms(chr,
130 s->reconnect_time * 1000,
131 socket_reconnect_timeout,
132 chr);
133 g_source_set_name(s->reconnect_timer, name);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300134 g_free(name);
135}
136
137static void check_report_connect_error(Chardev *chr,
138 Error *err)
139{
140 SocketChardev *s = SOCKET_CHARDEV(chr);
141
142 if (!s->connect_err_reported) {
Markus Armbruster5217f182020-05-05 12:19:03 +0200143 error_reportf_err(err,
144 "Unable to connect character device %s: ",
145 chr->label);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300146 s->connect_err_reported = true;
lichuned4e0d22020-06-22 05:30:17 +0800147 } else {
148 error_free(err);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300149 }
150 qemu_chr_socket_restart_timer(chr);
151}
152
Daniel P. Berrange194b7f02017-12-18 13:54:17 +0000153static void tcp_chr_accept(QIONetListener *listener,
154 QIOChannelSocket *cioc,
155 void *opaque);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300156
Anton Nefedovb0a335e2017-02-02 17:26:29 +0300157static int tcp_chr_read_poll(void *opaque);
Alberto Garcia78d01592019-08-12 18:58:29 +0300158static void tcp_chr_disconnect_locked(Chardev *chr);
Anton Nefedovb0a335e2017-02-02 17:26:29 +0300159
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300160/* Called with chr_write_lock held. */
161static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
162{
163 SocketChardev *s = SOCKET_CHARDEV(chr);
164
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000165 if (s->state == TCP_CHARDEV_STATE_CONNECTED) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300166 int ret = io_channel_send_full(s->ioc, buf, len,
167 s->write_msgfds,
168 s->write_msgfds_num);
169
xinhua.Cao81e34932018-07-04 11:36:42 +0800170 /* free the written msgfds in any cases
171 * other than ret < 0 && errno == EAGAIN
172 */
173 if (!(ret < 0 && EAGAIN == errno)
174 && s->write_msgfds_num) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300175 g_free(s->write_msgfds);
176 s->write_msgfds = 0;
177 s->write_msgfds_num = 0;
178 }
179
Anton Nefedovb0a335e2017-02-02 17:26:29 +0300180 if (ret < 0 && errno != EAGAIN) {
181 if (tcp_chr_read_poll(chr) <= 0) {
Dima Stepanov27109442020-05-28 12:11:18 +0300182 /* Perform disconnect and return error. */
Alberto Garcia78d01592019-08-12 18:58:29 +0300183 tcp_chr_disconnect_locked(chr);
Anton Nefedovb0a335e2017-02-02 17:26:29 +0300184 } /* else let the read handler finish it properly */
185 }
186
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300187 return ret;
188 } else {
Dima Stepanov27109442020-05-28 12:11:18 +0300189 /* Indicate an error. */
190 errno = EIO;
191 return -1;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300192 }
193}
194
195static int tcp_chr_read_poll(void *opaque)
196{
197 Chardev *chr = CHARDEV(opaque);
198 SocketChardev *s = SOCKET_CHARDEV(opaque);
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000199 if (s->state != TCP_CHARDEV_STATE_CONNECTED) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300200 return 0;
201 }
202 s->max_size = qemu_chr_be_can_write(chr);
203 return s->max_size;
204}
205
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300206static void tcp_chr_process_IAC_bytes(Chardev *chr,
207 SocketChardev *s,
208 uint8_t *buf, int *size)
209{
Jing Liuae92cbd2016-09-23 08:06:11 +0200210 /* Handle any telnet or tn3270 client's basic IAC options.
211 * For telnet options, it satisfies char by char mode with no echo.
212 * For tn3270 options, it satisfies binary mode with EOR.
213 * All IAC options will be removed from the buf and the do_opt
214 * pointer will be used to track the state of the width of the
215 * IAC information.
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300216 *
Jing Liuae92cbd2016-09-23 08:06:11 +0200217 * RFC854: "All TELNET commands consist of at least a two byte sequence.
218 * The commands dealing with option negotiation are three byte sequences,
219 * the third byte being the code for the option referenced."
220 * "IAC BREAK", "IAC IP", "IAC NOP" and the double IAC are two bytes.
221 * "IAC SB", "IAC SE" and "IAC EOR" are saved to split up data boundary
222 * for tn3270.
223 * NOP, Break and Interrupt Process(IP) might be encountered during a TN3270
224 * session, and NOP and IP need to be done later.
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300225 */
226
227 int i;
228 int j = 0;
229
230 for (i = 0; i < *size; i++) {
231 if (s->do_telnetopt > 1) {
232 if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
233 /* Double IAC means send an IAC */
234 if (j != i) {
235 buf[j] = buf[i];
236 }
237 j++;
238 s->do_telnetopt = 1;
239 } else {
240 if ((unsigned char)buf[i] == IAC_BREAK
241 && s->do_telnetopt == 2) {
242 /* Handle IAC break commands by sending a serial break */
243 qemu_chr_be_event(chr, CHR_EVENT_BREAK);
244 s->do_telnetopt++;
Jing Liuae92cbd2016-09-23 08:06:11 +0200245 } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_EOR
246 || (unsigned char)buf[i] == IAC_SB
247 || (unsigned char)buf[i] == IAC_SE)
248 && s->do_telnetopt == 2) {
249 buf[j++] = IAC;
250 buf[j++] = buf[i];
251 s->do_telnetopt++;
252 } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_IP
253 || (unsigned char)buf[i] == IAC_NOP)
254 && s->do_telnetopt == 2) {
255 /* TODO: IP and NOP need to be implemented later. */
256 s->do_telnetopt++;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300257 }
258 s->do_telnetopt++;
259 }
260 if (s->do_telnetopt >= 4) {
261 s->do_telnetopt = 1;
262 }
263 } else {
264 if ((unsigned char)buf[i] == IAC) {
265 s->do_telnetopt = 2;
266 } else {
267 if (j != i) {
268 buf[j] = buf[i];
269 }
270 j++;
271 }
272 }
273 }
274 *size = j;
275}
276
277static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
278{
279 SocketChardev *s = SOCKET_CHARDEV(chr);
280
281 int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
282
283 assert(num <= TCP_MAX_FDS);
284
285 if (to_copy) {
286 int i;
287
288 memcpy(fds, s->read_msgfds, to_copy * sizeof(int));
289
290 /* Close unused fds */
291 for (i = to_copy; i < s->read_msgfds_num; i++) {
292 close(s->read_msgfds[i]);
293 }
294
295 g_free(s->read_msgfds);
296 s->read_msgfds = 0;
297 s->read_msgfds_num = 0;
298 }
299
300 return to_copy;
301}
302
303static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
304{
305 SocketChardev *s = SOCKET_CHARDEV(chr);
306
307 /* clear old pending fd array */
308 g_free(s->write_msgfds);
309 s->write_msgfds = NULL;
310 s->write_msgfds_num = 0;
311
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000312 if ((s->state != TCP_CHARDEV_STATE_CONNECTED) ||
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300313 !qio_channel_has_feature(s->ioc,
314 QIO_CHANNEL_FEATURE_FD_PASS)) {
315 return -1;
316 }
317
318 if (num) {
319 s->write_msgfds = g_new(int, num);
320 memcpy(s->write_msgfds, fds, num * sizeof(int));
321 }
322
323 s->write_msgfds_num = num;
324
325 return 0;
326}
327
328static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
329{
330 SocketChardev *s = SOCKET_CHARDEV(chr);
331 struct iovec iov = { .iov_base = buf, .iov_len = len };
332 int ret;
333 size_t i;
334 int *msgfds = NULL;
335 size_t msgfds_num = 0;
336
337 if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
338 ret = qio_channel_readv_full(s->ioc, &iov, 1,
339 &msgfds, &msgfds_num,
340 NULL);
341 } else {
342 ret = qio_channel_readv_full(s->ioc, &iov, 1,
343 NULL, NULL,
344 NULL);
345 }
346
347 if (ret == QIO_CHANNEL_ERR_BLOCK) {
348 errno = EAGAIN;
349 ret = -1;
350 } else if (ret == -1) {
351 errno = EIO;
352 }
353
354 if (msgfds_num) {
355 /* close and clean read_msgfds */
356 for (i = 0; i < s->read_msgfds_num; i++) {
357 close(s->read_msgfds[i]);
358 }
359
360 if (s->read_msgfds_num) {
361 g_free(s->read_msgfds);
362 }
363
364 s->read_msgfds = msgfds;
365 s->read_msgfds_num = msgfds_num;
366 }
367
368 for (i = 0; i < s->read_msgfds_num; i++) {
369 int fd = s->read_msgfds[i];
370 if (fd < 0) {
371 continue;
372 }
373
374 /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
375 qemu_set_block(fd);
376
377#ifndef MSG_CMSG_CLOEXEC
378 qemu_set_cloexec(fd);
379#endif
380 }
381
382 return ret;
383}
384
385static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
386{
387 SocketChardev *s = SOCKET_CHARDEV(chr);
388 return qio_channel_create_watch(s->ioc, cond);
389}
390
Marc-André Lureaudfe9ea22018-08-17 15:52:23 +0200391static void remove_hup_source(SocketChardev *s)
392{
393 if (s->hup_source != NULL) {
394 g_source_destroy(s->hup_source);
395 g_source_unref(s->hup_source);
396 s->hup_source = NULL;
397 }
398}
399
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300400static void tcp_chr_free_connection(Chardev *chr)
401{
402 SocketChardev *s = SOCKET_CHARDEV(chr);
403 int i;
404
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300405 if (s->read_msgfds_num) {
406 for (i = 0; i < s->read_msgfds_num; i++) {
407 close(s->read_msgfds[i]);
408 }
409 g_free(s->read_msgfds);
410 s->read_msgfds = NULL;
411 s->read_msgfds_num = 0;
412 }
413
Marc-André Lureaudfe9ea22018-08-17 15:52:23 +0200414 remove_hup_source(s);
Klim Kireeva8aa6192018-01-25 16:51:29 +0300415
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300416 tcp_set_msgfds(chr, NULL, 0);
zhanghailiangb19456d2017-04-19 09:15:32 +0800417 remove_fd_in_watch(chr);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300418 object_unref(OBJECT(s->sioc));
419 s->sioc = NULL;
420 object_unref(OBJECT(s->ioc));
421 s->ioc = NULL;
422 g_free(chr->filename);
423 chr->filename = NULL;
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000424 tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300425}
426
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300427static const char *qemu_chr_socket_protocol(SocketChardev *s)
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300428{
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300429 if (s->is_telnet) {
430 return "telnet";
431 }
Julia Suvorova981b06e2018-10-19 01:35:00 +0300432 return s->is_websock ? "websocket" : "tcp";
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300433}
434
435static char *qemu_chr_socket_address(SocketChardev *s, const char *prefix)
436{
437 switch (s->addr->type) {
Markus Armbrusterbd269eb2017-04-26 09:36:41 +0200438 case SOCKET_ADDRESS_TYPE_INET:
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300439 return g_strdup_printf("%s%s:%s:%s%s", prefix,
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300440 qemu_chr_socket_protocol(s),
441 s->addr->u.inet.host,
442 s->addr->u.inet.port,
443 s->is_listen ? ",server" : "");
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300444 break;
Markus Armbrusterbd269eb2017-04-26 09:36:41 +0200445 case SOCKET_ADDRESS_TYPE_UNIX:
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300446 return g_strdup_printf("%sunix:%s%s", prefix,
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300447 s->addr->u.q_unix.path,
448 s->is_listen ? ",server" : "");
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300449 break;
Markus Armbrusterbd269eb2017-04-26 09:36:41 +0200450 case SOCKET_ADDRESS_TYPE_FD:
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300451 return g_strdup_printf("%sfd:%s%s", prefix, s->addr->u.fd.str,
452 s->is_listen ? ",server" : "");
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300453 break;
Markus Armbrusterbd269eb2017-04-26 09:36:41 +0200454 case SOCKET_ADDRESS_TYPE_VSOCK:
Markus Armbrusterd2e49aa2017-03-30 19:43:10 +0200455 return g_strdup_printf("%svsock:%s:%s", prefix,
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300456 s->addr->u.vsock.cid,
457 s->addr->u.vsock.port);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300458 default:
459 abort();
460 }
461}
462
Marc-André Lureaubbcde962016-12-20 15:32:31 +0100463static void update_disconnected_filename(SocketChardev *s)
464{
465 Chardev *chr = CHARDEV(s);
466
467 g_free(chr->filename);
Marc-André Lureau90a6d172017-07-04 18:53:35 +0200468 if (s->addr) {
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300469 chr->filename = qemu_chr_socket_address(s, "disconnected:");
Marc-André Lureau90a6d172017-07-04 18:53:35 +0200470 } else {
471 chr->filename = g_strdup("disconnected:socket");
472 }
Marc-André Lureaubbcde962016-12-20 15:32:31 +0100473}
474
Daniel P. Berrange9cca7572017-10-05 16:50:57 +0100475/* NB may be called even if tcp_chr_connect has not been
476 * reached, due to TLS or telnet initialization failure,
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000477 * so can *not* assume s->state == TCP_CHARDEV_STATE_CONNECTED
Alberto Garcia78d01592019-08-12 18:58:29 +0300478 * This must be called with chr->chr_write_lock held.
Daniel P. Berrange9cca7572017-10-05 16:50:57 +0100479 */
Alberto Garcia78d01592019-08-12 18:58:29 +0300480static void tcp_chr_disconnect_locked(Chardev *chr)
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300481{
482 SocketChardev *s = SOCKET_CHARDEV(chr);
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000483 bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300484
485 tcp_chr_free_connection(chr);
486
Daniel P. Berrange194b7f02017-12-18 13:54:17 +0000487 if (s->listener) {
Peter Xu3da9de52018-03-06 13:33:14 +0800488 qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept,
489 chr, NULL, chr->gcontext);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300490 }
Marc-André Lureaubbcde962016-12-20 15:32:31 +0100491 update_disconnected_filename(s);
Daniel P. Berrange9cca7572017-10-05 16:50:57 +0100492 if (emit_close) {
493 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
494 }
Li Feng2b61bb72020-05-22 10:55:54 +0800495 if (s->reconnect_time && !s->reconnect_timer) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300496 qemu_chr_socket_restart_timer(chr);
497 }
498}
499
Alberto Garcia78d01592019-08-12 18:58:29 +0300500static void tcp_chr_disconnect(Chardev *chr)
501{
502 qemu_mutex_lock(&chr->chr_write_lock);
503 tcp_chr_disconnect_locked(chr);
504 qemu_mutex_unlock(&chr->chr_write_lock);
505}
506
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300507static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
508{
509 Chardev *chr = CHARDEV(opaque);
510 SocketChardev *s = SOCKET_CHARDEV(opaque);
511 uint8_t buf[CHR_READ_BUF_LEN];
512 int len, size;
513
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000514 if ((s->state != TCP_CHARDEV_STATE_CONNECTED) ||
515 s->max_size <= 0) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300516 return TRUE;
517 }
518 len = sizeof(buf);
519 if (len > s->max_size) {
520 len = s->max_size;
521 }
522 size = tcp_chr_recv(chr, (void *)buf, len);
Daniel P. Berrangéc863fde2018-02-22 12:13:51 +0000523 if (size == 0 || (size == -1 && errno != EAGAIN)) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300524 /* connection closed */
525 tcp_chr_disconnect(chr);
526 } else if (size > 0) {
527 if (s->do_telnetopt) {
528 tcp_chr_process_IAC_bytes(chr, s, buf, &size);
529 }
530 if (size > 0) {
531 qemu_chr_be_write(chr, buf, size);
532 }
533 }
534
535 return TRUE;
536}
537
Klim Kireeva8aa6192018-01-25 16:51:29 +0300538static gboolean tcp_chr_hup(QIOChannel *channel,
539 GIOCondition cond,
540 void *opaque)
541{
542 Chardev *chr = CHARDEV(opaque);
543 tcp_chr_disconnect(chr);
544 return G_SOURCE_REMOVE;
545}
546
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300547static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
548{
549 SocketChardev *s = SOCKET_CHARDEV(chr);
550 int size;
551
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000552 if (s->state != TCP_CHARDEV_STATE_CONNECTED) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300553 return 0;
554 }
555
Marc-André Lureaubcdeb9b2017-07-06 19:03:53 +0200556 qio_channel_set_blocking(s->ioc, true, NULL);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300557 size = tcp_chr_recv(chr, (void *) buf, len);
Sai Pavan Boddu4d1d4602020-04-19 15:21:40 +0530558 if (s->state != TCP_CHARDEV_STATE_DISCONNECTED) {
559 qio_channel_set_blocking(s->ioc, false, NULL);
560 }
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300561 if (size == 0) {
562 /* connection closed */
563 tcp_chr_disconnect(chr);
564 }
565
566 return size;
567}
568
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300569static char *qemu_chr_compute_filename(SocketChardev *s)
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300570{
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300571 struct sockaddr_storage *ss = &s->sioc->localAddr;
572 struct sockaddr_storage *ps = &s->sioc->remoteAddr;
573 socklen_t ss_len = s->sioc->localAddrLen;
574 socklen_t ps_len = s->sioc->remoteAddrLen;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300575 char shost[NI_MAXHOST], sserv[NI_MAXSERV];
576 char phost[NI_MAXHOST], pserv[NI_MAXSERV];
577 const char *left = "", *right = "";
578
579 switch (ss->ss_family) {
580#ifndef _WIN32
581 case AF_UNIX:
582 return g_strdup_printf("unix:%s%s",
583 ((struct sockaddr_un *)(ss))->sun_path,
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300584 s->is_listen ? ",server" : "");
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300585#endif
586 case AF_INET6:
587 left = "[";
588 right = "]";
589 /* fall through */
590 case AF_INET:
591 getnameinfo((struct sockaddr *) ss, ss_len, shost, sizeof(shost),
592 sserv, sizeof(sserv), NI_NUMERICHOST | NI_NUMERICSERV);
593 getnameinfo((struct sockaddr *) ps, ps_len, phost, sizeof(phost),
594 pserv, sizeof(pserv), NI_NUMERICHOST | NI_NUMERICSERV);
595 return g_strdup_printf("%s:%s%s%s:%s%s <-> %s%s%s:%s",
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300596 qemu_chr_socket_protocol(s),
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300597 left, shost, right, sserv,
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300598 s->is_listen ? ",server" : "",
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300599 left, phost, right, pserv);
600
601 default:
602 return g_strdup_printf("unknown");
603 }
604}
605
Marc-André Lureaudfe9ea22018-08-17 15:52:23 +0200606static void update_ioc_handlers(SocketChardev *s)
607{
608 Chardev *chr = CHARDEV(s);
609
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000610 if (s->state != TCP_CHARDEV_STATE_CONNECTED) {
Marc-André Lureaudfe9ea22018-08-17 15:52:23 +0200611 return;
612 }
613
614 remove_fd_in_watch(chr);
615 chr->gsource = io_add_watch_poll(chr, s->ioc,
616 tcp_chr_read_poll,
617 tcp_chr_read, chr,
618 chr->gcontext);
619
620 remove_hup_source(s);
621 s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP);
622 g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup,
623 chr, NULL);
624 g_source_attach(s->hup_source, chr->gcontext);
625}
626
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300627static void tcp_chr_connect(void *opaque)
628{
629 Chardev *chr = CHARDEV(opaque);
630 SocketChardev *s = SOCKET_CHARDEV(opaque);
631
632 g_free(chr->filename);
Julia Suvorova4493b6a2018-10-19 01:34:59 +0300633 chr->filename = qemu_chr_compute_filename(s);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300634
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000635 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTED);
Marc-André Lureaudfe9ea22018-08-17 15:52:23 +0200636 update_ioc_handlers(s);
Marc-André Lureau63618132016-12-14 14:23:02 +0300637 qemu_chr_be_event(chr, CHR_EVENT_OPENED);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300638}
639
Peter Xuce1230c2018-03-06 13:33:15 +0800640static void tcp_chr_telnet_destroy(SocketChardev *s)
641{
642 if (s->telnet_source) {
643 g_source_destroy(s->telnet_source);
644 g_source_unref(s->telnet_source);
645 s->telnet_source = NULL;
646 }
647}
648
Peter Xubb86d052017-09-21 14:35:54 +0800649static void tcp_chr_update_read_handler(Chardev *chr)
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300650{
651 SocketChardev *s = SOCKET_CHARDEV(chr);
652
Paolo Bonzini5b774fe2019-02-20 15:33:27 +0100653 if (s->listener && s->state == TCP_CHARDEV_STATE_DISCONNECTED) {
Peter Xu3da9de52018-03-06 13:33:14 +0800654 /*
655 * It's possible that chardev context is changed in
656 * qemu_chr_be_update_read_handlers(). Reset it for QIO net
657 * listener if there is.
658 */
659 qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept,
660 chr, NULL, chr->gcontext);
661 }
662
Peter Xuce1230c2018-03-06 13:33:15 +0800663 if (s->telnet_source) {
664 tcp_chr_telnet_init(CHARDEV(s));
665 }
666
Marc-André Lureaudfe9ea22018-08-17 15:52:23 +0200667 update_ioc_handlers(s);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300668}
669
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300670static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
671 GIOCondition cond G_GNUC_UNUSED,
672 gpointer user_data)
673{
Peter Xuce1230c2018-03-06 13:33:15 +0800674 SocketChardev *s = user_data;
675 Chardev *chr = CHARDEV(s);
676 TCPChardevTelnetInit *init = s->telnet_init;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300677 ssize_t ret;
678
Peter Xuce1230c2018-03-06 13:33:15 +0800679 assert(init);
680
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300681 ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
682 if (ret < 0) {
683 if (ret == QIO_CHANNEL_ERR_BLOCK) {
684 ret = 0;
685 } else {
Peter Xuce1230c2018-03-06 13:33:15 +0800686 tcp_chr_disconnect(chr);
Peter Xu8b2ec542018-03-01 16:44:24 +0800687 goto end;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300688 }
689 }
690 init->buflen -= ret;
691
692 if (init->buflen == 0) {
Peter Xuce1230c2018-03-06 13:33:15 +0800693 tcp_chr_connect(chr);
Peter Xu8b2ec542018-03-01 16:44:24 +0800694 goto end;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300695 }
696
697 memmove(init->buf, init->buf + ret, init->buflen);
698
Peter Xu8b2ec542018-03-01 16:44:24 +0800699 return G_SOURCE_CONTINUE;
700
701end:
Peter Xuce1230c2018-03-06 13:33:15 +0800702 g_free(s->telnet_init);
703 s->telnet_init = NULL;
704 g_source_unref(s->telnet_source);
705 s->telnet_source = NULL;
Peter Xu8b2ec542018-03-01 16:44:24 +0800706 return G_SOURCE_REMOVE;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300707}
708
709static void tcp_chr_telnet_init(Chardev *chr)
710{
711 SocketChardev *s = SOCKET_CHARDEV(chr);
Peter Xuce1230c2018-03-06 13:33:15 +0800712 TCPChardevTelnetInit *init;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300713 size_t n = 0;
714
Peter Xuce1230c2018-03-06 13:33:15 +0800715 /* Destroy existing task */
716 tcp_chr_telnet_destroy(s);
717
718 if (s->telnet_init) {
719 /* We are possibly during a handshake already */
720 goto cont;
721 }
722
723 s->telnet_init = g_new0(TCPChardevTelnetInit, 1);
724 init = s->telnet_init;
725
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300726#define IACSET(x, a, b, c) \
727 do { \
728 x[n++] = a; \
729 x[n++] = b; \
730 x[n++] = c; \
731 } while (0)
732
Jing Liuae92cbd2016-09-23 08:06:11 +0200733 if (!s->is_tn3270) {
734 init->buflen = 12;
735 /* Prep the telnet negotion to put telnet in binary,
736 * no echo, single char mode */
737 IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
738 IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
739 IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
740 IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
741 } else {
742 init->buflen = 21;
743 /* Prep the TN3270 negotion based on RFC1576 */
744 IACSET(init->buf, 0xff, 0xfd, 0x19); /* IAC DO EOR */
745 IACSET(init->buf, 0xff, 0xfb, 0x19); /* IAC WILL EOR */
746 IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO BINARY */
747 IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL BINARY */
748 IACSET(init->buf, 0xff, 0xfd, 0x18); /* IAC DO TERMINAL TYPE */
749 IACSET(init->buf, 0xff, 0xfa, 0x18); /* IAC SB TERMINAL TYPE */
750 IACSET(init->buf, 0x01, 0xff, 0xf0); /* SEND IAC SE */
751 }
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300752
753#undef IACSET
754
Peter Xuce1230c2018-03-06 13:33:15 +0800755cont:
756 s->telnet_source = qio_channel_add_watch_source(s->ioc, G_IO_OUT,
757 tcp_chr_telnet_init_io,
758 s, NULL,
759 chr->gcontext);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300760}
761
762
Julia Suvorova981b06e2018-10-19 01:35:00 +0300763static void tcp_chr_websock_handshake(QIOTask *task, gpointer user_data)
764{
765 Chardev *chr = user_data;
766 SocketChardev *s = user_data;
767
768 if (qio_task_propagate_error(task, NULL)) {
769 tcp_chr_disconnect(chr);
770 } else {
771 if (s->do_telnetopt) {
772 tcp_chr_telnet_init(chr);
773 } else {
774 tcp_chr_connect(chr);
775 }
776 }
777}
778
779
780static void tcp_chr_websock_init(Chardev *chr)
781{
782 SocketChardev *s = SOCKET_CHARDEV(chr);
783 QIOChannelWebsock *wioc = NULL;
784 gchar *name;
785
786 wioc = qio_channel_websock_new_server(s->ioc);
787
788 name = g_strdup_printf("chardev-websocket-server-%s", chr->label);
789 qio_channel_set_name(QIO_CHANNEL(wioc), name);
790 g_free(name);
791 object_unref(OBJECT(s->ioc));
792 s->ioc = QIO_CHANNEL(wioc);
793
794 qio_channel_websock_handshake(wioc, tcp_chr_websock_handshake, chr, NULL);
795}
796
797
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300798static void tcp_chr_tls_handshake(QIOTask *task,
799 gpointer user_data)
800{
801 Chardev *chr = user_data;
802 SocketChardev *s = user_data;
803
804 if (qio_task_propagate_error(task, NULL)) {
805 tcp_chr_disconnect(chr);
806 } else {
Julia Suvorova981b06e2018-10-19 01:35:00 +0300807 if (s->is_websock) {
808 tcp_chr_websock_init(chr);
809 } else if (s->do_telnetopt) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300810 tcp_chr_telnet_init(chr);
811 } else {
812 tcp_chr_connect(chr);
813 }
814 }
815}
816
817
818static void tcp_chr_tls_init(Chardev *chr)
819{
820 SocketChardev *s = SOCKET_CHARDEV(chr);
821 QIOChannelTLS *tioc;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300822 gchar *name;
823
824 if (s->is_listen) {
825 tioc = qio_channel_tls_new_server(
826 s->ioc, s->tls_creds,
Daniel P. Berrangefd4a5fd2019-03-08 15:21:50 +0000827 s->tls_authz,
Markus Armbruster9261ef52020-06-30 11:03:28 +0200828 NULL);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300829 } else {
830 tioc = qio_channel_tls_new_client(
831 s->ioc, s->tls_creds,
Markus Armbrusterbd269eb2017-04-26 09:36:41 +0200832 s->addr->u.inet.host,
Markus Armbruster9261ef52020-06-30 11:03:28 +0200833 NULL);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300834 }
835 if (tioc == NULL) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300836 tcp_chr_disconnect(chr);
837 return;
838 }
839 name = g_strdup_printf("chardev-tls-%s-%s",
840 s->is_listen ? "server" : "client",
841 chr->label);
842 qio_channel_set_name(QIO_CHANNEL(tioc), name);
843 g_free(name);
844 object_unref(OBJECT(s->ioc));
845 s->ioc = QIO_CHANNEL(tioc);
846
847 qio_channel_tls_handshake(tioc,
848 tcp_chr_tls_handshake,
849 chr,
Peter Xu1939ccd2018-03-05 14:43:24 +0800850 NULL,
Peter Xu05b6cc42018-03-06 13:33:19 +0800851 chr->gcontext);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300852}
853
854
855static void tcp_chr_set_client_ioc_name(Chardev *chr,
856 QIOChannelSocket *sioc)
857{
858 SocketChardev *s = SOCKET_CHARDEV(chr);
859 char *name;
860 name = g_strdup_printf("chardev-tcp-%s-%s",
861 s->is_listen ? "server" : "client",
862 chr->label);
863 qio_channel_set_name(QIO_CHANNEL(sioc), name);
864 g_free(name);
865
866}
867
868static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
869{
870 SocketChardev *s = SOCKET_CHARDEV(chr);
871
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000872 if (s->state != TCP_CHARDEV_STATE_CONNECTING) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300873 return -1;
874 }
875
876 s->ioc = QIO_CHANNEL(sioc);
877 object_ref(OBJECT(sioc));
878 s->sioc = sioc;
879 object_ref(OBJECT(sioc));
880
881 qio_channel_set_blocking(s->ioc, false, NULL);
882
883 if (s->do_nodelay) {
884 qio_channel_set_delay(s->ioc, false);
885 }
Daniel P. Berrange194b7f02017-12-18 13:54:17 +0000886 if (s->listener) {
Peter Xu3da9de52018-03-06 13:33:14 +0800887 qio_net_listener_set_client_func_full(s->listener, NULL, NULL,
888 NULL, chr->gcontext);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300889 }
890
891 if (s->tls_creds) {
892 tcp_chr_tls_init(chr);
Julia Suvorova981b06e2018-10-19 01:35:00 +0300893 } else if (s->is_websock) {
894 tcp_chr_websock_init(chr);
895 } else if (s->do_telnetopt) {
896 tcp_chr_telnet_init(chr);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300897 } else {
Julia Suvorova981b06e2018-10-19 01:35:00 +0300898 tcp_chr_connect(chr);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300899 }
900
901 return 0;
902}
903
904
905static int tcp_chr_add_client(Chardev *chr, int fd)
906{
907 int ret;
908 QIOChannelSocket *sioc;
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000909 SocketChardev *s = SOCKET_CHARDEV(chr);
910
911 if (s->state != TCP_CHARDEV_STATE_DISCONNECTED) {
912 return -1;
913 }
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300914
915 sioc = qio_channel_socket_new_fd(fd, NULL);
916 if (!sioc) {
917 return -1;
918 }
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000919 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300920 tcp_chr_set_client_ioc_name(chr, sioc);
921 ret = tcp_chr_new_client(chr, sioc);
922 object_unref(OBJECT(sioc));
923 return ret;
924}
925
Daniel P. Berrange194b7f02017-12-18 13:54:17 +0000926static void tcp_chr_accept(QIONetListener *listener,
927 QIOChannelSocket *cioc,
928 void *opaque)
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300929{
930 Chardev *chr = CHARDEV(opaque);
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000931 SocketChardev *s = SOCKET_CHARDEV(chr);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300932
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000933 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
Daniel P. Berrange194b7f02017-12-18 13:54:17 +0000934 tcp_chr_set_client_ioc_name(chr, cioc);
935 tcp_chr_new_client(chr, cioc);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300936}
937
Daniel P. Berrangéefae0b92019-02-11 18:24:35 +0000938
939static int tcp_chr_connect_client_sync(Chardev *chr, Error **errp)
940{
941 SocketChardev *s = SOCKET_CHARDEV(chr);
942 QIOChannelSocket *sioc = qio_channel_socket_new();
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000943 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
Daniel P. Berrangéefae0b92019-02-11 18:24:35 +0000944 tcp_chr_set_client_ioc_name(chr, sioc);
945 if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000946 tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
Daniel P. Berrangéefae0b92019-02-11 18:24:35 +0000947 object_unref(OBJECT(sioc));
948 return -1;
949 }
950 tcp_chr_new_client(chr, sioc);
951 object_unref(OBJECT(sioc));
952 return 0;
953}
954
955
956static void tcp_chr_accept_server_sync(Chardev *chr)
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300957{
958 SocketChardev *s = SOCKET_CHARDEV(chr);
959 QIOChannelSocket *sioc;
Daniel P. Berrangéefae0b92019-02-11 18:24:35 +0000960 info_report("QEMU waiting for connection on: %s",
961 chr->filename);
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +0000962 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
Daniel P. Berrangéefae0b92019-02-11 18:24:35 +0000963 sioc = qio_net_listener_wait_client(s->listener);
964 tcp_chr_set_client_ioc_name(chr, sioc);
965 tcp_chr_new_client(chr, sioc);
966 object_unref(OBJECT(sioc));
967}
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +0300968
Daniel P. Berrangéefae0b92019-02-11 18:24:35 +0000969
970static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
971{
972 SocketChardev *s = SOCKET_CHARDEV(chr);
Daniel P. Berrangéd1885e52019-02-11 18:24:39 +0000973 const char *opts[] = { "telnet", "tn3270", "websock", "tls-creds" };
974 bool optset[] = { s->is_telnet, s->is_tn3270, s->is_websock, s->tls_creds };
975 size_t i;
976
977 QEMU_BUILD_BUG_ON(G_N_ELEMENTS(opts) != G_N_ELEMENTS(optset));
978 for (i = 0; i < G_N_ELEMENTS(opts); i++) {
979 if (optset[i]) {
980 error_setg(errp,
981 "'%s' option is incompatible with waiting for "
982 "connection completion", opts[i]);
983 return -1;
984 }
985 }
986
Daniel P. Berrangé4b473732019-02-11 18:24:40 +0000987 tcp_chr_reconn_timer_cancel(s);
988
989 /*
990 * We expect states to be as follows:
991 *
992 * - server
993 * - wait -> CONNECTED
994 * - nowait -> DISCONNECTED
995 * - client
996 * - reconnect == 0 -> CONNECTED
997 * - reconnect != 0 -> CONNECTING
998 *
999 */
1000 if (s->state == TCP_CHARDEV_STATE_CONNECTING) {
1001 if (!s->connect_task) {
1002 error_setg(errp,
1003 "Unexpected 'connecting' state without connect task "
1004 "while waiting for connection completion");
1005 return -1;
1006 }
1007 /*
1008 * tcp_chr_wait_connected should only ever be run from the
1009 * main loop thread associated with chr->gcontext, otherwise
1010 * qio_task_wait_thread has a dangerous race condition with
1011 * free'ing of the s->connect_task object.
1012 *
1013 * Acquiring the main context doesn't 100% prove we're in
1014 * the main loop thread, but it does at least guarantee
1015 * that the main loop won't be executed by another thread
1016 * avoiding the race condition with the task idle callback.
1017 */
1018 g_main_context_acquire(chr->gcontext);
1019 qio_task_wait_thread(s->connect_task);
1020 g_main_context_release(chr->gcontext);
1021
1022 /*
1023 * The completion callback (qemu_chr_socket_connected) for
1024 * s->connect_task should have set this to NULL by the time
1025 * qio_task_wait_thread has returned.
1026 */
1027 assert(!s->connect_task);
1028
1029 /*
1030 * NB we are *not* guaranteed to have "s->state == ..CONNECTED"
1031 * at this point as this first connect may be failed, so
1032 * allow the next loop to run regardless.
1033 */
1034 }
1035
1036 while (s->state != TCP_CHARDEV_STATE_CONNECTED) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001037 if (s->is_listen) {
Daniel P. Berrangéefae0b92019-02-11 18:24:35 +00001038 tcp_chr_accept_server_sync(chr);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001039 } else {
Daniel P. Berrangé25d93b62019-02-11 18:24:38 +00001040 Error *err = NULL;
1041 if (tcp_chr_connect_client_sync(chr, &err) < 0) {
1042 if (s->reconnect_time) {
1043 error_free(err);
1044 g_usleep(s->reconnect_time * 1000ULL * 1000ULL);
1045 } else {
1046 error_propagate(errp, err);
1047 return -1;
1048 }
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001049 }
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001050 }
1051 }
1052
1053 return 0;
1054}
1055
1056static void char_socket_finalize(Object *obj)
1057{
1058 Chardev *chr = CHARDEV(obj);
1059 SocketChardev *s = SOCKET_CHARDEV(obj);
1060
1061 tcp_chr_free_connection(chr);
Peter Xu2c716ba2018-01-04 22:18:35 +08001062 tcp_chr_reconn_timer_cancel(s);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001063 qapi_free_SocketAddress(s->addr);
Peter Xuce1230c2018-03-06 13:33:15 +08001064 tcp_chr_telnet_destroy(s);
1065 g_free(s->telnet_init);
Daniel P. Berrange194b7f02017-12-18 13:54:17 +00001066 if (s->listener) {
Peter Xu3da9de52018-03-06 13:33:14 +08001067 qio_net_listener_set_client_func_full(s->listener, NULL, NULL,
1068 NULL, chr->gcontext);
Daniel P. Berrange194b7f02017-12-18 13:54:17 +00001069 object_unref(OBJECT(s->listener));
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001070 }
1071 if (s->tls_creds) {
1072 object_unref(OBJECT(s->tls_creds));
1073 }
Daniel P. Berrangefd4a5fd2019-03-08 15:21:50 +00001074 g_free(s->tls_authz);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001075
1076 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
1077}
1078
1079static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
1080{
1081 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
1082 Chardev *chr = CHARDEV(opaque);
1083 SocketChardev *s = SOCKET_CHARDEV(chr);
1084 Error *err = NULL;
1085
Daniel P. Berrangé4b473732019-02-11 18:24:40 +00001086 s->connect_task = NULL;
1087
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001088 if (qio_task_propagate_error(task, &err)) {
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +00001089 tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001090 check_report_connect_error(chr, err);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001091 goto cleanup;
1092 }
1093
1094 s->connect_err_reported = false;
1095 tcp_chr_new_client(chr, sioc);
1096
1097cleanup:
1098 object_unref(OBJECT(sioc));
1099}
1100
Daniel P. Berrangé4b473732019-02-11 18:24:40 +00001101
1102static void tcp_chr_connect_client_task(QIOTask *task,
1103 gpointer opaque)
1104{
1105 QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
1106 SocketAddress *addr = opaque;
1107 Error *err = NULL;
1108
1109 qio_channel_socket_connect_sync(ioc, addr, &err);
1110
1111 qio_task_set_error(task, err);
1112}
1113
1114
Daniel P. Berrangéefae0b92019-02-11 18:24:35 +00001115static void tcp_chr_connect_client_async(Chardev *chr)
Peter Xu3e7d4d22018-03-06 13:33:17 +08001116{
1117 SocketChardev *s = SOCKET_CHARDEV(chr);
1118 QIOChannelSocket *sioc;
1119
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +00001120 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
Peter Xu3e7d4d22018-03-06 13:33:17 +08001121 sioc = qio_channel_socket_new();
1122 tcp_chr_set_client_ioc_name(chr, sioc);
Daniel P. Berrangé4b473732019-02-11 18:24:40 +00001123 /*
1124 * Normally code would use the qio_channel_socket_connect_async
1125 * method which uses a QIOTask + qio_task_set_error internally
1126 * to avoid blocking. The tcp_chr_wait_connected method, however,
1127 * needs a way to synchronize with completion of the background
1128 * connect task which can't be done with the QIOChannelSocket
1129 * async APIs. Thus we must use QIOTask directly to implement
1130 * the non-blocking concept locally.
1131 */
1132 s->connect_task = qio_task_new(OBJECT(sioc),
1133 qemu_chr_socket_connected,
Marc-André Lureau68066012020-04-20 13:20:12 +02001134 object_ref(OBJECT(chr)),
1135 (GDestroyNotify)object_unref);
Daniel P. Berrangé4b473732019-02-11 18:24:40 +00001136 qio_task_run_in_thread(s->connect_task,
1137 tcp_chr_connect_client_task,
1138 s->addr,
1139 NULL,
1140 chr->gcontext);
Peter Xu3e7d4d22018-03-06 13:33:17 +08001141}
1142
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001143static gboolean socket_reconnect_timeout(gpointer opaque)
1144{
1145 Chardev *chr = CHARDEV(opaque);
1146 SocketChardev *s = SOCKET_CHARDEV(opaque);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001147
Alberto Garcia78d01592019-08-12 18:58:29 +03001148 qemu_mutex_lock(&chr->chr_write_lock);
Peter Xu2c716ba2018-01-04 22:18:35 +08001149 g_source_unref(s->reconnect_timer);
1150 s->reconnect_timer = NULL;
Alberto Garcia78d01592019-08-12 18:58:29 +03001151 qemu_mutex_unlock(&chr->chr_write_lock);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001152
1153 if (chr->be_open) {
1154 return false;
1155 }
1156
Daniel P. Berrangéefae0b92019-02-11 18:24:35 +00001157 tcp_chr_connect_client_async(chr);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001158
1159 return false;
1160}
1161
Daniel P. Berrangé16459842019-02-11 18:24:29 +00001162
Daniel P. Berrangéb5e18e52019-02-11 18:24:36 +00001163static int qmp_chardev_open_socket_server(Chardev *chr,
1164 bool is_telnet,
1165 bool is_waitconnect,
1166 Error **errp)
1167{
1168 SocketChardev *s = SOCKET_CHARDEV(chr);
1169 char *name;
1170 if (is_telnet) {
1171 s->do_telnetopt = 1;
1172 }
1173 s->listener = qio_net_listener_new();
1174
1175 name = g_strdup_printf("chardev-tcp-listener-%s", chr->label);
1176 qio_net_listener_set_name(s->listener, name);
1177 g_free(name);
1178
Juan Quintelafc8135c2019-08-19 18:08:21 +02001179 if (qio_net_listener_open_sync(s->listener, s->addr, 1, errp) < 0) {
Daniel P. Berrangéb5e18e52019-02-11 18:24:36 +00001180 object_unref(OBJECT(s->listener));
1181 s->listener = NULL;
1182 return -1;
1183 }
1184
1185 qapi_free_SocketAddress(s->addr);
1186 s->addr = socket_local_address(s->listener->sioc[0]->fd, errp);
1187 update_disconnected_filename(s);
1188
1189 if (is_waitconnect) {
1190 tcp_chr_accept_server_sync(chr);
1191 } else {
1192 qio_net_listener_set_client_func_full(s->listener,
1193 tcp_chr_accept,
1194 chr, NULL,
1195 chr->gcontext);
1196 }
1197
1198 return 0;
1199}
1200
1201
1202static int qmp_chardev_open_socket_client(Chardev *chr,
1203 int64_t reconnect,
1204 Error **errp)
1205{
1206 SocketChardev *s = SOCKET_CHARDEV(chr);
1207
1208 if (reconnect > 0) {
1209 s->reconnect_time = reconnect;
1210 tcp_chr_connect_client_async(chr);
1211 return 0;
1212 } else {
1213 return tcp_chr_connect_client_sync(chr, errp);
1214 }
1215}
1216
1217
Daniel P. Berrangé16459842019-02-11 18:24:29 +00001218static bool qmp_chardev_validate_socket(ChardevSocket *sock,
1219 SocketAddress *addr,
1220 Error **errp)
1221{
1222 /* Validate any options which have a dependency on address type */
1223 switch (addr->type) {
1224 case SOCKET_ADDRESS_TYPE_FD:
1225 if (sock->has_reconnect) {
1226 error_setg(errp,
1227 "'reconnect' option is incompatible with "
1228 "'fd' address type");
1229 return false;
1230 }
1231 if (sock->has_tls_creds &&
1232 !(sock->has_server && sock->server)) {
1233 error_setg(errp,
1234 "'tls_creds' option is incompatible with "
1235 "'fd' address type as client");
1236 return false;
1237 }
1238 break;
1239
1240 case SOCKET_ADDRESS_TYPE_UNIX:
1241 if (sock->has_tls_creds) {
1242 error_setg(errp,
1243 "'tls_creds' option is incompatible with "
1244 "'unix' address type");
1245 return false;
1246 }
1247 break;
1248
1249 case SOCKET_ADDRESS_TYPE_INET:
1250 break;
1251
1252 case SOCKET_ADDRESS_TYPE_VSOCK:
1253 if (sock->has_tls_creds) {
1254 error_setg(errp,
1255 "'tls_creds' option is incompatible with "
1256 "'vsock' address type");
1257 return false;
1258 }
1259
1260 default:
1261 break;
1262 }
1263
Daniel P. Berrangefd4a5fd2019-03-08 15:21:50 +00001264 if (sock->has_tls_authz && !sock->has_tls_creds) {
1265 error_setg(errp, "'tls_authz' option requires 'tls_creds' option");
1266 return false;
1267 }
1268
Daniel P. Berrangé16459842019-02-11 18:24:29 +00001269 /* Validate any options which have a dependancy on client vs server */
Daniel P. Berrangé4a0582f2019-02-11 18:24:30 +00001270 if (!sock->has_server || sock->server) {
1271 if (sock->has_reconnect) {
1272 error_setg(errp,
1273 "'reconnect' option is incompatible with "
1274 "socket in server listen mode");
1275 return false;
1276 }
1277 } else {
Daniel P. Berrangé16459842019-02-11 18:24:29 +00001278 if (sock->has_websocket && sock->websocket) {
1279 error_setg(errp, "%s", "Websocket client is not implemented");
1280 return false;
1281 }
Daniel P. Berrangé767abe72019-02-11 18:24:31 +00001282 if (sock->has_wait) {
Marc-André Lureaua9b305b2019-04-15 18:33:36 +02001283 warn_report("'wait' option is deprecated with "
1284 "socket in client connect mode");
1285 if (sock->wait) {
1286 error_setg(errp, "%s",
1287 "'wait' option is incompatible with "
1288 "socket in client connect mode");
1289 return false;
1290 }
Daniel P. Berrangé767abe72019-02-11 18:24:31 +00001291 }
Daniel P. Berrangé16459842019-02-11 18:24:29 +00001292 }
1293
1294 return true;
1295}
1296
1297
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001298static void qmp_chardev_open_socket(Chardev *chr,
1299 ChardevBackend *backend,
1300 bool *be_opened,
1301 Error **errp)
1302{
1303 SocketChardev *s = SOCKET_CHARDEV(chr);
1304 ChardevSocket *sock = backend->u.socket.data;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001305 bool do_nodelay = sock->has_nodelay ? sock->nodelay : false;
1306 bool is_listen = sock->has_server ? sock->server : true;
1307 bool is_telnet = sock->has_telnet ? sock->telnet : false;
Jing Liuae92cbd2016-09-23 08:06:11 +02001308 bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001309 bool is_waitconnect = sock->has_wait ? sock->wait : false;
Julia Suvorova981b06e2018-10-19 01:35:00 +03001310 bool is_websock = sock->has_websocket ? sock->websocket : false;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001311 int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
Markus Armbrusterbd269eb2017-04-26 09:36:41 +02001312 SocketAddress *addr;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001313
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001314 s->is_listen = is_listen;
1315 s->is_telnet = is_telnet;
Jing Liuae92cbd2016-09-23 08:06:11 +02001316 s->is_tn3270 = is_tn3270;
Julia Suvorova981b06e2018-10-19 01:35:00 +03001317 s->is_websock = is_websock;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001318 s->do_nodelay = do_nodelay;
1319 if (sock->tls_creds) {
1320 Object *creds;
1321 creds = object_resolve_path_component(
1322 object_get_objects_root(), sock->tls_creds);
1323 if (!creds) {
1324 error_setg(errp, "No TLS credentials with id '%s'",
1325 sock->tls_creds);
Daniel P. Berrangée154fd72019-02-11 18:24:34 +00001326 return;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001327 }
1328 s->tls_creds = (QCryptoTLSCreds *)
1329 object_dynamic_cast(creds,
1330 TYPE_QCRYPTO_TLS_CREDS);
1331 if (!s->tls_creds) {
1332 error_setg(errp, "Object with id '%s' is not TLS credentials",
1333 sock->tls_creds);
Daniel P. Berrangée154fd72019-02-11 18:24:34 +00001334 return;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001335 }
1336 object_ref(OBJECT(s->tls_creds));
1337 if (is_listen) {
1338 if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
1339 error_setg(errp, "%s",
1340 "Expected TLS credentials for server endpoint");
Daniel P. Berrangée154fd72019-02-11 18:24:34 +00001341 return;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001342 }
1343 } else {
1344 if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
1345 error_setg(errp, "%s",
1346 "Expected TLS credentials for client endpoint");
Daniel P. Berrangée154fd72019-02-11 18:24:34 +00001347 return;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001348 }
1349 }
1350 }
Daniel P. Berrangefd4a5fd2019-03-08 15:21:50 +00001351 s->tls_authz = g_strdup(sock->tls_authz);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001352
Markus Armbrusterbd269eb2017-04-26 09:36:41 +02001353 s->addr = addr = socket_address_flatten(sock->addr);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001354
Daniel P. Berrangé16459842019-02-11 18:24:29 +00001355 if (!qmp_chardev_validate_socket(sock, addr, errp)) {
Daniel P. Berrangée154fd72019-02-11 18:24:34 +00001356 return;
Marc-André Lureau4591bd42018-07-17 14:31:45 +02001357 }
Daniel P. Berrangé16459842019-02-11 18:24:29 +00001358
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001359 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
Markus Armbrusterca0b64e2017-03-30 19:43:09 +02001360 /* TODO SOCKET_ADDRESS_FD where fd has AF_UNIX */
Markus Armbrusterbd269eb2017-04-26 09:36:41 +02001361 if (addr->type == SOCKET_ADDRESS_TYPE_UNIX) {
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001362 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
1363 }
1364
1365 /* be isn't opened until we get a connection */
1366 *be_opened = false;
1367
Marc-André Lureaubbcde962016-12-20 15:32:31 +01001368 update_disconnected_filename(s);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001369
Daniel P. Berrangéb5e18e52019-02-11 18:24:36 +00001370 if (s->is_listen) {
1371 if (qmp_chardev_open_socket_server(chr, is_telnet || is_tn3270,
1372 is_waitconnect, errp) < 0) {
1373 return;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001374 }
Marc-André Lureau5573f982018-08-17 15:52:22 +02001375 } else {
Daniel P. Berrangéb5e18e52019-02-11 18:24:36 +00001376 if (qmp_chardev_open_socket_client(chr, reconnect, errp) < 0) {
Daniel P. Berrangée154fd72019-02-11 18:24:34 +00001377 return;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001378 }
1379 }
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001380}
1381
1382static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
1383 Error **errp)
1384{
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001385 const char *path = qemu_opt_get(opts, "path");
1386 const char *host = qemu_opt_get(opts, "host");
1387 const char *port = qemu_opt_get(opts, "port");
Daniel P. Berrange09357002017-12-21 12:57:54 +00001388 const char *fd = qemu_opt_get(opts, "fd");
xiaoqiang zhao776b97d2020-05-16 11:13:25 +08001389 bool tight = qemu_opt_get_bool(opts, "tight", true);
1390 bool abstract = qemu_opt_get_bool(opts, "abstract", false);
Markus Armbrusterdfd100f2017-04-26 09:36:39 +02001391 SocketAddressLegacy *addr;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001392 ChardevSocket *sock;
1393
Daniel P. Berrange09357002017-12-21 12:57:54 +00001394 if ((!!path + !!fd + !!host) != 1) {
Daniel P. Berrange9bb40602017-12-22 13:20:40 +00001395 error_setg(errp,
Daniel P. Berrange09357002017-12-21 12:57:54 +00001396 "Exactly one of 'path', 'fd' or 'host' required");
Daniel P. Berrange9bb40602017-12-22 13:20:40 +00001397 return;
1398 }
1399
Daniel P. Berrangé16459842019-02-11 18:24:29 +00001400 if (host && !port) {
1401 error_setg(errp, "chardev: socket: no port given");
1402 return;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001403 }
1404
Daniel P. Berrangé16459842019-02-11 18:24:29 +00001405 backend->type = CHARDEV_BACKEND_KIND_SOCKET;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001406 sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
1407 qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
1408
Daniel P. Berrangé5981c3a2019-02-11 18:24:32 +00001409 sock->has_nodelay = qemu_opt_get(opts, "delay");
1410 sock->nodelay = !qemu_opt_get_bool(opts, "delay", true);
1411 /*
1412 * We have different default to QMP for 'server', hence
1413 * we can't just check for existence of 'server'
1414 */
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001415 sock->has_server = true;
Daniel P. Berrangé5981c3a2019-02-11 18:24:32 +00001416 sock->server = qemu_opt_get_bool(opts, "server", false);
1417 sock->has_telnet = qemu_opt_get(opts, "telnet");
1418 sock->telnet = qemu_opt_get_bool(opts, "telnet", false);
1419 sock->has_tn3270 = qemu_opt_get(opts, "tn3270");
1420 sock->tn3270 = qemu_opt_get_bool(opts, "tn3270", false);
1421 sock->has_websocket = qemu_opt_get(opts, "websocket");
1422 sock->websocket = qemu_opt_get_bool(opts, "websocket", false);
Daniel P. Berrangé767abe72019-02-11 18:24:31 +00001423 /*
1424 * We have different default to QMP for 'wait' when 'server'
1425 * is set, hence we can't just check for existence of 'wait'
1426 */
Daniel P. Berrangé5981c3a2019-02-11 18:24:32 +00001427 sock->has_wait = qemu_opt_find(opts, "wait") || sock->server;
1428 sock->wait = qemu_opt_get_bool(opts, "wait", true);
Marc-André Lureau3b023752018-07-17 14:43:51 +02001429 sock->has_reconnect = qemu_opt_find(opts, "reconnect");
Daniel P. Berrangé5981c3a2019-02-11 18:24:32 +00001430 sock->reconnect = qemu_opt_get_number(opts, "reconnect", 0);
1431 sock->has_tls_creds = qemu_opt_get(opts, "tls-creds");
1432 sock->tls_creds = g_strdup(qemu_opt_get(opts, "tls-creds"));
Daniel P. Berrangefd4a5fd2019-03-08 15:21:50 +00001433 sock->has_tls_authz = qemu_opt_get(opts, "tls-authz");
1434 sock->tls_authz = g_strdup(qemu_opt_get(opts, "tls-authz"));
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001435
Markus Armbrusterdfd100f2017-04-26 09:36:39 +02001436 addr = g_new0(SocketAddressLegacy, 1);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001437 if (path) {
1438 UnixSocketAddress *q_unix;
Markus Armbrusterdfd100f2017-04-26 09:36:39 +02001439 addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001440 q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
1441 q_unix->path = g_strdup(path);
xiaoqiang zhao776b97d2020-05-16 11:13:25 +08001442 q_unix->tight = tight;
1443 q_unix->abstract = abstract;
Daniel P. Berrange9bb40602017-12-22 13:20:40 +00001444 } else if (host) {
Markus Armbrusterdfd100f2017-04-26 09:36:39 +02001445 addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001446 addr->u.inet.data = g_new(InetSocketAddress, 1);
1447 *addr->u.inet.data = (InetSocketAddress) {
1448 .host = g_strdup(host),
1449 .port = g_strdup(port),
1450 .has_to = qemu_opt_get(opts, "to"),
1451 .to = qemu_opt_get_number(opts, "to", 0),
1452 .has_ipv4 = qemu_opt_get(opts, "ipv4"),
1453 .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
1454 .has_ipv6 = qemu_opt_get(opts, "ipv6"),
1455 .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
1456 };
Daniel P. Berrange09357002017-12-21 12:57:54 +00001457 } else if (fd) {
1458 addr->type = SOCKET_ADDRESS_LEGACY_KIND_FD;
1459 addr->u.fd.data = g_new(String, 1);
1460 addr->u.fd.data->str = g_strdup(fd);
Daniel P. Berrange9bb40602017-12-22 13:20:40 +00001461 } else {
1462 g_assert_not_reached();
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001463 }
1464 sock->addr = addr;
1465}
1466
Marc-André Lureau123676e2016-12-21 12:26:38 +01001467static void
1468char_socket_get_addr(Object *obj, Visitor *v, const char *name,
1469 void *opaque, Error **errp)
1470{
1471 SocketChardev *s = SOCKET_CHARDEV(obj);
1472
1473 visit_type_SocketAddress(v, name, &s->addr, errp);
1474}
1475
Marc-André Lureauda2d19b2016-12-21 15:43:46 +01001476static bool
1477char_socket_get_connected(Object *obj, Error **errp)
1478{
1479 SocketChardev *s = SOCKET_CHARDEV(obj);
1480
Daniel P. Berrangé32423cc2019-02-11 18:24:37 +00001481 return s->state == TCP_CHARDEV_STATE_CONNECTED;
Marc-André Lureauda2d19b2016-12-21 15:43:46 +01001482}
1483
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001484static void char_socket_class_init(ObjectClass *oc, void *data)
1485{
1486 ChardevClass *cc = CHARDEV_CLASS(oc);
1487
1488 cc->parse = qemu_chr_parse_socket;
1489 cc->open = qmp_chardev_open_socket;
1490 cc->chr_wait_connected = tcp_chr_wait_connected;
1491 cc->chr_write = tcp_chr_write;
1492 cc->chr_sync_read = tcp_chr_sync_read;
1493 cc->chr_disconnect = tcp_chr_disconnect;
1494 cc->get_msgfds = tcp_get_msgfds;
1495 cc->set_msgfds = tcp_set_msgfds;
1496 cc->chr_add_client = tcp_chr_add_client;
1497 cc->chr_add_watch = tcp_chr_add_watch;
1498 cc->chr_update_read_handler = tcp_chr_update_read_handler;
Marc-André Lureau123676e2016-12-21 12:26:38 +01001499
1500 object_class_property_add(oc, "addr", "SocketAddress",
1501 char_socket_get_addr, NULL,
Markus Armbrusterd2623122020-05-05 17:29:22 +02001502 NULL, NULL);
Marc-André Lureauda2d19b2016-12-21 15:43:46 +01001503
1504 object_class_property_add_bool(oc, "connected", char_socket_get_connected,
Markus Armbrusterd2623122020-05-05 17:29:22 +02001505 NULL);
Marc-André Lureaud24ca4b2016-12-12 18:41:00 +03001506}
1507
1508static const TypeInfo char_socket_type_info = {
1509 .name = TYPE_CHARDEV_SOCKET,
1510 .parent = TYPE_CHARDEV,
1511 .instance_size = sizeof(SocketChardev),
1512 .instance_finalize = char_socket_finalize,
1513 .class_init = char_socket_class_init,
1514};
1515
1516static void register_types(void)
1517{
1518 type_register_static(&char_socket_type_info);
1519}
1520
1521type_init(register_types);