virnetserverservice.c 12.6 KB
Newer Older
1 2 3
/*
 * virnetserverservice.c: generic network RPC server service
 *
E
Eric Blake 已提交
4
 * Copyright (C) 2006-2012 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2006 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26 27
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include "virnetserverservice.h"

28
#include "viralloc.h"
29
#include "virerror.h"
30
#include "virthread.h"
31 32 33 34

#define VIR_FROM_THIS VIR_FROM_RPC

struct _virNetServerService {
35
    virObject object;
36 37 38 39 40 41

    size_t nsocks;
    virNetSocketPtr *socks;

    int auth;
    bool readonly;
42
    size_t nrequests_client_max;
43

44
#if WITH_GNUTLS
45
    virNetTLSContextPtr tls;
46
#endif
47 48 49 50 51 52

    virNetServerServiceDispatchFunc dispatchFunc;
    void *dispatchOpaque;
};


53 54 55 56 57
static virClassPtr virNetServerServiceClass;
static void virNetServerServiceDispose(void *obj);

static int virNetServerServiceOnceInit(void)
{
58 59
    if (!(virNetServerServiceClass = virClassNew(virClassForObject(),
                                                 "virNetServerService",
60 61 62 63 64 65 66 67 68
                                                 sizeof(virNetServerService),
                                                 virNetServerServiceDispose)))
        return -1;

    return 0;
}

VIR_ONCE_GLOBAL_INIT(virNetServerService)

69 70 71 72 73 74 75 76 77

static void virNetServerServiceAccept(virNetSocketPtr sock,
                                      int events ATTRIBUTE_UNUSED,
                                      void *opaque)
{
    virNetServerServicePtr svc = opaque;
    virNetSocketPtr clientsock = NULL;

    if (virNetSocketAccept(sock, &clientsock) < 0)
78
        goto cleanup;
79 80 81 82 83

    if (!clientsock) /* Connection already went away */
        goto cleanup;

    if (!svc->dispatchFunc)
84
        goto cleanup;
85

86
    svc->dispatchFunc(svc, clientsock, svc->dispatchOpaque);
87 88

cleanup:
89
    virObjectUnref(clientsock);
90 91 92 93 94 95
}


virNetServerServicePtr virNetServerServiceNewTCP(const char *nodename,
                                                 const char *service,
                                                 int auth,
96
#if WITH_GNUTLS
97 98
                                                 virNetTLSContextPtr tls,
#endif
99
                                                 bool readonly,
M
Michal Privoznik 已提交
100
                                                 size_t max_queued_clients,
101
                                                 size_t nrequests_client_max)
102 103 104 105
{
    virNetServerServicePtr svc;
    size_t i;

106 107 108 109 110
    if (virNetServerServiceInitialize() < 0)
        return NULL;

    if (!(svc = virObjectNew(virNetServerServiceClass)))
        return NULL;
111 112 113

    svc->auth = auth;
    svc->readonly = readonly;
114
    svc->nrequests_client_max = nrequests_client_max;
115
#if WITH_GNUTLS
116
    svc->tls = virObjectRef(tls);
117
#endif
118 119 120 121 122 123 124

    if (virNetSocketNewListenTCP(nodename,
                                 service,
                                 &svc->socks,
                                 &svc->nsocks) < 0)
        goto error;

125
    for (i = 0; i < svc->nsocks; i++) {
M
Michal Privoznik 已提交
126
        if (virNetSocketListen(svc->socks[i], max_queued_clients) < 0)
127 128 129 130
            goto error;

        /* IO callback is initially disabled, until we're ready
         * to deal with incoming clients */
131
        virObjectRef(svc);
132 133 134
        if (virNetSocketAddIOCallback(svc->socks[i],
                                      0,
                                      virNetServerServiceAccept,
135
                                      svc,
136 137
                                      virObjectFreeCallback) < 0) {
            virObjectUnref(svc);
138
            goto error;
139
        }
140 141 142 143 144 145
    }


    return svc;

error:
146
    virObjectUnref(svc);
147 148 149 150 151 152 153 154
    return NULL;
}


virNetServerServicePtr virNetServerServiceNewUNIX(const char *path,
                                                  mode_t mask,
                                                  gid_t grp,
                                                  int auth,
155
#if WITH_GNUTLS
156 157
                                                  virNetTLSContextPtr tls,
#endif
158
                                                  bool readonly,
M
Michal Privoznik 已提交
159
                                                  size_t max_queued_clients,
160
                                                  size_t nrequests_client_max)
161 162
{
    virNetServerServicePtr svc;
163
    size_t i;
164

165 166 167 168 169
    if (virNetServerServiceInitialize() < 0)
        return NULL;

    if (!(svc = virObjectNew(virNetServerServiceClass)))
        return NULL;
170 171 172

    svc->auth = auth;
    svc->readonly = readonly;
173
    svc->nrequests_client_max = nrequests_client_max;
174
#if WITH_GNUTLS
175
    svc->tls = virObjectRef(tls);
176
#endif
177 178 179

    svc->nsocks = 1;
    if (VIR_ALLOC_N(svc->socks, svc->nsocks) < 0)
180
        goto error;
181 182 183

    if (virNetSocketNewListenUNIX(path,
                                  mask,
184
                                  -1,
185 186 187 188
                                  grp,
                                  &svc->socks[0]) < 0)
        goto error;

189
    for (i = 0; i < svc->nsocks; i++) {
M
Michal Privoznik 已提交
190
        if (virNetSocketListen(svc->socks[i], max_queued_clients) < 0)
191 192 193 194
            goto error;

        /* IO callback is initially disabled, until we're ready
         * to deal with incoming clients */
195
        virObjectRef(svc);
196 197 198
        if (virNetSocketAddIOCallback(svc->socks[i],
                                      0,
                                      virNetServerServiceAccept,
199
                                      svc,
200 201
                                      virObjectFreeCallback) < 0) {
            virObjectUnref(svc);
202
            goto error;
203
        }
204 205 206 207 208 209
    }


    return svc;

error:
210
    virObjectUnref(svc);
211 212 213
    return NULL;
}

214 215
virNetServerServicePtr virNetServerServiceNewFD(int fd,
                                                int auth,
216
#if WITH_GNUTLS
217 218
                                                virNetTLSContextPtr tls,
#endif
219
                                                bool readonly,
220
                                                size_t nrequests_client_max)
221 222
{
    virNetServerServicePtr svc;
223
    size_t i;
224 225 226 227 228 229 230 231 232 233

    if (virNetServerServiceInitialize() < 0)
        return NULL;

    if (!(svc = virObjectNew(virNetServerServiceClass)))
        return NULL;

    svc->auth = auth;
    svc->readonly = readonly;
    svc->nrequests_client_max = nrequests_client_max;
234
#if WITH_GNUTLS
235
    svc->tls = virObjectRef(tls);
236
#endif
237 238 239

    svc->nsocks = 1;
    if (VIR_ALLOC_N(svc->socks, svc->nsocks) < 0)
240
        goto error;
241 242 243 244 245

    if (virNetSocketNewListenFD(fd,
                                &svc->socks[0]) < 0)
        goto error;

246
    for (i = 0; i < svc->nsocks; i++) {
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
        /* IO callback is initially disabled, until we're ready
         * to deal with incoming clients */
        if (virNetSocketAddIOCallback(svc->socks[i],
                                      0,
                                      virNetServerServiceAccept,
                                      svc,
                                      virObjectFreeCallback) < 0)
            goto error;
    }


    return svc;

error:
    virObjectUnref(svc);
    return NULL;
}

265

266 267 268 269 270 271
virNetServerServicePtr virNetServerServiceNewPostExecRestart(virJSONValuePtr object)
{
    virNetServerServicePtr svc;
    virJSONValuePtr socks;
    size_t i;
    int n;
272
    unsigned int max;
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290

    if (virNetServerServiceInitialize() < 0)
        return NULL;

    if (!(svc = virObjectNew(virNetServerServiceClass)))
        return NULL;

    if (virJSONValueObjectGetNumberInt(object, "auth", &svc->auth) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing auth field in JSON state document"));
        goto error;
    }
    if (virJSONValueObjectGetBoolean(object, "readonly", &svc->readonly) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing readonly field in JSON state document"));
        goto error;
    }
    if (virJSONValueObjectGetNumberUint(object, "nrequests_client_max",
291
                                        &max) < 0) {
292 293 294 295
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing nrequests_client_max field in JSON state document"));
        goto error;
    }
296
    svc->nrequests_client_max = max;
297 298 299 300 301 302 303 304 305 306 307 308 309 310

    if (!(socks = virJSONValueObjectGet(object, "socks"))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing socks field in JSON state document"));
        goto error;
    }

    if ((n = virJSONValueArraySize(socks)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("socks field in JSON was not an array"));
        goto error;
    }

    svc->nsocks = n;
311
    if (VIR_ALLOC_N(svc->socks, svc->nsocks) < 0)
312 313
        goto error;

314
    for (i = 0; i < svc->nsocks; i++) {
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
        virJSONValuePtr child = virJSONValueArrayGet(socks, i);
        virNetSocketPtr sock;

        if (!(sock = virNetSocketNewPostExecRestart(child))) {
            virObjectUnref(sock);
            goto error;
        }

        svc->socks[i] = sock;

        /* IO callback is initially disabled, until we're ready
         * to deal with incoming clients */
        virObjectRef(svc);
        if (virNetSocketAddIOCallback(sock,
                                      0,
                                      virNetServerServiceAccept,
                                      svc,
                                      virObjectFreeCallback) < 0) {
            virObjectUnref(svc);
            virObjectUnref(sock);
            goto error;
        }
    }

    return svc;

error:
    virObjectUnref(svc);
    return NULL;
}


virJSONValuePtr virNetServerServicePreExecRestart(virNetServerServicePtr svc)
{
    virJSONValuePtr object = virJSONValueNewObject();
    virJSONValuePtr socks;
    size_t i;

    if (!object)
        return NULL;

    if (virJSONValueObjectAppendNumberInt(object, "auth", svc->auth) < 0)
        goto error;
    if (virJSONValueObjectAppendBoolean(object, "readonly", svc->readonly) < 0)
        goto error;
    if (virJSONValueObjectAppendNumberUint(object, "nrequests_client_max", svc->nrequests_client_max) < 0)
        goto error;

363 364 365
    if (!(socks = virJSONValueNewArray()))
        goto error;

366 367 368 369 370
    if (virJSONValueObjectAppend(object, "socks", socks) < 0) {
        virJSONValueFree(socks);
        goto error;
    }

371
    for (i = 0; i < svc->nsocks; i++) {
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
        virJSONValuePtr child;
        if (!(child = virNetSocketPreExecRestart(svc->socks[i])))
            goto error;

        if (virJSONValueArrayAppend(socks, child) < 0) {
            virJSONValueFree(child);
            goto error;
        }
    }

    return object;

error:
    virJSONValueFree(object);
    return NULL;
}


390 391 392 393 394 395 396 397
int virNetServerServiceGetPort(virNetServerServicePtr svc)
{
    /* We're assuming if there are multiple sockets
     * for IPv4 & 6, then they are all on same port */
    return virNetSocketGetPort(svc->socks[0]);
}


398 399 400 401 402 403 404 405 406 407 408 409
int virNetServerServiceGetAuth(virNetServerServicePtr svc)
{
    return svc->auth;
}


bool virNetServerServiceIsReadonly(virNetServerServicePtr svc)
{
    return svc->readonly;
}


410 411 412 413 414
size_t virNetServerServiceGetMaxRequests(virNetServerServicePtr svc)
{
    return svc->nrequests_client_max;
}

415
#if WITH_GNUTLS
416 417 418 419
virNetTLSContextPtr virNetServerServiceGetTLSContext(virNetServerServicePtr svc)
{
    return svc->tls;
}
420
#endif
421

422 423 424 425 426 427 428 429 430
void virNetServerServiceSetDispatcher(virNetServerServicePtr svc,
                                      virNetServerServiceDispatchFunc func,
                                      void *opaque)
{
    svc->dispatchFunc = func;
    svc->dispatchOpaque = opaque;
}


431
void virNetServerServiceDispose(void *obj)
432
{
433
    virNetServerServicePtr svc = obj;
434
    size_t i;
435

436
    for (i = 0; i < svc->nsocks; i++)
437
        virObjectUnref(svc->socks[i]);
438 439
    VIR_FREE(svc->socks);

440
#if WITH_GNUTLS
441
    virObjectUnref(svc->tls);
442
#endif
443 444 445 446 447
}

void virNetServerServiceToggle(virNetServerServicePtr svc,
                               bool enabled)
{
448
    size_t i;
449

450
    for (i = 0; i < svc->nsocks; i++)
451 452 453 454 455
        virNetSocketUpdateIOCallback(svc->socks[i],
                                     enabled ?
                                     VIR_EVENT_HANDLE_READABLE :
                                     0);
}
456 457 458

void virNetServerServiceClose(virNetServerServicePtr svc)
{
459
    size_t i;
460 461 462 463 464 465 466 467

    if (!svc)
        return;

    for (i = 0; i < svc->nsocks; i++) {
        virNetSocketClose(svc->socks[i]);
    }
}