static int testSocketTCPAccept(const void *opaque) { virNetSocketPtr *lsock = NULL; /* Listen socket */ size_t nlsock = 0, i; virNetSocketPtr ssock = NULL; /* Server socket */ virNetSocketPtr csock = NULL; /* Client socket */ const struct testTCPData *data = opaque; int ret = -1; char portstr[100]; snprintf(portstr, sizeof(portstr), "%d", data->port); if (virNetSocketNewListenTCP(data->lnode, portstr, &lsock, &nlsock) < 0) goto cleanup; for (i = 0 ; i < nlsock ; i++) { if (virNetSocketListen(lsock[i], 0) < 0) goto cleanup; } if (virNetSocketNewConnectTCP(data->cnode, portstr, &csock) < 0) goto cleanup; virNetSocketFree(csock); for (i = 0 ; i < nlsock ; i++) { if (virNetSocketAccept(lsock[i], &ssock) != -1 && ssock) { char c = 'a'; if (virNetSocketWrite(ssock, &c, 1) != -1 && virNetSocketRead(ssock, &c, 1) != -1) { VIR_DEBUG("Unexpected client socket present"); goto cleanup; } } virNetSocketFree(ssock); ssock = NULL; } ret = 0; cleanup: virNetSocketFree(ssock); for (i = 0 ; i < nlsock ; i++) virNetSocketFree(lsock[i]); VIR_FREE(lsock); return ret; }
void virNetClientClose(virNetClientPtr client) { if (!client) return; virNetClientLock(client); virNetSocketRemoveIOCallback(client->sock); virNetSocketFree(client->sock); client->sock = NULL; virNetTLSSessionFree(client->tls); client->tls = NULL; #if HAVE_SASL virNetSASLSessionFree(client->sasl); client->sasl = NULL; #endif virNetClientUnlock(client); }
void virNetServerServiceFree(virNetServerServicePtr svc) { int i; if (!svc) return; svc->refs--; if (svc->refs > 0) return; for (i = 0 ; i < svc->nsocks ; i++) virNetSocketFree(svc->socks[i]); VIR_FREE(svc->socks); virNetTLSContextFree(svc->tls); VIR_FREE(svc); }
static void virNetServerServiceAccept(virNetSocketPtr sock, int events ATTRIBUTE_UNUSED, void *opaque) { virNetServerServicePtr svc = opaque; virNetServerClientPtr client = NULL; virNetSocketPtr clientsock = NULL; if (virNetSocketAccept(sock, &clientsock) < 0) goto error; if (!clientsock) /* Connection already went away */ goto cleanup; if (!(client = virNetServerClientNew(clientsock, svc->auth, svc->readonly, svc->nrequests_client_max, svc->tls))) goto error; if (!svc->dispatchFunc) goto error; if (svc->dispatchFunc(svc, client, svc->dispatchOpaque) < 0) virNetServerClientClose(client); virNetServerClientFree(client); cleanup: return; error: if (client) { virNetServerClientClose(client); virNetServerClientFree(client); } else { virNetSocketFree(clientsock); } }
void virNetClientFree(virNetClientPtr client) { int i; if (!client) return; virNetClientLock(client); PROBE(RPC_CLIENT_FREE, "client=%p refs=%d", client, client->refs); client->refs--; if (client->refs > 0) { virNetClientUnlock(client); return; } for (i = 0 ; i < client->nprograms ; i++) virNetClientProgramFree(client->programs[i]); VIR_FREE(client->programs); VIR_FORCE_CLOSE(client->wakeupSendFD); VIR_FORCE_CLOSE(client->wakeupReadFD); VIR_FREE(client->hostname); if (client->sock) virNetSocketRemoveIOCallback(client->sock); virNetSocketFree(client->sock); virNetTLSSessionFree(client->tls); #if HAVE_SASL virNetSASLSessionFree(client->sasl); #endif virNetClientUnlock(client); virMutexDestroy(&client->lock); VIR_FREE(client); }
int virNetSocketNewListenTCP(const char *nodename, const char *service, virNetSocketPtr **retsocks, size_t *nretsocks) { virNetSocketPtr *socks = NULL; size_t nsocks = 0; struct addrinfo *ai = NULL; struct addrinfo hints; int fd = -1; int i; int addrInUse = false; *retsocks = NULL; *nretsocks = 0; memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; int e = getaddrinfo(nodename, service, &hints, &ai); if (e != 0) { virNetError(VIR_ERR_SYSTEM_ERROR, _("Unable to resolve address '%s' service '%s': %s"), nodename, service, gai_strerror(e)); return -1; } struct addrinfo *runp = ai; while (runp) { virSocketAddr addr; memset(&addr, 0, sizeof(addr)); if ((fd = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol)) < 0) { virReportSystemError(errno, "%s", _("Unable to create socket")); goto error; } int opt = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) < 0) { virReportSystemError(errno, "%s", _("Unable to enable port reuse")); goto error; } #ifdef IPV6_V6ONLY if (runp->ai_family == PF_INET6) { int on = 1; /* * Normally on Linux an INET6 socket will bind to the INET4 * address too. If getaddrinfo returns results with INET4 * first though, this will result in INET6 binding failing. * We can trivially cope with multiple server sockets, so * we force it to only listen on IPv6 */ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&on, sizeof on) < 0) { virReportSystemError(errno, "%s", _("Unable to force bind to IPv6 only")); goto error; } } #endif if (bind(fd, runp->ai_addr, runp->ai_addrlen) < 0) { if (errno != EADDRINUSE) { virReportSystemError(errno, "%s", _("Unable to bind to port")); goto error; } addrInUse = true; VIR_FORCE_CLOSE(fd); runp = runp->ai_next; continue; } addr.len = sizeof(addr.data); if (getsockname(fd, &addr.data.sa, &addr.len) < 0) { virReportSystemError(errno, "%s", _("Unable to get local socket name")); goto error; } VIR_DEBUG("%p f=%d f=%d", &addr, runp->ai_family, addr.data.sa.sa_family); if (VIR_EXPAND_N(socks, nsocks, 1) < 0) { virReportOOMError(); goto error; } if (!(socks[nsocks-1] = virNetSocketNew(&addr, NULL, false, fd, -1, 0))) goto error; runp = runp->ai_next; fd = -1; } if (nsocks == 0 && addrInUse) { virReportSystemError(EADDRINUSE, "%s", _("Unable to bind to port")); goto error; } freeaddrinfo(ai); *retsocks = socks; *nretsocks = nsocks; return 0; error: for (i = 0 ; i < nsocks ; i++) virNetSocketFree(socks[i]); VIR_FREE(socks); freeaddrinfo(ai); VIR_FORCE_CLOSE(fd); return -1; }
static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr, virSocketAddrPtr remoteAddr, bool isClient, int fd, int errfd, pid_t pid) { virNetSocketPtr sock; int no_slow_start = 1; VIR_DEBUG("localAddr=%p remoteAddr=%p fd=%d errfd=%d pid=%d", localAddr, remoteAddr, fd, errfd, pid); if (virSetCloseExec(fd) < 0) { virReportSystemError(errno, "%s", _("Unable to set close-on-exec flag")); return NULL; } if (virSetNonBlock(fd) < 0) { virReportSystemError(errno, "%s", _("Unable to enable non-blocking flag")); return NULL; } if (VIR_ALLOC(sock) < 0) { virReportOOMError(); return NULL; } if (virMutexInit(&sock->lock) < 0) { virReportSystemError(errno, "%s", _("Unable to initialize mutex")); VIR_FREE(sock); return NULL; } sock->refs = 1; if (localAddr) sock->localAddr = *localAddr; if (remoteAddr) sock->remoteAddr = *remoteAddr; sock->fd = fd; sock->errfd = errfd; sock->pid = pid; /* Disable nagle for TCP sockets */ if (sock->localAddr.data.sa.sa_family == AF_INET || sock->localAddr.data.sa.sa_family == AF_INET6) { if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &no_slow_start, sizeof(no_slow_start)) < 0) { virReportSystemError(errno, "%s", _("Unable to disable nagle algorithm")); goto error; } } if (localAddr && !(sock->localAddrStr = virSocketFormatAddrFull(localAddr, true, ";"))) goto error; if (remoteAddr && !(sock->remoteAddrStr = virSocketFormatAddrFull(remoteAddr, true, ";"))) goto error; sock->client = isClient; PROBE(RPC_SOCKET_NEW, "sock=%p refs=%d fd=%d errfd=%d pid=%d localAddr=%s, remoteAddr=%s", sock, sock->refs, fd, errfd, pid, NULLSTR(sock->localAddrStr), NULLSTR(sock->remoteAddrStr)); return sock; error: sock->fd = sock->errfd = -1; /* Caller owns fd/errfd on failure */ virNetSocketFree(sock); return NULL; }