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