stream.c 27.3 KB
Newer Older
1 2 3
/*
 * stream.c: APIs for managing client streams
 *
4
 * Copyright (C) 2009-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * 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
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22 23 24 25 26
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */


#include <config.h>

#include "stream.h"
27
#include "remote.h"
28
#include "viralloc.h"
29
#include "virlog.h"
30
#include "virnetserverclient.h"
31
#include "virerror.h"
32
#include "libvirt_internal.h"
33 34

#define VIR_FROM_THIS VIR_FROM_STREAMS
35

36 37
VIR_LOG_INIT("daemon.stream");

38 39
struct daemonClientStream {
    daemonClientPrivatePtr priv;
40
    int refs;
41 42 43 44 45

    virNetServerProgramPtr prog;

    virStreamPtr st;
    int procedure;
46
    unsigned int serial;
47

48 49
    bool recvEOF;
    bool closed;
50 51 52 53

    int filterID;

    virNetMessagePtr rx;
54
    bool tx;
55

56
    bool allowSkip;
57
    size_t dataLen; /* How much data is there remaining until we see a hole */
58

59 60 61
    daemonClientStreamPtr next;
};

62
static int
63 64
daemonStreamHandleWrite(virNetServerClientPtr client,
                        daemonClientStream *stream);
65
static int
66 67
daemonStreamHandleRead(virNetServerClientPtr client,
                       daemonClientStream *stream);
68
static int
69 70 71
daemonStreamHandleFinish(virNetServerClientPtr client,
                         daemonClientStream *stream,
                         virNetMessagePtr msg);
72
static int
73 74 75
daemonStreamHandleAbort(virNetServerClientPtr client,
                        daemonClientStream *stream,
                        virNetMessagePtr msg);
76 77 78 79



static void
80
daemonStreamUpdateEvents(daemonClientStream *stream)
81 82
{
    int newEvents = 0;
83 84
    if (stream->closed)
        return;
85 86
    if (stream->rx)
        newEvents |= VIR_STREAM_EVENT_WRITABLE;
87 88
    if (stream->tx && !stream->recvEOF)
        newEvents |= VIR_STREAM_EVENT_READABLE;
89 90 91 92

    virStreamEventUpdateCallback(stream->st, newEvents);
}

93 94 95 96 97 98 99 100
/*
 * Invoked when an outgoing data packet message has been fully sent.
 * This simply re-enables TX of further data.
 *
 * The idea is to stop the daemon growing without bound due to
 * fast stream, but slow client
 */
static void
101
daemonStreamMessageFinished(virNetMessagePtr msg,
102 103 104
                            void *opaque)
{
    daemonClientStream *stream = opaque;
105
    VIR_DEBUG("stream=%p proc=%d serial=%u",
106 107
              stream, msg->header.proc, msg->header.serial);

108
    stream->tx = true;
109
    daemonStreamUpdateEvents(stream);
110 111

    daemonFreeClientStream(NULL, stream);
112
}
113

114

115 116 117 118
/*
 * Callback that gets invoked when a stream becomes writable/readable
 */
static void
119
daemonStreamEvent(virStreamPtr st, int events, void *opaque)
120
{
121 122 123
    virNetServerClientPtr client = opaque;
    daemonClientStream *stream;
    daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
124

125
    virMutexLock(&priv->lock);
126

127 128 129 130 131 132
    stream = priv->streams;
    while (stream) {
        if (stream->st == st)
            break;
        stream = stream->next;
    }
133 134 135 136 137 138 139

    if (!stream) {
        VIR_WARN("event for client=%p stream st=%p, but missing stream state", client, st);
        virStreamEventRemoveCallback(st);
        goto cleanup;
    }

140
    VIR_DEBUG("st=%p events=%d EOF=%d closed=%d", st, events, stream->recvEOF, stream->closed);
141

D
Daniel P. Berrange 已提交
142 143
    if (!stream->closed &&
        (events & VIR_STREAM_EVENT_WRITABLE)) {
144 145 146
        if (daemonStreamHandleWrite(client, stream) < 0) {
            daemonRemoveClientStream(client, stream);
            virNetServerClientClose(client);
147 148 149 150
            goto cleanup;
        }
    }

D
Daniel P. Berrange 已提交
151 152 153
    if (!stream->closed && !stream->recvEOF &&
        (events & (VIR_STREAM_EVENT_READABLE))) {
        events = events & ~(VIR_STREAM_EVENT_READABLE);
154 155 156
        if (daemonStreamHandleRead(client, stream) < 0) {
            daemonRemoveClientStream(client, stream);
            virNetServerClientClose(client);
157 158
            goto cleanup;
        }
159 160 161 162 163 164 165 166
        /* If we detected EOF during read processing,
         * then clear hangup/error conditions, since
         * we want the client to see the EOF message
         * we just sent them
         */
        if (stream->recvEOF)
            events = events & ~(VIR_STREAM_EVENT_HANGUP |
                                VIR_STREAM_EVENT_ERROR);
167 168
    }

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
    /* If we have a completion/abort message, always process it */
    if (stream->rx) {
        virNetMessagePtr msg = stream->rx;
        switch (msg->header.status) {
        case VIR_NET_CONTINUE:
            /* nada */
            break;
        case VIR_NET_OK:
            virNetMessageQueueServe(&stream->rx);
            if (daemonStreamHandleFinish(client, stream, msg) < 0) {
                virNetMessageFree(msg);
                daemonRemoveClientStream(client, stream);
                virNetServerClientClose(client);
                goto cleanup;
            }
            break;
        case VIR_NET_ERROR:
        default:
            virNetMessageQueueServe(&stream->rx);
            if (daemonStreamHandleAbort(client, stream, msg) < 0) {
                virNetMessageFree(msg);
                daemonRemoveClientStream(client, stream);
                virNetServerClientClose(client);
                goto cleanup;
            }
            break;
        }
    }

D
Daniel P. Berrange 已提交
198 199 200 201 202 203 204 205

    /* If we got HANGUP, we need to only send an empty
     * packet so the client sees an EOF and cleans up
     */
    if (!stream->closed && !stream->recvEOF &&
        (events & VIR_STREAM_EVENT_HANGUP)) {
        virNetMessagePtr msg;
        events &= ~(VIR_STREAM_EVENT_HANGUP);
206
        stream->tx = false;
207
        stream->recvEOF = true;
D
Daniel P. Berrange 已提交
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
        if (!(msg = virNetMessageNew(false))) {
            daemonRemoveClientStream(client, stream);
            virNetServerClientClose(client);
            goto cleanup;
        }
        msg->cb = daemonStreamMessageFinished;
        msg->opaque = stream;
        stream->refs++;
        if (virNetServerProgramSendStreamData(remoteProgram,
                                              client,
                                              msg,
                                              stream->procedure,
                                              stream->serial,
                                              "", 0) < 0) {
            virNetMessageFree(msg);
            daemonRemoveClientStream(client, stream);
            virNetServerClientClose(client);
            goto cleanup;
        }
    }

229 230 231
    if (!stream->closed &&
        (events & (VIR_STREAM_EVENT_ERROR | VIR_STREAM_EVENT_HANGUP))) {
        int ret;
232 233 234 235
        virNetMessagePtr msg;
        virNetMessageError rerr;

        memset(&rerr, 0, sizeof(rerr));
236
        stream->closed = true;
237
        virStreamEventRemoveCallback(stream->st);
238 239
        virStreamAbort(stream->st);
        if (events & VIR_STREAM_EVENT_HANGUP)
240 241
            virReportError(VIR_ERR_RPC,
                           "%s", _("stream had unexpected termination"));
242
        else
243 244
            virReportError(VIR_ERR_RPC,
                           "%s", _("stream had I/O failure"));
245

246
        msg = virNetMessageNew(false);
247 248 249 250 251 252 253 254 255 256 257
        if (!msg) {
            ret = -1;
        } else {
            ret = virNetServerProgramSendStreamError(remoteProgram,
                                                     client,
                                                     msg,
                                                     &rerr,
                                                     stream->procedure,
                                                     stream->serial);
        }
        daemonRemoveClientStream(client, stream);
258
        if (ret < 0)
259
            virNetServerClientClose(client);
260 261 262 263
        goto cleanup;
    }

    if (stream->closed) {
264
        daemonRemoveClientStream(client, stream);
265
    } else {
266
        daemonStreamUpdateEvents(stream);
267 268
    }

269
 cleanup:
270
    virMutexUnlock(&priv->lock);
271 272
}

273 274 275 276 277 278 279 280 281 282

/*
 * @client: a locked client object
 *
 * Invoked by the main loop when filtering incoming messages.
 *
 * Returns 1 if the message was processed, 0 if skipped,
 * -1 on fatal client error
 */
static int
283
daemonStreamFilter(virNetServerClientPtr client ATTRIBUTE_UNUSED,
284 285
                   virNetMessagePtr msg,
                   void *opaque)
286
{
287 288
    daemonClientStream *stream = opaque;
    int ret = 0;
289

290 291
    virMutexLock(&stream->priv->lock);

292 293
    if (msg->header.type != VIR_NET_STREAM &&
        msg->header.type != VIR_NET_STREAM_HOLE)
294 295 296 297 298 299 300 301 302
        goto cleanup;

    if (!virNetServerProgramMatches(stream->prog, msg))
        goto cleanup;

    if (msg->header.proc != stream->procedure ||
        msg->header.serial != stream->serial)
        goto cleanup;

303
    VIR_DEBUG("Incoming client=%p, rx=%p, serial=%u, proc=%d, status=%d",
304 305 306 307 308 309 310
              client, stream->rx, msg->header.proc,
              msg->header.serial, msg->header.status);

    virNetMessageQueuePush(&stream->rx, msg);
    daemonStreamUpdateEvents(stream);
    ret = 1;

311
 cleanup:
312 313
    virMutexUnlock(&stream->priv->lock);
    return ret;
314 315 316 317 318
}


/*
 * @conn: a connection object to associate the stream with
319
 * @header: the method call to associate with the stream
320 321 322 323 324
 *
 * Creates a new stream for this conn
 *
 * Returns a new stream object, or NULL upon OOM
 */
325 326 327 328
daemonClientStream *
daemonCreateClientStream(virNetServerClientPtr client,
                         virStreamPtr st,
                         virNetServerProgramPtr prog,
329 330
                         virNetMessageHeaderPtr header,
                         bool allowSkip)
331
{
332 333
    daemonClientStream *stream;
    daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
334

335
    VIR_DEBUG("client=%p, proc=%d, serial=%u, st=%p",
336
              client, header->proc, header->serial, st);
337

338
    if (VIR_ALLOC(stream) < 0)
339 340
        return NULL;

341
    stream->refs = 1;
342
    stream->priv = priv;
343
    stream->prog = virObjectRef(prog);
344 345 346 347
    stream->procedure = header->proc;
    stream->serial = header->serial;
    stream->filterID = -1;
    stream->st = st;
348
    stream->allowSkip = allowSkip;
349 350 351 352 353 354 355 356 357 358

    return stream;
}

/*
 * @stream: an unused client stream
 *
 * Frees the memory associated with this inactive client
 * stream
 */
359 360
int daemonFreeClientStream(virNetServerClientPtr client,
                           daemonClientStream *stream)
361
{
362 363
    virNetMessagePtr msg;
    int ret = 0;
364 365

    if (!stream)
366 367
        return 0;

368 369 370 371
    stream->refs--;
    if (stream->refs)
        return 0;

372
    VIR_DEBUG("client=%p, proc=%d, serial=%u",
373
              client, stream->procedure, stream->serial);
374

375
    virObjectUnref(stream->prog);
376 377 378

    msg = stream->rx;
    while (msg) {
379
        virNetMessagePtr tmp = msg->next;
380 381
        if (client) {
            /* Send a dummy reply to free up 'msg' & unblock client rx */
382
            virNetMessageClear(msg);
383 384 385 386 387 388 389
            msg->header.type = VIR_NET_REPLY;
            if (virNetServerClientSendMessage(client, msg) < 0) {
                virNetServerClientImmediateClose(client);
                virNetMessageFree(msg);
                ret = -1;
            }
        } else {
390 391
            virNetMessageFree(msg);
        }
392 393 394
        msg = tmp;
    }

395
    virObjectUnref(stream->st);
396
    VIR_FREE(stream);
397 398

    return ret;
399 400 401 402 403 404 405
}


/*
 * @client: a locked client to add the stream to
 * @stream: a stream to add
 */
406 407 408
int daemonAddClientStream(virNetServerClientPtr client,
                          daemonClientStream *stream,
                          bool transmit)
409
{
410
    VIR_DEBUG("client=%p, proc=%d, serial=%u, st=%p, transmit=%d",
411 412
              client, stream->procedure, stream->serial, stream->st, transmit);
    daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
413

414 415 416 417
    if (stream->filterID != -1) {
        VIR_WARN("Filter already added to client %p", client);
        return -1;
    }
418

419
    if (virStreamEventAddCallback(stream->st, 0,
420
                                  daemonStreamEvent, client,
421
                                  virObjectFreeCallback) < 0)
422 423
        return -1;

424 425
    virObjectRef(client);

426 427 428 429 430
    if ((stream->filterID = virNetServerClientAddFilter(client,
                                                        daemonStreamFilter,
                                                        stream)) < 0) {
        virStreamEventRemoveCallback(stream->st);
        return -1;
431 432
    }

433
    if (transmit)
434
        stream->tx = true;
435

436 437 438
    virMutexLock(&priv->lock);
    stream->next = priv->streams;
    priv->streams = stream;
439

440
    daemonStreamUpdateEvents(stream);
441

442
    virMutexUnlock(&priv->lock);
443

444
    return 0;
445 446 447 448 449 450 451 452 453
}


/*
 * @client: a locked client object
 * @stream: an inactive, closed stream object
 *
 * Removes a stream from the list of active streams for the client
 *
N
Nitesh Konkar 已提交
454
 * Returns 0 if the stream was removed, -1 if it doesn't exist
455 456
 */
int
457 458
daemonRemoveClientStream(virNetServerClientPtr client,
                         daemonClientStream *stream)
459
{
460
    VIR_DEBUG("client=%p, proc=%d, serial=%u, st=%p",
461 462 463 464 465 466 467 468 469
              client, stream->procedure, stream->serial, stream->st);
    daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
    daemonClientStream *curr = priv->streams;
    daemonClientStream *prev = NULL;

    if (stream->filterID != -1) {
        virNetServerClientRemoveFilter(client,
                                       stream->filterID);
        stream->filterID = -1;
470 471
    }

472
    if (!stream->closed) {
473
        stream->closed = true;
474
        virStreamEventRemoveCallback(stream->st);
475
        virStreamAbort(stream->st);
476
    }
477 478 479 480 481 482

    while (curr) {
        if (curr == stream) {
            if (prev)
                prev->next = curr->next;
            else
483 484
                priv->streams = curr->next;
            return daemonFreeClientStream(client, stream);
485 486 487 488 489 490
        }
        prev = curr;
        curr = curr->next;
    }
    return -1;
}
491 492


493 494 495 496 497 498 499 500 501 502 503
void
daemonRemoveAllClientStreams(daemonClientStream *stream)
{
    daemonClientStream *tmp;

    VIR_DEBUG("stream=%p", stream);

    while (stream) {
        tmp = stream->next;

        if (!stream->closed) {
504
            stream->closed = true;
505 506 507 508 509 510 511 512 513 514 515
            virStreamEventRemoveCallback(stream->st);
            virStreamAbort(stream->st);
        }

        daemonFreeClientStream(NULL, stream);

        VIR_DEBUG("next stream=%p", tmp);
        stream = tmp;
    }
}

516 517 518 519 520 521 522
/*
 * Returns:
 *   -1  if fatal error occurred
 *    0  if message was fully processed
 *    1  if message is still being processed
 */
static int
523 524 525
daemonStreamHandleWriteData(virNetServerClientPtr client,
                            daemonClientStream *stream,
                            virNetMessagePtr msg)
526 527 528
{
    int ret;

529
    VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u, len=%zu, offset=%zu",
530 531
              client, stream, msg->header.proc, msg->header.serial,
              msg->bufferLength, msg->bufferOffset);
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546

    ret = virStreamSend(stream->st,
                        msg->buffer + msg->bufferOffset,
                        msg->bufferLength - msg->bufferOffset);

    if (ret > 0) {
        msg->bufferOffset += ret;

        /* Partial write, so indicate we have more todo later */
        if (msg->bufferOffset < msg->bufferLength)
            return 1;
    } else if (ret == -2) {
        /* Blocking, so indicate we have more todo later */
        return 1;
    } else {
547 548 549 550
        virNetMessageError rerr;

        memset(&rerr, 0, sizeof(rerr));

551
        VIR_INFO("Stream send failed");
552
        stream->closed = true;
553 554 555
        virStreamEventRemoveCallback(stream->st);
        virStreamAbort(stream->st);

556 557 558 559 560
        return virNetServerProgramSendReplyError(stream->prog,
                                                 client,
                                                 msg,
                                                 &rerr,
                                                 &msg->header);
561 562 563 564 565 566 567
    }

    return 0;
}


/*
E
Eric Blake 已提交
568
 * Process a finish handshake from the client.
569
 *
570
 * Returns a VIR_NET_OK confirmation if successful, or a VIR_NET_ERROR
571 572 573 574 575
 * if there was a stream error
 *
 * Returns 0 if successfully sent RPC reply, -1 upon fatal error
 */
static int
576 577 578
daemonStreamHandleFinish(virNetServerClientPtr client,
                         daemonClientStream *stream,
                         virNetMessagePtr msg)
579 580 581
{
    int ret;

582
    VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u",
583
              client, stream, msg->header.proc, msg->header.serial);
584

585
    stream->closed = true;
586
    virStreamEventRemoveCallback(stream->st);
587 588 589
    ret = virStreamFinish(stream->st);

    if (ret < 0) {
590 591 592 593 594 595 596
        virNetMessageError rerr;
        memset(&rerr, 0, sizeof(rerr));
        return virNetServerProgramSendReplyError(stream->prog,
                                                 client,
                                                 msg,
                                                 &rerr,
                                                 &msg->header);
597 598
    } else {
        /* Send zero-length confirm */
599 600 601 602 603 604
        return virNetServerProgramSendStreamData(stream->prog,
                                                 client,
                                                 msg,
                                                 stream->procedure,
                                                 stream->serial,
                                                 NULL, 0);
605 606 607 608 609 610 611 612 613 614
    }
}


/*
 * Process an abort request from the client.
 *
 * Returns 0 if successfully aborted, -1 upon error
 */
static int
615 616 617
daemonStreamHandleAbort(virNetServerClientPtr client,
                        daemonClientStream *stream,
                        virNetMessagePtr msg)
618
{
619
    VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u",
620
              client, stream, msg->header.proc, msg->header.serial);
621 622
    int ret;
    bool raise_error = false;
623

624
    stream->closed = true;
625
    virStreamEventRemoveCallback(stream->st);
626
    ret = virStreamAbort(stream->st);
627

628
    if (msg->header.status == VIR_NET_ERROR) {
629 630
        VIR_INFO("stream aborted at client request");
        raise_error = (ret < 0);
631
    } else {
632 633 634
        virReportError(VIR_ERR_RPC,
                       _("stream aborted with unexpected status %d"),
                       msg->header.status);
635
        raise_error = true;
636 637
    }

638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
    if (raise_error) {
        virNetMessageError rerr;
        memset(&rerr, 0, sizeof(rerr));
        return virNetServerProgramSendReplyError(remoteProgram,
                                                 client,
                                                 msg,
                                                 &rerr,
                                                 &msg->header);
    } else {
        /* Send zero-length confirm */
        return virNetServerProgramSendStreamData(stream->prog,
                                                 client,
                                                 msg,
                                                 stream->procedure,
                                                 stream->serial,
                                                 NULL, 0);
    }
655 656 657
}


658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
static int
daemonStreamHandleHole(virNetServerClientPtr client,
                       daemonClientStream *stream,
                       virNetMessagePtr msg)
{
    int ret;
    virNetStreamHole data;

    VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u",
              client, stream, msg->header.proc, msg->header.serial);

    /* Let's check if client plays nicely and advertised usage of
     * sparse stream upfront. */
    if (!stream->allowSkip) {
        virReportError(VIR_ERR_RPC, "%s",
                       _("Unexpected stream hole"));
        return -1;
    }

    if (virNetMessageDecodePayload(msg,
                                   (xdrproc_t) xdr_virNetStreamHole,
                                   &data) < 0)
        return -1;

    ret = virStreamSendHole(stream->st, data.length, data.flags);

    if (ret < 0) {
        virNetMessageError rerr;

        memset(&rerr, 0, sizeof(rerr));

        VIR_INFO("Stream send hole failed");
        stream->closed = true;
        virStreamEventRemoveCallback(stream->st);
        virStreamAbort(stream->st);

        return virNetServerProgramSendReplyError(stream->prog,
                                                 client,
                                                 msg,
                                                 &rerr,
                                                 &msg->header);
    }

    return 0;
}

704 705 706 707 708 709 710 711 712

/*
 * Called when the stream is signalled has being able to accept
 * data writes. Will process all pending incoming messages
 * until they're all gone, or I/O blocks
 *
 * Returns 0 on success, or -1 upon fatal error
 */
static int
713 714
daemonStreamHandleWrite(virNetServerClientPtr client,
                        daemonClientStream *stream)
715
{
716
    VIR_DEBUG("client=%p, stream=%p", client, stream);
717

718 719
    while (stream->rx && !stream->closed) {
        virNetMessagePtr msg = stream->rx;
720
        int ret;
721

722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
        if (msg->header.type == VIR_NET_STREAM_HOLE) {
            /* Handle special case when the client sent us a hole.
             * Otherwise just carry on with processing stream
             * data. */
            ret = daemonStreamHandleHole(client, stream, msg);
        } else if (msg->header.type == VIR_NET_STREAM) {
            switch (msg->header.status) {
            case VIR_NET_OK:
                ret = daemonStreamHandleFinish(client, stream, msg);
                break;

            case VIR_NET_CONTINUE:
                ret = daemonStreamHandleWriteData(client, stream, msg);
                break;

            case VIR_NET_ERROR:
            default:
                ret = daemonStreamHandleAbort(client, stream, msg);
                break;
            }
        } else {
            virReportError(VIR_ERR_RPC,
                           _("Unexpected message type: %d"),
                           msg->header.type);
            ret = -1;
747 748
        }

749 750
        if (ret > 0)
            break;  /* still processing data from msg */
751

752 753 754
        virNetMessageQueueServe(&stream->rx);
        if (ret < 0) {
            virNetMessageFree(msg);
755
            virNetServerClientImmediateClose(client);
756 757
            return -1;
        }
758 759 760 761 762 763 764 765

        /* 'CONTINUE' messages don't send a reply (unless error
         * occurred), so to release the 'msg' object we need to
         * send a fake zero-length reply. Nothing actually gets
         * onto the wire, but this causes the client to reset
         * its active request count / throttling
         */
        if (msg->header.status == VIR_NET_CONTINUE) {
766
            virNetMessageClear(msg);
767 768 769
            msg->header.type = VIR_NET_REPLY;
            if (virNetServerClientSendMessage(client, msg) < 0) {
                virNetMessageFree(msg);
770
                virNetServerClientImmediateClose(client);
771 772 773
                return -1;
            }
        }
774 775 776 777
    }

    return 0;
}
778 779 780 781 782



/*
 * Invoked when a stream is signalled as having data
J
Ján Tomko 已提交
783
 * available to read. This reads up to one message
784 785 786
 * worth of data, and then queues that for transmission
 * to the client.
 *
Y
Yuri Chornoivan 已提交
787
 * Returns 0 if data was queued for TX, or an error RPC
788 789 790 791
 * was sent, or -1 on fatal error, indicating client should
 * be killed
 */
static int
792 793
daemonStreamHandleRead(virNetServerClientPtr client,
                       daemonClientStream *stream)
794
{
795 796
    virNetMessagePtr msg = NULL;
    virNetMessageError rerr;
797
    char *buffer;
798
    size_t bufferLen = VIR_NET_MESSAGE_LEGACY_PAYLOAD_MAX;
799 800
    int ret = -1;
    int rv;
801 802
    int inData = 0;
    long long length = 0;
803

804 805 806 807 808 809 810 811 812
    VIR_DEBUG("client=%p, stream=%p tx=%d closed=%d",
              client, stream, stream->tx, stream->closed);

    /* We might have had an event pending before we shut
     * down the stream, so if we're marked as closed,
     * then do nothing
     */
    if (stream->closed)
        return 0;
813 814 815 816 817 818

    /* Shouldn't ever be called unless we're marked able to
     * transmit, but doesn't hurt to check */
    if (!stream->tx)
        return 0;

819 820
    memset(&rerr, 0, sizeof(rerr));

821 822 823
    if (VIR_ALLOC_N(buffer, bufferLen) < 0)
        return -1;

824 825 826
    if (!(msg = virNetMessageNew(false)))
        goto cleanup;

827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
    if (stream->allowSkip && stream->dataLen == 0) {
        /* Handle skip. We want to send some data to the client. But we might
         * be in a hole. Seek to next data. But if we are in data already, just
         * carry on. */

        rv = virStreamInData(stream->st, &inData, &length);
        VIR_DEBUG("rv=%d inData=%d length=%lld", rv, inData, length);

        if (rv < 0) {
            if (virNetServerProgramSendStreamError(remoteProgram,
                                                   client,
                                                   msg,
                                                   &rerr,
                                                   stream->procedure,
                                                   stream->serial) < 0)
                goto cleanup;
            msg = NULL;

            /* We're done with this call */
            goto done;
        } else {
            if (!inData && length) {
                stream->tx = false;
                msg->cb = daemonStreamMessageFinished;
                msg->opaque = stream;
                stream->refs++;
                if (virNetServerProgramSendStreamHole(remoteProgram,
                                                      client,
                                                      msg,
                                                      stream->procedure,
                                                      stream->serial,
                                                      length,
                                                      0) < 0)
                    goto cleanup;

                msg = NULL;

                /* We have successfully sent stream skip to the other side.
                 * To keep streams in sync seek locally too. */
                virStreamSendHole(stream->st, length, 0);
                /* We're done with this call */
                goto done;
            }
        }

        stream->dataLen = length;
    }

    if (stream->allowSkip &&
        bufferLen > stream->dataLen)
        bufferLen = stream->dataLen;

879 880
    rv = virStreamRecv(stream->st, buffer, bufferLen);
    if (rv == -2) {
881 882
        /* Should never get this, since we're only called when we know
         * we're readable, but hey things change... */
883 884 885 886 887 888 889 890 891
    } else if (rv < 0) {
        if (virNetServerProgramSendStreamError(remoteProgram,
                                               client,
                                               msg,
                                               &rerr,
                                               stream->procedure,
                                               stream->serial) < 0)
            goto cleanup;
        msg = NULL;
892
    } else {
893 894 895
        if (stream->allowSkip)
            stream->dataLen -= rv;

896
        stream->tx = false;
897
        if (rv == 0)
898
            stream->recvEOF = true;
899

900 901 902 903 904 905 906 907 908 909 910
        msg->cb = daemonStreamMessageFinished;
        msg->opaque = stream;
        stream->refs++;
        if (virNetServerProgramSendStreamData(remoteProgram,
                                              client,
                                              msg,
                                              stream->procedure,
                                              stream->serial,
                                              buffer, rv) < 0)
            goto cleanup;
        msg = NULL;
911 912
    }

913
 done:
914 915
    ret = 0;
 cleanup:
916
    VIR_FREE(buffer);
917
    virNetMessageFree(msg);
918 919
    return ret;
}