virKeepAlivePtr keepalive;
bool wantClose;
+ int closeReason;
};
virNetClientCallPtr thiscall);
static int virNetClientQueueNonBlocking(virNetClientPtr client,
virNetMessagePtr msg);
+static void virNetClientCloseInternal(virNetClientPtr client,
+ int reason);
static void virNetClientLock(virNetClientPtr client)
static void
virNetClientKeepAliveDeadCB(void *opaque)
{
- virNetClientClose(opaque);
+ virNetClientCloseInternal(opaque, VIR_CONNECT_CLOSE_REASON_KEEPALIVE);
}
static int
}
+static void
+virNetClientMarkClose(virNetClientPtr client,
+ int reason)
+{
+ VIR_DEBUG("client=%p, reason=%d", client, reason);
+ virNetSocketRemoveIOCallback(client->sock);
+ client->wantClose = true;
+ client->closeReason = reason;
+}
+
+
static void
virNetClientCloseLocked(virNetClientPtr client)
{
virKeepAlivePtr ka;
- VIR_DEBUG("client=%p, sock=%p", client, client->sock);
+ VIR_DEBUG("client=%p, sock=%p, reason=%d", client, client->sock, client->closeReason);
if (!client->sock)
return;
- virNetSocketRemoveIOCallback(client->sock);
virNetSocketFree(client->sock);
client->sock = NULL;
virNetTLSSessionFree(client->tls);
}
}
-void virNetClientClose(virNetClientPtr client)
+static void virNetClientCloseInternal(virNetClientPtr client,
+ int reason)
{
VIR_DEBUG("client=%p", client);
if (!client)
return;
+ if (!client->sock ||
+ client->wantClose)
+ return;
+
virNetClientLock(client);
- client->wantClose = true;
+ virNetClientMarkClose(client, reason);
/* If there is a thread polling for data on the socket, wake the thread up
* otherwise try to pass the buck to a possibly waiting thread. If no
}
+void virNetClientClose(virNetClientPtr client)
+{
+ virNetClientCloseInternal(client, VIR_CONNECT_CLOSE_REASON_CLIENT);
+}
+
+
#if HAVE_SASL
void virNetClientSetSASLSession(virNetClientPtr client,
virNetSASLSessionPtr sasl)
}
if (virKeepAliveTrigger(client->keepalive, &msg)) {
- client->wantClose = true;
+ virNetClientMarkClose(client, VIR_CONNECT_CLOSE_REASON_KEEPALIVE);
} else if (msg && virNetClientQueueNonBlocking(client, msg) < 0) {
VIR_WARN("Could not queue keepalive request");
virNetMessageFree(msg);
if (saferead(client->wakeupReadFD, &ignore, sizeof(ignore)) != sizeof(ignore)) {
virReportSystemError(errno, "%s",
_("read on wakeup fd failed"));
+ virNetClientMarkClose(client, VIR_CONNECT_CLOSE_REASON_ERROR);
goto error;
}
}
if (fds[0].revents & POLLOUT) {
- if (virNetClientIOHandleOutput(client) < 0)
+ if (virNetClientIOHandleOutput(client) < 0) {
+ virNetClientMarkClose(client, VIR_CONNECT_CLOSE_REASON_ERROR);
goto error;
+ }
}
if (fds[0].revents & POLLIN) {
- if (virNetClientIOHandleInput(client) < 0)
+ if (virNetClientIOHandleInput(client) < 0) {
+ virNetClientMarkClose(client, VIR_CONNECT_CLOSE_REASON_ERROR);
goto error;
+ }
}
/* Iterate through waiting calls and if any are
}
if (fds[0].revents & (POLLHUP | POLLERR)) {
+ virNetClientMarkClose(client, VIR_CONNECT_CLOSE_REASON_EOF);
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("received hangup / error event on socket"));
goto error;
{
int events = 0;
+ if (client->wantClose)
+ return;
+
if (enableCallback) {
events |= VIR_EVENT_HANDLE_READABLE;
virNetClientCallMatchPredicate(client->waitDispatch,
virNetClientLock(client);
+ VIR_DEBUG("client=%p wantclose=%d", client, client ? client->wantClose : false);
+
if (!client->sock)
goto done;
if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) {
VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or "
"VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__);
- virNetSocketRemoveIOCallback(sock);
+ virNetClientMarkClose(client,
+ (events & VIR_EVENT_HANDLE_HANGUP) ?
+ VIR_CONNECT_CLOSE_REASON_EOF :
+ VIR_CONNECT_CLOSE_REASON_ERROR);
goto done;
}
if (events & VIR_EVENT_HANDLE_WRITABLE) {
if (virNetClientIOHandleOutput(client) < 0)
- virNetSocketRemoveIOCallback(sock);
+ virNetClientMarkClose(client, VIR_CONNECT_CLOSE_REASON_ERROR);
}
if (events & VIR_EVENT_HANDLE_READABLE) {
if (virNetClientIOHandleInput(client) < 0)
- virNetSocketRemoveIOCallback(sock);
+ virNetClientMarkClose(client, VIR_CONNECT_CLOSE_REASON_ERROR);
}
/* Remove completed calls or signal their threads. */
virNetClientIOUpdateCallback(client, true);
done:
+ if (client->wantClose)
+ virNetClientCloseLocked(client);
virNetClientUnlock(client);
}