qemuxmlconftest: Add test case for virtiofs on s390 using 'ccw' addresses
[libvirt.git] / src / rpc / virnetserverprogram.c
blobb1236bf49b0460838188e5b0943a7d768879d088
1 /*
2 * virnetserverprogram.c: generic network RPC server program
4 * Copyright (C) 2006-2012 Red Hat, Inc.
5 * Copyright (C) 2006 Daniel P. Berrange
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <http://www.gnu.org/licenses/>.
22 #include <config.h>
24 #include "virnetserverprogram.h"
25 #include "virnetserverclient.h"
27 #include "viralloc.h"
28 #include "virerror.h"
29 #include "virlog.h"
30 #include "virfile.h"
31 #include "virthread.h"
33 #define VIR_FROM_THIS VIR_FROM_RPC
35 VIR_LOG_INIT("rpc.netserverprogram");
37 struct _virNetServerProgram {
38 virObject parent;
40 unsigned program;
41 unsigned version;
42 virNetServerProgramProc *procs;
43 size_t nprocs;
47 static virClass *virNetServerProgramClass;
48 static void virNetServerProgramDispose(void *obj);
50 static int virNetServerProgramOnceInit(void)
52 if (!VIR_CLASS_NEW(virNetServerProgram, virClassForObject()))
53 return -1;
55 return 0;
58 VIR_ONCE_GLOBAL_INIT(virNetServerProgram);
61 virNetServerProgram *virNetServerProgramNew(unsigned program,
62 unsigned version,
63 virNetServerProgramProc *procs,
64 size_t nprocs)
66 virNetServerProgram *prog;
68 if (virNetServerProgramInitialize() < 0)
69 return NULL;
71 if (!(prog = virObjectNew(virNetServerProgramClass)))
72 return NULL;
74 prog->program = program;
75 prog->version = version;
76 prog->procs = procs;
77 prog->nprocs = nprocs;
79 VIR_DEBUG("prog=%p", prog);
81 return prog;
85 int virNetServerProgramGetID(virNetServerProgram *prog)
87 return prog->program;
91 int virNetServerProgramGetVersion(virNetServerProgram *prog)
93 return prog->version;
97 int virNetServerProgramMatches(virNetServerProgram *prog,
98 virNetMessage *msg)
100 if (prog->program == msg->header.prog &&
101 prog->version == msg->header.vers)
102 return 1;
103 return 0;
107 static virNetServerProgramProc *virNetServerProgramGetProc(virNetServerProgram *prog,
108 int procedure)
110 virNetServerProgramProc *proc;
112 if (procedure < 0)
113 return NULL;
114 if (procedure >= prog->nprocs)
115 return NULL;
117 proc = &prog->procs[procedure];
119 if (!proc->func)
120 return NULL;
122 return proc;
125 unsigned int
126 virNetServerProgramGetPriority(virNetServerProgram *prog,
127 int procedure)
129 virNetServerProgramProc *proc = virNetServerProgramGetProc(prog, procedure);
131 if (!proc)
132 return 0;
134 return proc->priority;
137 static int
138 virNetServerProgramSendError(unsigned program,
139 unsigned version,
140 virNetServerClient *client,
141 virNetMessage *msg,
142 struct virNetMessageError *rerr,
143 int procedure,
144 int type,
145 unsigned int serial)
147 VIR_DEBUG("prog=%d ver=%d proc=%d type=%d serial=%u msg=%p rerr=%p",
148 program, version, procedure, type, serial, msg, rerr);
150 virNetMessageSaveError(rerr);
152 /* Return header. */
153 msg->header.prog = program;
154 msg->header.vers = version;
155 msg->header.proc = procedure;
156 msg->header.type = type;
157 msg->header.serial = serial;
158 msg->header.status = VIR_NET_ERROR;
160 if (virNetMessageEncodeHeader(msg) < 0)
161 goto error;
163 if (virNetMessageEncodePayload(msg, (xdrproc_t)xdr_virNetMessageError, rerr) < 0)
164 goto error;
165 xdr_free((xdrproc_t)xdr_virNetMessageError, (void*)rerr);
167 /* Put reply on end of tx queue to send out */
168 if (virNetServerClientSendMessage(client, msg) < 0)
169 return -1;
171 return 0;
173 error:
174 VIR_WARN("Failed to serialize remote error '%p'", rerr);
175 xdr_free((xdrproc_t)xdr_virNetMessageError, (void*)rerr);
176 return -1;
181 * @client: the client to send the error to
182 * @req: the message this error is in reply to
184 * Send an error message to the client
186 * Returns 0 if the error was sent, -1 upon fatal error
189 virNetServerProgramSendReplyError(virNetServerProgram *prog,
190 virNetServerClient *client,
191 virNetMessage *msg,
192 struct virNetMessageError *rerr,
193 struct virNetMessageHeader *req)
196 * For data streams, errors are sent back as data streams
197 * For method calls, errors are sent back as method replies
199 return virNetServerProgramSendError(prog->program,
200 prog->version,
201 client,
202 msg,
203 rerr,
204 req->proc,
205 req->type == VIR_NET_STREAM ? VIR_NET_STREAM : VIR_NET_REPLY,
206 req->serial);
210 int virNetServerProgramSendStreamError(virNetServerProgram *prog,
211 virNetServerClient *client,
212 virNetMessage *msg,
213 struct virNetMessageError *rerr,
214 int procedure,
215 unsigned int serial)
217 return virNetServerProgramSendError(prog->program,
218 prog->version,
219 client,
220 msg,
221 rerr,
222 procedure,
223 VIR_NET_STREAM,
224 serial);
228 int virNetServerProgramUnknownError(virNetServerClient *client,
229 virNetMessage *msg,
230 struct virNetMessageHeader *req)
232 virNetMessageError rerr = { 0 };
234 virReportError(VIR_ERR_RPC,
235 _("Cannot find program %1$d version %2$d"), req->prog, req->vers);
237 return virNetServerProgramSendError(req->prog,
238 req->vers,
239 client,
240 msg,
241 &rerr,
242 req->proc,
243 VIR_NET_REPLY,
244 req->serial);
248 static int
249 virNetServerProgramDispatchCall(virNetServerProgram *prog,
250 virNetServer *server,
251 virNetServerClient *client,
252 virNetMessage *msg);
255 * @server: the unlocked server object
256 * @client: the unlocked client object
257 * @msg: the complete incoming message packet, with header already decoded
259 * This function is intended to be called from worker threads
260 * when an incoming message is ready to be dispatched for
261 * execution.
263 * Upon successful return the '@msg' instance will be released
264 * by this function (or more often, reused to send a reply).
265 * Upon failure, the '@msg' must be freed by the caller.
267 * Returns 0 if the message was dispatched, -1 upon fatal error
269 int virNetServerProgramDispatch(virNetServerProgram *prog,
270 virNetServer *server,
271 virNetServerClient *client,
272 virNetMessage *msg)
274 int ret = -1;
275 virNetMessageError rerr = { 0 };
277 VIR_DEBUG("prog=%d ver=%d type=%d status=%d serial=%u proc=%d",
278 msg->header.prog, msg->header.vers, msg->header.type,
279 msg->header.status, msg->header.serial, msg->header.proc);
281 /* Check version, etc. */
282 if (msg->header.prog != prog->program) {
283 virReportError(VIR_ERR_RPC,
284 _("program mismatch (actual %1$x, expected %2$x)"),
285 msg->header.prog, prog->program);
286 goto error;
289 if (msg->header.vers != prog->version) {
290 virReportError(VIR_ERR_RPC,
291 _("version mismatch (actual %1$x, expected %2$x)"),
292 msg->header.vers, prog->version);
293 goto error;
296 switch (msg->header.type) {
297 case VIR_NET_CALL:
298 case VIR_NET_CALL_WITH_FDS:
299 ret = virNetServerProgramDispatchCall(prog, server, client, msg);
300 break;
302 case VIR_NET_STREAM:
303 /* Since stream data is non-acked, async, we may continue to receive
304 * stream packets after we closed down a stream. Just drop & ignore
305 * these.
307 VIR_INFO("Ignoring unexpected stream data serial=%u proc=%d status=%d",
308 msg->header.serial, msg->header.proc, msg->header.status);
309 /* Send a dummy reply to free up 'msg' & unblock client rx */
310 virNetMessageClear(msg);
311 msg->header.type = VIR_NET_REPLY;
312 if (virNetServerClientSendMessage(client, msg) < 0)
313 return -1;
314 ret = 0;
315 break;
317 case VIR_NET_REPLY:
318 case VIR_NET_REPLY_WITH_FDS:
319 case VIR_NET_MESSAGE:
320 case VIR_NET_STREAM_HOLE:
321 default:
322 virReportError(VIR_ERR_RPC,
323 _("Unexpected message type %1$u"),
324 msg->header.type);
325 goto error;
328 return ret;
330 error:
331 if (msg->header.type == VIR_NET_CALL ||
332 msg->header.type == VIR_NET_CALL_WITH_FDS) {
333 ret = virNetServerProgramSendReplyError(prog, client, msg, &rerr, &msg->header);
334 } else {
335 /* Send a dummy reply to free up 'msg' & unblock client rx */
336 virNetMessageClear(msg);
337 msg->header.type = VIR_NET_REPLY;
338 if (virNetServerClientSendMessage(client, msg) < 0)
339 return -1;
340 ret = 0;
343 return ret;
348 * @server: the unlocked server object
349 * @client: the unlocked client object
350 * @msg: the complete incoming method call, with header already decoded
352 * This method is used to dispatch a message representing an
353 * incoming method call from a client. It decodes the payload
354 * to obtain method call arguments, invokes the method and
355 * then sends a reply packet with the return values
357 * Returns 0 if the reply was sent, or -1 upon fatal error
359 static int
360 virNetServerProgramDispatchCall(virNetServerProgram *prog,
361 virNetServer *server,
362 virNetServerClient *client,
363 virNetMessage *msg)
365 g_autofree char *arg = NULL;
366 g_autofree char *ret = NULL;
367 int rv = -1;
368 virNetServerProgramProc *dispatcher = NULL;
369 virNetMessageError rerr = { 0 };
370 size_t i;
371 g_autoptr(virIdentity) identity = NULL;
373 if (msg->header.status != VIR_NET_OK) {
374 virReportError(VIR_ERR_RPC,
375 _("Unexpected message status %1$u"),
376 msg->header.status);
377 goto error;
380 dispatcher = virNetServerProgramGetProc(prog, msg->header.proc);
382 if (!dispatcher) {
383 virReportError(VIR_ERR_RPC,
384 _("unknown procedure: %1$d"),
385 msg->header.proc);
386 goto error;
389 /* If the client is not authenticated, don't allow any RPC ops
390 * which are except for authentication ones */
391 if (dispatcher->needAuth &&
392 !virNetServerClientIsAuthenticated(client)) {
393 /* Explicitly *NOT* calling remoteDispatchAuthError() because
394 we want back-compatibility with libvirt clients which don't
395 support the VIR_ERR_AUTH_FAILED error code */
396 virReportError(VIR_ERR_RPC,
397 "%s", _("authentication required"));
398 goto error;
401 arg = g_new0(char, dispatcher->arg_len);
402 ret = g_new0(char, dispatcher->ret_len);
404 if (virNetMessageDecodePayload(msg, dispatcher->arg_filter, arg) < 0)
405 goto error;
407 if (!(identity = virNetServerClientGetIdentity(client)))
408 goto error;
410 if (virIdentitySetCurrent(identity) < 0)
411 goto error;
414 * When the RPC handler is called:
416 * - Server object is unlocked
417 * - Client object is unlocked
419 * Without locking, it is safe to use:
421 * 'args and 'ret'
423 rv = (dispatcher->func)(server, client, msg, &rerr, arg, ret);
425 if (virIdentitySetCurrent(NULL) < 0)
426 goto error;
429 * If rv == 1, this indicates the dispatch func has
430 * populated 'msg' with a list of FDs to return to
431 * the caller.
433 * Otherwise we must clear out the FDs we got from
434 * the client originally.
437 if (rv != 1) {
438 for (i = 0; i < msg->nfds; i++)
439 VIR_FORCE_CLOSE(msg->fds[i]);
440 VIR_FREE(msg->fds);
441 msg->nfds = 0;
444 if (rv < 0)
445 goto error;
447 /* Return header. We're re-using same message object, so
448 * only need to tweak type/status fields */
449 /*msg->header.prog = msg->header.prog;*/
450 /*msg->header.vers = msg->header.vers;*/
451 /*msg->header.proc = msg->header.proc;*/
452 msg->header.type = msg->nfds ? VIR_NET_REPLY_WITH_FDS : VIR_NET_REPLY;
453 /*msg->header.serial = msg->header.serial;*/
454 msg->header.status = VIR_NET_OK;
456 if (virNetMessageEncodeHeader(msg) < 0)
457 goto error;
459 if (msg->nfds &&
460 virNetMessageEncodeNumFDs(msg) < 0)
461 goto error;
463 if (virNetMessageEncodePayload(msg, dispatcher->ret_filter, ret) < 0)
464 goto error;
466 xdr_free(dispatcher->arg_filter, arg);
467 xdr_free(dispatcher->ret_filter, ret);
469 /* Put reply on end of tx queue to send out */
470 return virNetServerClientSendMessage(client, msg);
472 error:
473 if (arg)
474 xdr_free(dispatcher->arg_filter, arg);
475 if (ret)
476 xdr_free(dispatcher->ret_filter, ret);
478 /* Bad stuff (de-)serializing message, but we have an
479 * RPC error message we can send back to the client */
480 rv = virNetServerProgramSendReplyError(prog, client, msg, &rerr, &msg->header);
482 return rv;
486 int virNetServerProgramSendStreamData(virNetServerProgram *prog,
487 virNetServerClient *client,
488 virNetMessage *msg,
489 int procedure,
490 unsigned int serial,
491 const char *data,
492 size_t len)
494 VIR_DEBUG("client=%p msg=%p data=%p len=%zu", client, msg, data, len);
496 /* Return header. We're reusing same message object, so
497 * only need to tweak type/status fields */
498 msg->header.prog = prog->program;
499 msg->header.vers = prog->version;
500 msg->header.proc = procedure;
501 msg->header.type = VIR_NET_STREAM;
502 msg->header.serial = serial;
504 * NB
505 * data != NULL + len > 0 => VIR_NET_CONTINUE (Sending back data)
506 * data != NULL + len == 0 => VIR_NET_CONTINUE (Sending read EOF)
507 * data == NULL => VIR_NET_OK (Sending finish handshake confirmation)
509 msg->header.status = data ? VIR_NET_CONTINUE : VIR_NET_OK;
511 if (virNetMessageEncodeHeader(msg) < 0)
512 return -1;
514 if (virNetMessageEncodePayloadRaw(msg, data, len) < 0)
515 return -1;
517 VIR_DEBUG("Total %zu", msg->bufferLength);
519 return virNetServerClientSendMessage(client, msg);
523 int virNetServerProgramSendStreamHole(virNetServerProgram *prog,
524 virNetServerClient *client,
525 virNetMessage *msg,
526 int procedure,
527 unsigned int serial,
528 long long length,
529 unsigned int flags)
531 virNetStreamHole data = { 0 };
533 VIR_DEBUG("client=%p msg=%p length=%lld", client, msg, length);
535 data.length = length;
536 data.flags = flags;
538 msg->header.prog = prog->program;
539 msg->header.vers = prog->version;
540 msg->header.proc = procedure;
541 msg->header.type = VIR_NET_STREAM_HOLE;
542 msg->header.serial = serial;
543 msg->header.status = VIR_NET_CONTINUE;
545 if (virNetMessageEncodeHeader(msg) < 0)
546 return -1;
548 if (virNetMessageEncodePayload(msg,
549 (xdrproc_t)xdr_virNetStreamHole,
550 &data) < 0)
551 return -1;
553 return virNetServerClientSendMessage(client, msg);
557 void virNetServerProgramDispose(void *obj G_GNUC_UNUSED)