static void virNetServerClientDispatchMessage(virNetServerClientPtr client, virNetMessagePtr msg) { virObjectLock(client); if (!client->dispatchFunc) { virNetMessageFree(msg); client->wantClose = true; virObjectUnlock(client); } else { virObjectUnlock(client); /* Accessing 'client' is safe, because virNetServerClientSetDispatcher * only permits setting 'dispatchFunc' once, so if non-NULL, it will * never change again */ client->dispatchFunc(client, msg, client->dispatchOpaque); } }
/* * Read data until we get a complete message to process */ static void virNetServerClientDispatchRead(virNetServerClientPtr client) { readmore: if (client->rx->nfds == 0) { if (virNetServerClientRead(client) < 0) { client->wantClose = true; return; /* Error */ } } if (client->rx->bufferOffset < client->rx->bufferLength) return; /* Still not read enough */ /* Either done with length word header */ if (client->rx->bufferLength == VIR_NET_MESSAGE_LEN_MAX) { if (virNetMessageDecodeLength(client->rx) < 0) { client->wantClose = true; return; } virNetServerClientUpdateEvent(client); /* Try and read payload immediately instead of going back into poll() because chances are the data is already waiting for us */ goto readmore; } else { /* Grab the completed message */ virNetMessagePtr msg = client->rx; virNetMessagePtr response = NULL; virNetServerClientFilterPtr filter; size_t i; /* Decode the header so we can use it for routing decisions */ if (virNetMessageDecodeHeader(msg) < 0) { virNetMessageFree(msg); client->wantClose = true; return; } /* Now figure out if we need to read more data to get some * file descriptors */ if (msg->header.type == VIR_NET_CALL_WITH_FDS && virNetMessageDecodeNumFDs(msg) < 0) { virNetMessageFree(msg); client->wantClose = true; return; /* Error */ } /* Try getting the file descriptors (may fail if blocking) */ for (i = msg->donefds ; i < msg->nfds ; i++) { int rv; if ((rv = virNetSocketRecvFD(client->sock, &(msg->fds[i]))) < 0) { virNetMessageFree(msg); client->wantClose = true; return; } if (rv == 0) /* Blocking */ break; msg->donefds++; } /* Need to poll() until FDs arrive */ if (msg->donefds < msg->nfds) { /* Because DecodeHeader/NumFDs reset bufferOffset, we * put it back to what it was, so everything works * again next time we run this method */ client->rx->bufferOffset = client->rx->bufferLength; return; } /* Definitely finished reading, so remove from queue */ virNetMessageQueueServe(&client->rx); PROBE(RPC_SERVER_CLIENT_MSG_RX, "client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u", client, msg->bufferLength, msg->header.prog, msg->header.vers, msg->header.proc, msg->header.type, msg->header.status, msg->header.serial); if (virKeepAliveCheckMessage(client->keepalive, msg, &response)) { virNetMessageFree(msg); client->nrequests--; msg = NULL; if (response && virNetServerClientSendMessageLocked(client, response) < 0) virNetMessageFree(response); } /* Maybe send off for queue against a filter */ if (msg) { filter = client->filters; while (filter) { int ret = filter->func(client, msg, filter->opaque); if (ret < 0) { virNetMessageFree(msg); msg = NULL; if (ret < 0) client->wantClose = true; break; } if (ret > 0) { msg = NULL; break; } filter = filter->next; } } /* Send off to for normal dispatch to workers */ if (msg) { virObjectRef(client); if (!client->dispatchFunc || client->dispatchFunc(client, msg, client->dispatchOpaque) < 0) { virNetMessageFree(msg); client->wantClose = true; virObjectUnref(client); return; } } /* Possibly need to create another receive buffer */ if (client->nrequests < client->nrequests_max) { if (!(client->rx = virNetMessageNew(true))) { client->wantClose = true; } else { client->rx->bufferLength = VIR_NET_MESSAGE_LEN_MAX; if (VIR_ALLOC_N(client->rx->buffer, client->rx->bufferLength) < 0) { virReportOOMError(); client->wantClose = true; } else { client->nrequests++; } } } virNetServerClientUpdateEvent(client); } }