* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "qemu-common.h"
#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
#include "qemu/base64.h"
#include "io/channel-socket.h"
#include "io/channel-file.h"
+#include "io/channel-tls.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-#include <errno.h>
-#include <sys/time.h>
#include <zlib.h>
#ifndef _WIN32
#include <netdb.h>
#include <sys/select.h>
#ifdef CONFIG_BSD
-#include <sys/stat.h>
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <dev/ppbus/ppi.h>
#include <dev/ppbus/ppbconf.h>
#include <linux/parport.h>
#endif
#ifdef __sun__
-#include <sys/stat.h>
#include <sys/ethernet.h>
#include <sys/sockio.h>
#include <netinet/arp.h>
Error **errp)
{
CharDriverState *chr;
- ChardevCommon *common = qapi_ChardevDummy_base(backend->u.null);
+ ChardevCommon *common = backend->u.null;
chr = qemu_chr_alloc(common, errp);
if (!chr) {
ChardevMux *mux = backend->u.mux;
CharDriverState *chr, *drv;
MuxDriver *d;
- ChardevCommon *common = qapi_ChardevMux_base(backend->u.mux);
+ ChardevCommon *common = qapi_ChardevMux_base(mux);
drv = qemu_chr_find(mux->chardev);
if (drv == NULL) {
ioc, &iov, 1,
fds, nfds, NULL);
if (ret == QIO_CHANNEL_ERR_BLOCK) {
- errno = EAGAIN;
- return -1;
- } else if (ret < 0) {
if (offset) {
return offset;
}
+ errno = EAGAIN;
+ return -1;
+ } else if (ret < 0) {
errno = EINVAL;
return -1;
}
char *filename_in;
char *filename_out;
const char *filename = opts->device;
- ChardevCommon *common = qapi_ChardevHostdev_base(backend->u.pipe);
+ ChardevCommon *common = qapi_ChardevHostdev_base(opts);
filename_in = g_strdup_printf("%s.in", filename);
ChardevStdio *opts = backend->u.stdio;
CharDriverState *chr;
struct sigaction act;
- ChardevCommon *common = qapi_ChardevStdio_base(backend->u.stdio);
+ ChardevCommon *common = qapi_ChardevStdio_base(opts);
if (is_daemonized()) {
error_setg(errp, "cannot use stdio with -daemonize");
PtyCharDriver *s;
int master_fd, slave_fd;
char pty_name[PATH_MAX];
- ChardevCommon *common = qapi_ChardevDummy_base(backend->u.pty);
+ ChardevCommon *common = backend->u.pty;
master_fd = qemu_openpty_raw(&slave_fd, pty_name);
if (master_fd < 0) {
return NULL;
}
- drv = g_new0(ParallelCharDriver, 1);
- drv->fd = fd;
- drv->mode = IEEE1284_MODE_COMPAT;
-
chr = qemu_chr_alloc(backend, errp);
if (!chr) {
return NULL;
}
+
+ drv = g_new0(ParallelCharDriver, 1);
+ chr->opaque = drv;
chr->chr_write = null_chr_write;
chr->chr_ioctl = pp_ioctl;
chr->chr_close = pp_close;
- chr->opaque = drv;
+
+ drv->fd = fd;
+ drv->mode = IEEE1284_MODE_COMPAT;
return chr;
}
}
static CharDriverState *qemu_chr_open_pp_fd(int fd,
- ChardevBackend *backend,
+ ChardevCommon *backend,
Error **errp)
{
CharDriverState *chr;
- chr = qemu_chr_alloc(common, errp);
+ chr = qemu_chr_alloc(backend, errp);
if (!chr) {
return NULL;
}
const char *filename = opts->device;
CharDriverState *chr;
WinCharState *s;
- ChardevCommon *common = qapi_ChardevHostdev_base(backend->u.pipe);
+ ChardevCommon *common = qapi_ChardevHostdev_base(opts);
chr = qemu_chr_alloc(common, errp);
if (!chr) {
ChardevReturn *ret,
Error **errp)
{
- ChardevCommon *common = qapi_ChardevDummy_base(backend->u.console);
+ ChardevCommon *common = backend->u.console;
return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE),
common, errp);
}
/* TCP Net console */
typedef struct {
- QIOChannel *ioc;
+ QIOChannel *ioc; /* Client I/O channel */
+ QIOChannelSocket *sioc; /* Client master channel */
QIOChannelSocket *listen_ioc;
guint listen_tag;
+ QCryptoTLSCreds *tls_creds;
int connected;
int max_size;
int do_telnetopt;
QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
}
remove_fd_in_watch(chr);
+ object_unref(OBJECT(s->sioc));
+ s->sioc = NULL;
object_unref(OBJECT(s->ioc));
s->ioc = NULL;
g_free(chr->filename);
return size;
}
-#ifndef _WIN32
-CharDriverState *qemu_chr_open_eventfd(int eventfd)
-{
- CharDriverState *chr = qemu_chr_open_fd(eventfd, eventfd, NULL, NULL);
-
- if (chr) {
- chr->avail_connections = 1;
- }
-
- return chr;
-}
-#endif
-
static void tcp_chr_connect(void *opaque)
{
CharDriverState *chr = opaque;
TCPCharDriver *s = chr->opaque;
- QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(s->ioc);
g_free(chr->filename);
- chr->filename = sockaddr_to_str(&sioc->localAddr, sioc->localAddrLen,
- &sioc->remoteAddr, sioc->remoteAddrLen,
- s->is_listen, s->is_telnet);
+ chr->filename = sockaddr_to_str(
+ &s->sioc->localAddr, s->sioc->localAddrLen,
+ &s->sioc->remoteAddr, s->sioc->remoteAddrLen,
+ s->is_listen, s->is_telnet);
s->connected = 1;
if (s->ioc) {
{
TCPCharDriver *s = chr->opaque;
+ if (!s->connected) {
+ return;
+ }
+
remove_fd_in_watch(chr);
if (s->ioc) {
chr->fd_in_tag = io_add_watch_poll(s->ioc,
init, NULL);
}
+
+static void tcp_chr_tls_handshake(Object *source,
+ Error *err,
+ gpointer user_data)
+{
+ CharDriverState *chr = user_data;
+ TCPCharDriver *s = chr->opaque;
+
+ if (err) {
+ tcp_chr_disconnect(chr);
+ } else {
+ if (s->do_telnetopt) {
+ tcp_chr_telnet_init(chr);
+ } else {
+ tcp_chr_connect(chr);
+ }
+ }
+}
+
+
+static void tcp_chr_tls_init(CharDriverState *chr)
+{
+ TCPCharDriver *s = chr->opaque;
+ QIOChannelTLS *tioc;
+ Error *err = NULL;
+
+ if (s->is_listen) {
+ tioc = qio_channel_tls_new_server(
+ s->ioc, s->tls_creds,
+ NULL, /* XXX Use an ACL */
+ &err);
+ } else {
+ tioc = qio_channel_tls_new_client(
+ s->ioc, s->tls_creds,
+ s->addr->u.inet->host,
+ &err);
+ }
+ if (tioc == NULL) {
+ error_free(err);
+ tcp_chr_disconnect(chr);
+ }
+ object_unref(OBJECT(s->ioc));
+ s->ioc = QIO_CHANNEL(tioc);
+
+ qio_channel_tls_handshake(tioc,
+ tcp_chr_tls_handshake,
+ chr,
+ NULL);
+}
+
+
static int tcp_chr_new_client(CharDriverState *chr, QIOChannelSocket *sioc)
{
TCPCharDriver *s = chr->opaque;
s->ioc = QIO_CHANNEL(sioc);
object_ref(OBJECT(sioc));
+ s->sioc = sioc;
+ object_ref(OBJECT(sioc));
if (s->do_nodelay) {
qio_channel_set_delay(s->ioc, false);
s->listen_tag = 0;
}
- if (s->do_telnetopt) {
- tcp_chr_telnet_init(chr);
+ if (s->tls_creds) {
+ tcp_chr_tls_init(chr);
} else {
- tcp_chr_connect(chr);
+ if (s->do_telnetopt) {
+ tcp_chr_telnet_init(chr);
+ } else {
+ tcp_chr_connect(chr);
+ }
}
return 0;
}
g_free(s->read_msgfds);
}
+ if (s->tls_creds) {
+ object_unref(OBJECT(s->tls_creds));
+ }
if (s->write_msgfds_num) {
g_free(s->write_msgfds);
}
Error **errp)
{
ChardevRingbuf *opts = backend->u.ringbuf;
- ChardevCommon *common = qapi_ChardevRingbuf_base(backend->u.ringbuf);
+ ChardevCommon *common = qapi_ChardevRingbuf_base(opts);
CharDriverState *chr;
RingBufCharDriver *d;
return NULL;
}
-static void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
+void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
{
const char *logfile = qemu_opt_get(opts, "logfile");
Error **errp)
{
const char *path = qemu_opt_get(opts, "path");
+ ChardevFile *file;
if (path == NULL) {
error_setg(errp, "chardev: file: no filename given");
return;
}
- backend->u.file = g_new0(ChardevFile, 1);
- qemu_chr_parse_common(opts, qapi_ChardevFile_base(backend->u.file));
- backend->u.file->out = g_strdup(path);
+ file = backend->u.file = g_new0(ChardevFile, 1);
+ qemu_chr_parse_common(opts, qapi_ChardevFile_base(file));
+ file->out = g_strdup(path);
- backend->u.file->has_append = true;
- backend->u.file->append = qemu_opt_get_bool(opts, "append", false);
+ file->has_append = true;
+ file->append = qemu_opt_get_bool(opts, "append", false);
}
static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
Error **errp)
{
- backend->u.stdio = g_new0(ChardevStdio, 1);
- qemu_chr_parse_common(opts, qapi_ChardevStdio_base(backend->u.stdio));
- backend->u.stdio->has_signal = true;
- backend->u.stdio->signal = qemu_opt_get_bool(opts, "signal", true);
+ ChardevStdio *stdio;
+
+ stdio = backend->u.stdio = g_new0(ChardevStdio, 1);
+ qemu_chr_parse_common(opts, qapi_ChardevStdio_base(stdio));
+ stdio->has_signal = true;
+ stdio->signal = qemu_opt_get_bool(opts, "signal", true);
}
#ifdef HAVE_CHARDEV_SERIAL
Error **errp)
{
const char *device = qemu_opt_get(opts, "path");
+ ChardevHostdev *serial;
if (device == NULL) {
error_setg(errp, "chardev: serial/tty: no device path given");
return;
}
- backend->u.serial = g_new0(ChardevHostdev, 1);
- qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(backend->u.serial));
- backend->u.serial->device = g_strdup(device);
+ serial = backend->u.serial = g_new0(ChardevHostdev, 1);
+ qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial));
+ serial->device = g_strdup(device);
}
#endif
Error **errp)
{
const char *device = qemu_opt_get(opts, "path");
+ ChardevHostdev *parallel;
if (device == NULL) {
error_setg(errp, "chardev: parallel: no device path given");
return;
}
- backend->u.parallel = g_new0(ChardevHostdev, 1);
- qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(backend->u.parallel));
- backend->u.parallel->device = g_strdup(device);
+ parallel = backend->u.parallel = g_new0(ChardevHostdev, 1);
+ qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel));
+ parallel->device = g_strdup(device);
}
#endif
Error **errp)
{
const char *device = qemu_opt_get(opts, "path");
+ ChardevHostdev *dev;
if (device == NULL) {
error_setg(errp, "chardev: pipe: no device path given");
return;
}
- backend->u.pipe = g_new0(ChardevHostdev, 1);
- qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(backend->u.pipe));
- backend->u.pipe->device = g_strdup(device);
+ dev = backend->u.pipe = g_new0(ChardevHostdev, 1);
+ qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev));
+ dev->device = g_strdup(device);
}
static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
Error **errp)
{
int val;
+ ChardevRingbuf *ringbuf;
- backend->u.ringbuf = g_new0(ChardevRingbuf, 1);
- qemu_chr_parse_common(opts, qapi_ChardevRingbuf_base(backend->u.ringbuf));
+ ringbuf = backend->u.ringbuf = g_new0(ChardevRingbuf, 1);
+ qemu_chr_parse_common(opts, qapi_ChardevRingbuf_base(ringbuf));
val = qemu_opt_get_size(opts, "size", 0);
if (val != 0) {
- backend->u.ringbuf->has_size = true;
- backend->u.ringbuf->size = val;
+ ringbuf->has_size = true;
+ ringbuf->size = val;
}
}
Error **errp)
{
const char *chardev = qemu_opt_get(opts, "chardev");
+ ChardevMux *mux;
if (chardev == NULL) {
error_setg(errp, "chardev: mux: no chardev given");
return;
}
- backend->u.mux = g_new0(ChardevMux, 1);
- qemu_chr_parse_common(opts, qapi_ChardevMux_base(backend->u.mux));
- backend->u.mux->chardev = g_strdup(chardev);
+ mux = backend->u.mux = g_new0(ChardevMux, 1);
+ qemu_chr_parse_common(opts, qapi_ChardevMux_base(mux));
+ mux->chardev = g_strdup(chardev);
}
static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
const char *path = qemu_opt_get(opts, "path");
const char *host = qemu_opt_get(opts, "host");
const char *port = qemu_opt_get(opts, "port");
+ const char *tls_creds = qemu_opt_get(opts, "tls-creds");
SocketAddress *addr;
+ ChardevSocket *sock;
if (!path) {
if (!host) {
error_setg(errp, "chardev: socket: no port given");
return;
}
+ } else {
+ if (tls_creds) {
+ error_setg(errp, "TLS can only be used over TCP socket");
+ return;
+ }
}
- backend->u.socket = g_new0(ChardevSocket, 1);
- qemu_chr_parse_common(opts, qapi_ChardevSocket_base(backend->u.socket));
+ sock = backend->u.socket = g_new0(ChardevSocket, 1);
+ qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
- backend->u.socket->has_nodelay = true;
- backend->u.socket->nodelay = do_nodelay;
- backend->u.socket->has_server = true;
- backend->u.socket->server = is_listen;
- backend->u.socket->has_telnet = true;
- backend->u.socket->telnet = is_telnet;
- backend->u.socket->has_wait = true;
- backend->u.socket->wait = is_waitconnect;
- backend->u.socket->has_reconnect = true;
- backend->u.socket->reconnect = reconnect;
+ sock->has_nodelay = true;
+ sock->nodelay = do_nodelay;
+ sock->has_server = true;
+ sock->server = is_listen;
+ sock->has_telnet = true;
+ sock->telnet = is_telnet;
+ sock->has_wait = true;
+ sock->wait = is_waitconnect;
+ sock->has_reconnect = true;
+ sock->reconnect = reconnect;
+ sock->tls_creds = g_strdup(tls_creds);
addr = g_new0(SocketAddress, 1);
if (path) {
+ UnixSocketAddress *q_unix;
addr->type = SOCKET_ADDRESS_KIND_UNIX;
- addr->u.q_unix = g_new0(UnixSocketAddress, 1);
- addr->u.q_unix->path = g_strdup(path);
+ q_unix = addr->u.q_unix = g_new0(UnixSocketAddress, 1);
+ q_unix->path = g_strdup(path);
} else {
addr->type = SOCKET_ADDRESS_KIND_INET;
- addr->u.inet = g_new0(InetSocketAddress, 1);
- addr->u.inet->host = g_strdup(host);
- addr->u.inet->port = g_strdup(port);
- addr->u.inet->has_to = qemu_opt_get(opts, "to");
- addr->u.inet->to = qemu_opt_get_number(opts, "to", 0);
- addr->u.inet->has_ipv4 = qemu_opt_get(opts, "ipv4");
- addr->u.inet->ipv4 = qemu_opt_get_bool(opts, "ipv4", 0);
- addr->u.inet->has_ipv6 = qemu_opt_get(opts, "ipv6");
- addr->u.inet->ipv6 = qemu_opt_get_bool(opts, "ipv6", 0);
+ addr->u.inet = g_new(InetSocketAddress, 1);
+ *addr->u.inet = (InetSocketAddress) {
+ .host = g_strdup(host),
+ .port = g_strdup(port),
+ .has_to = qemu_opt_get(opts, "to"),
+ .to = qemu_opt_get_number(opts, "to", 0),
+ .has_ipv4 = qemu_opt_get(opts, "ipv4"),
+ .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
+ .has_ipv6 = qemu_opt_get(opts, "ipv6"),
+ .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
+ };
}
- backend->u.socket->addr = addr;
+ sock->addr = addr;
}
static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
const char *localport = qemu_opt_get(opts, "localport");
bool has_local = false;
SocketAddress *addr;
+ ChardevUdp *udp;
if (host == NULL || strlen(host) == 0) {
host = "localhost";
has_local = true;
}
- backend->u.udp = g_new0(ChardevUdp, 1);
- qemu_chr_parse_common(opts, qapi_ChardevUdp_base(backend->u.udp));
+ udp = backend->u.udp = g_new0(ChardevUdp, 1);
+ qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp));
addr = g_new0(SocketAddress, 1);
addr->type = SOCKET_ADDRESS_KIND_INET;
- addr->u.inet = g_new0(InetSocketAddress, 1);
- addr->u.inet->host = g_strdup(host);
- addr->u.inet->port = g_strdup(port);
- addr->u.inet->has_ipv4 = qemu_opt_get(opts, "ipv4");
- addr->u.inet->ipv4 = qemu_opt_get_bool(opts, "ipv4", 0);
- addr->u.inet->has_ipv6 = qemu_opt_get(opts, "ipv6");
- addr->u.inet->ipv6 = qemu_opt_get_bool(opts, "ipv6", 0);
- backend->u.udp->remote = addr;
+ addr->u.inet = g_new(InetSocketAddress, 1);
+ *addr->u.inet = (InetSocketAddress) {
+ .host = g_strdup(host),
+ .port = g_strdup(port),
+ .has_ipv4 = qemu_opt_get(opts, "ipv4"),
+ .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
+ .has_ipv6 = qemu_opt_get(opts, "ipv6"),
+ .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
+ };
+ udp->remote = addr;
if (has_local) {
- backend->u.udp->has_local = true;
+ udp->has_local = true;
addr = g_new0(SocketAddress, 1);
addr->type = SOCKET_ADDRESS_KIND_INET;
- addr->u.inet = g_new0(InetSocketAddress, 1);
- addr->u.inet->host = g_strdup(localaddr);
- addr->u.inet->port = g_strdup(localport);
- backend->u.udp->local = addr;
+ addr->u.inet = g_new(InetSocketAddress, 1);
+ *addr->u.inet = (InetSocketAddress) {
+ .host = g_strdup(localaddr),
+ .port = g_strdup(localport),
+ };
+ udp->local = addr;
}
}
} else {
ChardevCommon *cc = g_new0(ChardevCommon, 1);
qemu_chr_parse_common(opts, cc);
- backend->u.data = cc;
+ backend->u.null = cc; /* Any ChardevCommon member would work */
}
ret = qmp_chardev_add(bid ? bid : id, backend, errp);
},{
.name = "telnet",
.type = QEMU_OPT_BOOL,
+ },{
+ .name = "tls-creds",
+ .type = QEMU_OPT_STRING,
},{
.name = "width",
.type = QEMU_OPT_NUMBER,
Error **errp)
{
ChardevFile *file = backend->u.file;
- ChardevCommon *common = qapi_ChardevFile_base(backend->u.file);
+ ChardevCommon *common = qapi_ChardevFile_base(file);
HANDLE out;
if (file->has_in) {
Error **errp)
{
ChardevHostdev *serial = backend->u.serial;
- ChardevCommon *common = qapi_ChardevHostdev_base(backend->u.serial);
+ ChardevCommon *common = qapi_ChardevHostdev_base(serial);
return qemu_chr_open_win_path(serial->device, common, errp);
}
Error **errp)
{
ChardevFile *file = backend->u.file;
- ChardevCommon *common = qapi_ChardevFile_base(backend->u.file);
+ ChardevCommon *common = qapi_ChardevFile_base(file);
int flags, in = -1, out;
flags = O_WRONLY | O_CREAT | O_BINARY;
Error **errp)
{
ChardevHostdev *serial = backend->u.serial;
- ChardevCommon *common = qapi_ChardevHostdev_base(backend->u.serial);
+ ChardevCommon *common = qapi_ChardevHostdev_base(serial);
int fd;
fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
Error **errp)
{
ChardevHostdev *parallel = backend->u.parallel;
- ChardevCommon *common = qapi_ChardevHostdev_base(backend->u.parallel);
+ ChardevCommon *common = qapi_ChardevHostdev_base(parallel);
int fd;
fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
bool is_telnet = sock->has_telnet ? sock->telnet : false;
bool is_waitconnect = sock->has_wait ? sock->wait : false;
int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
- ChardevCommon *common = qapi_ChardevSocket_base(backend->u.socket);
+ ChardevCommon *common = qapi_ChardevSocket_base(sock);
chr = qemu_chr_alloc(common, errp);
if (!chr) {
s->is_listen = is_listen;
s->is_telnet = is_telnet;
s->do_nodelay = do_nodelay;
+ if (sock->tls_creds) {
+ Object *creds;
+ creds = object_resolve_path_component(
+ object_get_objects_root(), sock->tls_creds);
+ if (!creds) {
+ error_setg(errp, "No TLS credentials with id '%s'",
+ sock->tls_creds);
+ goto error;
+ }
+ s->tls_creds = (QCryptoTLSCreds *)
+ object_dynamic_cast(creds,
+ TYPE_QCRYPTO_TLS_CREDS);
+ if (!s->tls_creds) {
+ error_setg(errp, "Object with id '%s' is not TLS credentials",
+ sock->tls_creds);
+ goto error;
+ }
+ object_ref(OBJECT(s->tls_creds));
+ if (is_listen) {
+ if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ error_setg(errp, "%s",
+ "Expected TLS credentials for server endpoint");
+ goto error;
+ }
+ } else {
+ if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
+ error_setg(errp, "%s",
+ "Expected TLS credentials for client endpoint");
+ goto error;
+ }
+ }
+ }
+
qapi_copy_SocketAddress(&s->addr, sock->addr);
chr->opaque = s;
if (s->reconnect_time) {
socket_try_connect(chr);
} else if (!qemu_chr_open_socket_fd(chr, errp)) {
- g_free(s);
- qemu_chr_free_common(chr);
- return NULL;
+ goto error;
}
if (is_listen && is_waitconnect) {
}
return chr;
+
+ error:
+ if (s->tls_creds) {
+ object_unref(OBJECT(s->tls_creds));
+ }
+ g_free(s);
+ qemu_chr_free_common(chr);
+ return NULL;
}
static CharDriverState *qmp_chardev_open_udp(const char *id,
Error **errp)
{
ChardevUdp *udp = backend->u.udp;
- ChardevCommon *common = qapi_ChardevUdp_base(backend->u.udp);
+ ChardevCommon *common = qapi_ChardevUdp_base(udp);
QIOChannelSocket *sioc = qio_channel_socket_new();
if (qio_channel_socket_dgram_sync(sioc,
- udp->remote, udp->local,
+ udp->local, udp->remote,
errp) < 0) {
object_unref(OBJECT(sioc));
return NULL;