1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include "qemu/osdep.h"
18
19#include "qemu-common.h"
20#include "qemu/error-report.h"
21#include "qapi/error.h"
22#include "channel.h"
23#include "socket.h"
24#include "migration.h"
25#include "qemu-file.h"
26#include "io/channel-socket.h"
27#include "trace.h"
28
29
30static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
31{
32 SocketAddress *saddr;
33
34 saddr = g_new0(SocketAddress, 1);
35 saddr->type = SOCKET_ADDRESS_TYPE_INET;
36
37 if (inet_parse(&saddr->u.inet, host_port, errp)) {
38 qapi_free_SocketAddress(saddr);
39 return NULL;
40 }
41
42 return saddr;
43}
44
45
46static SocketAddress *unix_build_address(const char *path)
47{
48 SocketAddress *saddr;
49
50 saddr = g_new0(SocketAddress, 1);
51 saddr->type = SOCKET_ADDRESS_TYPE_UNIX;
52 saddr->u.q_unix.path = g_strdup(path);
53
54 return saddr;
55}
56
57
58struct SocketConnectData {
59 MigrationState *s;
60 char *hostname;
61};
62
63static void socket_connect_data_free(void *opaque)
64{
65 struct SocketConnectData *data = opaque;
66 if (!data) {
67 return;
68 }
69 g_free(data->hostname);
70 g_free(data);
71}
72
73static void socket_outgoing_migration(QIOTask *task,
74 gpointer opaque)
75{
76 struct SocketConnectData *data = opaque;
77 QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task));
78 Error *err = NULL;
79
80 if (qio_task_propagate_error(task, &err)) {
81 trace_migration_socket_outgoing_error(error_get_pretty(err));
82 migrate_fd_error(data->s, err);
83 error_free(err);
84 } else {
85 trace_migration_socket_outgoing_connected(data->hostname);
86 migration_channel_connect(data->s, sioc, data->hostname);
87 }
88 object_unref(OBJECT(sioc));
89}
90
91static void socket_start_outgoing_migration(MigrationState *s,
92 SocketAddress *saddr,
93 Error **errp)
94{
95 QIOChannelSocket *sioc = qio_channel_socket_new();
96 struct SocketConnectData *data = g_new0(struct SocketConnectData, 1);
97
98 data->s = s;
99 if (saddr->type == SOCKET_ADDRESS_TYPE_INET) {
100 data->hostname = g_strdup(saddr->u.inet.host);
101 }
102
103 qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-outgoing");
104 qio_channel_socket_connect_async(sioc,
105 saddr,
106 socket_outgoing_migration,
107 data,
108 socket_connect_data_free);
109 qapi_free_SocketAddress(saddr);
110}
111
112void tcp_start_outgoing_migration(MigrationState *s,
113 const char *host_port,
114 Error **errp)
115{
116 Error *err = NULL;
117 SocketAddress *saddr = tcp_build_address(host_port, &err);
118 if (!err) {
119 socket_start_outgoing_migration(s, saddr, &err);
120 }
121 error_propagate(errp, err);
122}
123
124void unix_start_outgoing_migration(MigrationState *s,
125 const char *path,
126 Error **errp)
127{
128 SocketAddress *saddr = unix_build_address(path);
129 socket_start_outgoing_migration(s, saddr, errp);
130}
131
132
133static gboolean socket_accept_incoming_migration(QIOChannel *ioc,
134 GIOCondition condition,
135 gpointer opaque)
136{
137 QIOChannelSocket *sioc;
138 Error *err = NULL;
139
140 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
141 &err);
142 if (!sioc) {
143 error_report("could not accept migration connection (%s)",
144 error_get_pretty(err));
145 goto out;
146 }
147
148 trace_migration_socket_incoming_accepted();
149
150 qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-incoming");
151 migration_channel_process_incoming(QIO_CHANNEL(sioc));
152 object_unref(OBJECT(sioc));
153
154out:
155 if (migration_has_all_channels()) {
156
157 qio_channel_close(ioc, NULL);
158 return G_SOURCE_REMOVE;
159 } else {
160 return G_SOURCE_CONTINUE;
161 }
162}
163
164
165static void socket_start_incoming_migration(SocketAddress *saddr,
166 Error **errp)
167{
168 QIOChannelSocket *listen_ioc = qio_channel_socket_new();
169
170 qio_channel_set_name(QIO_CHANNEL(listen_ioc),
171 "migration-socket-listener");
172
173 if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {
174 object_unref(OBJECT(listen_ioc));
175 qapi_free_SocketAddress(saddr);
176 return;
177 }
178
179 qio_channel_add_watch(QIO_CHANNEL(listen_ioc),
180 G_IO_IN,
181 socket_accept_incoming_migration,
182 listen_ioc,
183 (GDestroyNotify)object_unref);
184 qapi_free_SocketAddress(saddr);
185}
186
187void tcp_start_incoming_migration(const char *host_port, Error **errp)
188{
189 Error *err = NULL;
190 SocketAddress *saddr = tcp_build_address(host_port, &err);
191 if (!err) {
192 socket_start_incoming_migration(saddr, &err);
193 }
194 error_propagate(errp, err);
195}
196
197void unix_start_incoming_migration(const char *path, Error **errp)
198{
199 SocketAddress *saddr = unix_build_address(path);
200 socket_start_incoming_migration(saddr, errp);
201}
202