Use a virFreeCallback on virNetSocket to ensure safe release

When unregistering an I/O callback from a virNetSocket object,
there is still a chance that an event may come in on the callback.
In this case it is possible that the virNetSocket might have been
freed already. Make use of a virFreeCallback when registering
the I/O callbacks and hold a reference for the entire time the
callback is set.

* src/rpc/virnetsocket.c: Register a free function for the
  file handle watch
* src/rpc/virnetsocket.h, src/rpc/virnetserverservice.c,
  src/rpc/virnetserverclient.c, src/rpc/virnetclient.c: Add
  a free function for the socket I/O watches
This commit is contained in:
Daniel P. Berrange 2011-07-19 14:11:33 +01:00
parent 6198f3a1d7
commit 7ea2ef4ce8
5 changed files with 74 additions and 7 deletions

View File

@ -110,6 +110,13 @@ static void virNetClientIncomingEvent(virNetSocketPtr sock,
int events,
void *opaque);
static void virNetClientEventFree(void *opaque)
{
virNetClientPtr client = opaque;
virNetClientFree(client);
}
static virNetClientPtr virNetClientNew(virNetSocketPtr sock,
const char *hostname)
{
@ -140,11 +147,15 @@ static virNetClientPtr virNetClientNew(virNetSocketPtr sock,
goto no_memory;
/* Set up a callback to listen on the socket data */
client->refs++;
if (virNetSocketAddIOCallback(client->sock,
VIR_EVENT_HANDLE_READABLE,
virNetClientIncomingEvent,
client) < 0)
client,
virNetClientEventFree) < 0) {
client->refs--;
VIR_DEBUG("Failed to add event watch, disabling events");
}
VIR_DEBUG("client=%p refs=%d", client, client->refs);
return client;

View File

@ -160,6 +160,13 @@ virNetServerClientCalculateHandleMode(virNetServerClientPtr client) {
return mode;
}
static void virNetServerClientEventFree(void *opaque)
{
virNetServerClientPtr client = opaque;
virNetServerClientFree(client);
}
/*
* @server: a locked or unlocked server object
* @client: a locked client object
@ -168,12 +175,16 @@ static int virNetServerClientRegisterEvent(virNetServerClientPtr client)
{
int mode = virNetServerClientCalculateHandleMode(client);
client->refs++;
VIR_DEBUG("Registering client event callback %d", mode);
if (virNetSocketAddIOCallback(client->sock,
mode,
virNetServerClientDispatchEvent,
client) < 0)
client,
virNetServerClientEventFree) < 0) {
client->refs--;
return -1;
}
return 0;
}

View File

@ -91,6 +91,14 @@ error:
}
static void virNetServerServiceEventFree(void *opaque)
{
virNetServerServicePtr svc = opaque;
virNetServerServiceFree(svc);
}
virNetServerServicePtr virNetServerServiceNewTCP(const char *nodename,
const char *service,
int auth,
@ -124,11 +132,15 @@ virNetServerServicePtr virNetServerServiceNewTCP(const char *nodename,
/* IO callback is initially disabled, until we're ready
* to deal with incoming clients */
virNetServerServiceRef(svc);
if (virNetSocketAddIOCallback(svc->socks[i],
0,
virNetServerServiceAccept,
svc) < 0)
svc,
virNetServerServiceEventFree) < 0) {
virNetServerServiceFree(svc);
goto error;
}
}
@ -180,11 +192,15 @@ virNetServerServicePtr virNetServerServiceNewUNIX(const char *path,
/* IO callback is initially disabled, until we're ready
* to deal with incoming clients */
virNetServerServiceRef(svc);
if (virNetSocketAddIOCallback(svc->socks[i],
0,
virNetServerServiceAccept,
svc) < 0)
svc,
virNetServerServiceEventFree) < 0) {
virNetServerServiceFree(svc);
goto error;
}
}

View File

@ -58,8 +58,12 @@ struct _virNetSocket {
pid_t pid;
int errfd;
bool client;
/* Event callback fields */
virNetSocketIOFunc func;
void *opaque;
virFreeCallback ff;
virSocketAddr localAddr;
virSocketAddr remoteAddr;
char *localAddrStr;
@ -1121,10 +1125,31 @@ static void virNetSocketEventHandle(int watch ATTRIBUTE_UNUSED,
}
static void virNetSocketEventFree(void *opaque)
{
virNetSocketPtr sock = opaque;
virFreeCallback ff;
void *eopaque;
virMutexLock(&sock->lock);
ff = sock->ff;
eopaque = sock->opaque;
sock->func = NULL;
sock->ff = NULL;
sock->opaque = NULL;
virMutexUnlock(&sock->lock);
if (ff)
ff(eopaque);
virNetSocketFree(sock);
}
int virNetSocketAddIOCallback(virNetSocketPtr sock,
int events,
virNetSocketIOFunc func,
void *opaque)
void *opaque,
virFreeCallback ff)
{
int ret = -1;
@ -1134,16 +1159,19 @@ int virNetSocketAddIOCallback(virNetSocketPtr sock,
goto cleanup;
}
sock->refs++;
if ((sock->watch = virEventAddHandle(sock->fd,
events,
virNetSocketEventHandle,
sock,
NULL)) < 0) {
virNetSocketEventFree)) < 0) {
VIR_DEBUG("Failed to register watch on socket %p", sock);
sock->refs--;
goto cleanup;
}
sock->func = func;
sock->opaque = opaque;
sock->ff = ff;
ret = 0;

View File

@ -109,7 +109,8 @@ int virNetSocketAccept(virNetSocketPtr sock,
int virNetSocketAddIOCallback(virNetSocketPtr sock,
int events,
virNetSocketIOFunc func,
void *opaque);
void *opaque,
virFreeCallback ff);
void virNetSocketUpdateIOCallback(virNetSocketPtr sock,
int events);