1 /*
2 * admin_remote.c
3 *
4 * Copyright (C) 2015 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22 #include <rpc/rpc.h>
23 #include "virtypedparam.h"
24 #include "admin_protocol.h"
25
26 typedef struct _remoteAdminPriv remoteAdminPriv;
27 struct _remoteAdminPriv {
28 virObjectLockable parent;
29
30 int counter;
31 virNetClient *client;
32 virNetClientProgram *program;
33 };
34
35 static virClass *remoteAdminPrivClass;
36
37 static void
remoteAdminPrivDispose(void * opaque)38 remoteAdminPrivDispose(void *opaque)
39 {
40 remoteAdminPriv *priv = opaque;
41
42 virObjectUnref(priv->program);
43 virObjectUnref(priv->client);
44 }
45
46
47 /* Helpers */
48 static virAdmServerPtr
get_nonnull_server(virAdmConnectPtr conn,admin_nonnull_server server)49 get_nonnull_server(virAdmConnectPtr conn, admin_nonnull_server server)
50 {
51 return virAdmGetServer(conn, server.name);
52 }
53
54 static virAdmClientPtr
get_nonnull_client(virAdmServerPtr srv,admin_nonnull_client client)55 get_nonnull_client(virAdmServerPtr srv, admin_nonnull_client client)
56 {
57 return virAdmGetClient(srv, client.id, client.timestamp, client.transport);
58 }
59
60 static void
make_nonnull_server(admin_nonnull_server * srv_dst,virAdmServerPtr srv_src)61 make_nonnull_server(admin_nonnull_server *srv_dst, virAdmServerPtr srv_src)
62 {
63 srv_dst->name = srv_src->name;
64 }
65
66 static void
make_nonnull_client(admin_nonnull_client * client_dst,virAdmClientPtr client_src)67 make_nonnull_client(admin_nonnull_client *client_dst,
68 virAdmClientPtr client_src)
69 {
70 client_dst->id = client_src->id;
71 client_dst->transport = client_src->transport;
72 client_dst->timestamp = client_src->timestamp;
73 make_nonnull_server(&client_dst->srv, client_src->srv);
74 }
75
76 static int
callFull(virAdmConnectPtr conn G_GNUC_UNUSED,remoteAdminPriv * priv,int * fdin,size_t fdinlen,int ** fdout,size_t * fdoutlen,int proc_nr,xdrproc_t args_filter,char * args,xdrproc_t ret_filter,char * ret)77 callFull(virAdmConnectPtr conn G_GNUC_UNUSED,
78 remoteAdminPriv *priv,
79 int *fdin,
80 size_t fdinlen,
81 int **fdout,
82 size_t *fdoutlen,
83 int proc_nr,
84 xdrproc_t args_filter, char *args,
85 xdrproc_t ret_filter, char *ret)
86 {
87 int rv;
88 virNetClientProgram *prog = priv->program;
89 int counter = priv->counter++;
90 virNetClient *client = priv->client;
91
92 /* Unlock, so that if we get any async events/stream data
93 * while processing the RPC, we don't deadlock when our
94 * callbacks for those are invoked
95 */
96 virObjectRef(priv);
97 virObjectUnlock(priv);
98
99 rv = virNetClientProgramCall(prog,
100 client,
101 counter,
102 proc_nr,
103 fdinlen, fdin,
104 fdoutlen, fdout,
105 args_filter, args,
106 ret_filter, ret);
107
108 virObjectLock(priv);
109 virObjectUnref(priv);
110
111 return rv;
112 }
113
114 static int
call(virAdmConnectPtr conn,unsigned int flags,int proc_nr,xdrproc_t args_filter,char * args,xdrproc_t ret_filter,char * ret)115 call(virAdmConnectPtr conn,
116 unsigned int flags,
117 int proc_nr,
118 xdrproc_t args_filter, char *args,
119 xdrproc_t ret_filter, char *ret)
120 {
121 virCheckFlags(0, -1);
122
123 return callFull(conn, conn->privateData,
124 NULL, 0, NULL, NULL, proc_nr,
125 args_filter, args, ret_filter, ret);
126 }
127
128 #include "admin_client.h"
129
130 static void
remoteAdminClientCloseFunc(virNetClient * client G_GNUC_UNUSED,int reason,void * opaque)131 remoteAdminClientCloseFunc(virNetClient *client G_GNUC_UNUSED,
132 int reason,
133 void *opaque)
134 {
135 virAdmConnectCloseCallbackData *cbdata = opaque;
136
137 virObjectLock(cbdata);
138
139 if (cbdata->callback) {
140 VIR_DEBUG("Triggering connection close callback %p reason=%d, opaque=%p",
141 cbdata->callback, reason, cbdata->opaque);
142 cbdata->callback(cbdata->conn, reason, cbdata->opaque);
143 virAdmConnectCloseCallbackDataReset(cbdata);
144 }
145 virObjectUnlock(cbdata);
146 }
147
148 static int
remoteAdminConnectOpen(virAdmConnectPtr conn,unsigned int flags)149 remoteAdminConnectOpen(virAdmConnectPtr conn, unsigned int flags)
150 {
151 int rv = -1;
152 remoteAdminPriv *priv = conn->privateData;
153 admin_connect_open_args args;
154
155 virObjectLock(priv);
156
157 args.flags = flags & ~VIR_CONNECT_NO_ALIASES;
158
159 if (virNetClientRegisterAsyncIO(priv->client) < 0) {
160 VIR_DEBUG("Failed to add event watch, disabling events and support for"
161 " keepalive messages");
162 virResetLastError();
163 }
164
165 virObjectRef(conn->closeCallback);
166 virNetClientSetCloseCallback(priv->client, remoteAdminClientCloseFunc,
167 conn->closeCallback,
168 virObjectFreeCallback);
169
170 if (call(conn, 0, ADMIN_PROC_CONNECT_OPEN,
171 (xdrproc_t)xdr_admin_connect_open_args, (char *)&args,
172 (xdrproc_t)xdr_void, (char *)NULL) == -1) {
173 goto done;
174 }
175
176 rv = 0;
177
178 done:
179 virObjectUnlock(priv);
180 return rv;
181 }
182
183 static int
remoteAdminConnectClose(virAdmConnectPtr conn)184 remoteAdminConnectClose(virAdmConnectPtr conn)
185 {
186 int rv = -1;
187 remoteAdminPriv *priv = conn->privateData;
188
189 virObjectLock(priv);
190
191 if (call(conn, 0, ADMIN_PROC_CONNECT_CLOSE,
192 (xdrproc_t)xdr_void, (char *)NULL,
193 (xdrproc_t)xdr_void, (char *)NULL) == -1) {
194 goto done;
195 }
196
197 virNetClientSetCloseCallback(priv->client, NULL, conn->closeCallback,
198 virObjectFreeCallback);
199 virNetClientClose(priv->client);
200
201 rv = 0;
202
203 done:
204 virObjectUnlock(priv);
205 return rv;
206 }
207
208 static void
remoteAdminPrivFree(void * opaque)209 remoteAdminPrivFree(void *opaque)
210 {
211 virAdmConnectPtr conn = opaque;
212
213 remoteAdminConnectClose(conn);
214 virObjectUnref(conn->privateData);
215 }
216
217 static remoteAdminPriv *
remoteAdminPrivNew(const char * sock_path)218 remoteAdminPrivNew(const char *sock_path)
219 {
220 remoteAdminPriv *priv = NULL;
221
222 if (!(priv = virObjectLockableNew(remoteAdminPrivClass)))
223 goto error;
224
225 if (!(priv->client = virNetClientNewUNIX(sock_path, NULL)))
226 goto error;
227
228 if (!(priv->program = virNetClientProgramNew(ADMIN_PROGRAM,
229 ADMIN_PROTOCOL_VERSION,
230 NULL, 0, NULL)))
231 goto error;
232
233 if (virNetClientAddProgram(priv->client, priv->program) < 0)
234 goto error;
235
236 return priv;
237 error:
238 virObjectUnref(priv);
239 return NULL;
240 }
241
242 static int
remoteAdminServerGetThreadPoolParameters(virAdmServerPtr srv,virTypedParameterPtr * params,int * nparams,unsigned int flags)243 remoteAdminServerGetThreadPoolParameters(virAdmServerPtr srv,
244 virTypedParameterPtr *params,
245 int *nparams,
246 unsigned int flags)
247 {
248 int rv = -1;
249 remoteAdminPriv *priv = srv->conn->privateData;
250 admin_server_get_threadpool_parameters_args args;
251 admin_server_get_threadpool_parameters_ret ret;
252
253 args.flags = flags;
254 make_nonnull_server(&args.srv, srv);
255
256 memset(&ret, 0, sizeof(ret));
257 virObjectLock(priv);
258
259 if (call(srv->conn, 0, ADMIN_PROC_SERVER_GET_THREADPOOL_PARAMETERS,
260 (xdrproc_t)xdr_admin_server_get_threadpool_parameters_args, (char *) &args,
261 (xdrproc_t)xdr_admin_server_get_threadpool_parameters_ret, (char *) &ret) == -1)
262 goto cleanup;
263
264 if (virTypedParamsDeserialize((struct _virTypedParameterRemote *) ret.params.params_val,
265 ret.params.params_len,
266 ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX,
267 params,
268 nparams) < 0)
269 goto cleanup;
270
271 rv = 0;
272 xdr_free((xdrproc_t)xdr_admin_server_get_threadpool_parameters_ret, (char *) &ret);
273
274 cleanup:
275 virObjectUnlock(priv);
276 return rv;
277 }
278
279 static int
remoteAdminServerSetThreadPoolParameters(virAdmServerPtr srv,virTypedParameterPtr params,int nparams,unsigned int flags)280 remoteAdminServerSetThreadPoolParameters(virAdmServerPtr srv,
281 virTypedParameterPtr params,
282 int nparams,
283 unsigned int flags)
284 {
285 int rv = -1;
286 remoteAdminPriv *priv = srv->conn->privateData;
287 admin_server_set_threadpool_parameters_args args;
288
289 args.flags = flags;
290 make_nonnull_server(&args.srv, srv);
291
292 virObjectLock(priv);
293
294 if (virTypedParamsSerialize(params, nparams,
295 ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX,
296 (struct _virTypedParameterRemote **) &args.params.params_val,
297 &args.params.params_len,
298 0) < 0)
299 goto cleanup;
300
301
302 if (call(srv->conn, 0, ADMIN_PROC_SERVER_SET_THREADPOOL_PARAMETERS,
303 (xdrproc_t)xdr_admin_server_set_threadpool_parameters_args, (char *) &args,
304 (xdrproc_t)xdr_void, (char *) NULL) == -1)
305 goto cleanup;
306
307 rv = 0;
308 cleanup:
309 virTypedParamsRemoteFree((struct _virTypedParameterRemote *) args.params.params_val,
310 args.params.params_len);
311 virObjectUnlock(priv);
312 return rv;
313 }
314
315 static int
remoteAdminClientGetInfo(virAdmClientPtr client,virTypedParameterPtr * params,int * nparams,unsigned int flags)316 remoteAdminClientGetInfo(virAdmClientPtr client,
317 virTypedParameterPtr *params,
318 int *nparams,
319 unsigned int flags)
320 {
321 int rv = -1;
322 remoteAdminPriv *priv = client->srv->conn->privateData;
323 admin_client_get_info_args args;
324 admin_client_get_info_ret ret;
325
326 args.flags = flags;
327 make_nonnull_client(&args.clnt, client);
328
329 memset(&ret, 0, sizeof(ret));
330 virObjectLock(priv);
331
332 if (call(client->srv->conn, 0, ADMIN_PROC_CLIENT_GET_INFO,
333 (xdrproc_t)xdr_admin_client_get_info_args, (char *) &args,
334 (xdrproc_t)xdr_admin_client_get_info_ret, (char *) &ret) == -1)
335 goto cleanup;
336
337 if (virTypedParamsDeserialize((struct _virTypedParameterRemote *) ret.params.params_val,
338 ret.params.params_len,
339 ADMIN_CLIENT_INFO_PARAMETERS_MAX,
340 params,
341 nparams) < 0)
342 goto cleanup;
343
344 rv = 0;
345 xdr_free((xdrproc_t)xdr_admin_client_get_info_ret, (char *) &ret);
346
347 cleanup:
348 virObjectUnlock(priv);
349 return rv;
350 }
351
352 static int
remoteAdminServerGetClientLimits(virAdmServerPtr srv,virTypedParameterPtr * params,int * nparams,unsigned int flags)353 remoteAdminServerGetClientLimits(virAdmServerPtr srv,
354 virTypedParameterPtr *params,
355 int *nparams,
356 unsigned int flags)
357 {
358 int rv = -1;
359 admin_server_get_client_limits_args args;
360 admin_server_get_client_limits_ret ret;
361 remoteAdminPriv *priv = srv->conn->privateData;
362 args.flags = flags;
363 make_nonnull_server(&args.srv, srv);
364
365 memset(&ret, 0, sizeof(ret));
366 virObjectLock(priv);
367
368 if (call(srv->conn, 0, ADMIN_PROC_SERVER_GET_CLIENT_LIMITS,
369 (xdrproc_t) xdr_admin_server_get_client_limits_args,
370 (char *) &args,
371 (xdrproc_t) xdr_admin_server_get_client_limits_ret,
372 (char *) &ret) == -1)
373 goto cleanup;
374
375 if (virTypedParamsDeserialize((struct _virTypedParameterRemote *) ret.params.params_val,
376 ret.params.params_len,
377 ADMIN_SERVER_CLIENT_LIMITS_MAX,
378 params,
379 nparams) < 0)
380 goto cleanup;
381
382 rv = 0;
383 xdr_free((xdrproc_t) xdr_admin_server_get_client_limits_ret,
384 (char *) &ret);
385
386 cleanup:
387 virObjectUnlock(priv);
388 return rv;
389 }
390
391 static int
remoteAdminServerSetClientLimits(virAdmServerPtr srv,virTypedParameterPtr params,int nparams,unsigned int flags)392 remoteAdminServerSetClientLimits(virAdmServerPtr srv,
393 virTypedParameterPtr params,
394 int nparams,
395 unsigned int flags)
396 {
397 int rv = -1;
398 admin_server_set_client_limits_args args;
399 remoteAdminPriv *priv = srv->conn->privateData;
400
401 args.flags = flags;
402 make_nonnull_server(&args.srv, srv);
403
404 virObjectLock(priv);
405
406 if (virTypedParamsSerialize(params, nparams,
407 ADMIN_SERVER_CLIENT_LIMITS_MAX,
408 (struct _virTypedParameterRemote **) &args.params.params_val,
409 &args.params.params_len,
410 0) < 0)
411 goto cleanup;
412
413 if (call(srv->conn, 0, ADMIN_PROC_SERVER_SET_CLIENT_LIMITS,
414 (xdrproc_t) xdr_admin_server_set_client_limits_args,
415 (char *) &args,
416 (xdrproc_t) xdr_void, (char *) NULL) == -1)
417 goto cleanup;
418
419 rv = 0;
420 cleanup:
421 virTypedParamsRemoteFree((struct _virTypedParameterRemote *) args.params.params_val,
422 args.params.params_len);
423 virObjectUnlock(priv);
424 return rv;
425 }
426
427 static int
remoteAdminConnectGetLoggingOutputs(virAdmConnectPtr conn,char ** outputs,unsigned int flags)428 remoteAdminConnectGetLoggingOutputs(virAdmConnectPtr conn,
429 char **outputs,
430 unsigned int flags)
431 {
432 int rv = -1;
433 remoteAdminPriv *priv = conn->privateData;
434 admin_connect_get_logging_outputs_args args;
435 admin_connect_get_logging_outputs_ret ret;
436
437 args.flags = flags;
438
439 memset(&ret, 0, sizeof(ret));
440 virObjectLock(priv);
441
442 if (call(conn,
443 0,
444 ADMIN_PROC_CONNECT_GET_LOGGING_OUTPUTS,
445 (xdrproc_t) xdr_admin_connect_get_logging_outputs_args,
446 (char *) &args,
447 (xdrproc_t) xdr_admin_connect_get_logging_outputs_ret,
448 (char *) &ret) == -1)
449 goto done;
450
451 if (outputs)
452 *outputs = g_steal_pointer(&ret.outputs);
453
454 rv = ret.noutputs;
455 xdr_free((xdrproc_t) xdr_admin_connect_get_logging_outputs_ret, (char *) &ret);
456
457 done:
458 virObjectUnlock(priv);
459 return rv;
460 }
461
462 static int
remoteAdminConnectGetLoggingFilters(virAdmConnectPtr conn,char ** filters,unsigned int flags)463 remoteAdminConnectGetLoggingFilters(virAdmConnectPtr conn,
464 char **filters,
465 unsigned int flags)
466 {
467 int rv = -1;
468 remoteAdminPriv *priv = conn->privateData;
469 admin_connect_get_logging_filters_args args;
470 admin_connect_get_logging_filters_ret ret;
471
472 args.flags = flags;
473
474 memset(&ret, 0, sizeof(ret));
475 virObjectLock(priv);
476
477 if (call(conn,
478 0,
479 ADMIN_PROC_CONNECT_GET_LOGGING_FILTERS,
480 (xdrproc_t) xdr_admin_connect_get_logging_filters_args,
481 (char *) &args,
482 (xdrproc_t) xdr_admin_connect_get_logging_filters_ret,
483 (char *) &ret) == -1)
484 goto done;
485
486 if (filters)
487 *filters = ret.filters ? *ret.filters : NULL;
488
489 rv = ret.nfilters;
490 VIR_FREE(ret.filters);
491
492 done:
493 virObjectUnlock(priv);
494 return rv;
495 }
496