Example #1
1
/*
 * Create socket for incoming connections and bind to it an address for
 * clients to use.  Returns -1 on failure.
 *
 * If '*family' is AF_UNIX and unix domain sockets are supported:
 * 'port' is ignored and 'address' is the path to the socket file in the filesystem.
 *
 * Otherwise:
 * address is a string representing the Inet/IPv6 address that the port
 * is advertised for.  To allow connections to all this host's internet
 * addresses from clients use address == "INADDR_ANY", or for localhost
 * access only use address == "INADDR_LOOPBACK".
 * On input, 'family' is a pointer to the address family to use (AF_INET,
 * AF_INET6) if the address specified is empty.  If the spec is not
 * empty then family is ignored and is set to the actual address family
 * used. 'family' must be initialized to AF_UNSPEC, in this case.
 */
static int
OpenRequestSocket(int port, const char *address, int *family,
		  int backlog, __pmFdSet *fdset, int *maximum)
{
    int			fd = -1;
    int			one, sts;
    __pmSockAddr	*myAddr;
    int			isUnix = 0;

    /*
     * Using this flag will eliminate the need for more conditional
     * compilation below, hopefully making the code easier to read and maintain.
     */
#if defined(HAVE_STRUCT_SOCKADDR_UN)
    if (*family == AF_UNIX)
	isUnix = 1;
#endif

    if (isUnix) {
	if ((myAddr = __pmSockAddrAlloc()) == NULL) {
	    __pmNoMem("OpenRequestSocket: can't allocate socket address",
		      sizeof(*myAddr), PM_FATAL_ERR);
	}

	/* Initialize the address. */
	__pmSockAddrSetFamily(myAddr, *family);
	__pmSockAddrSetPath(myAddr, address);

	/* Create the socket. */
	fd = __pmCreateUnixSocket();
    }
    else {
	/*
	 * If the address is unspecified, then use the address family we
	 * have been given, otherwise the family will be determined by
	 * __pmStringToSockAddr.
	 */
	if (address == NULL || strcmp(address, "INADDR_ANY") == 0) {
	    if ((myAddr = __pmSockAddrAlloc()) == NULL) {
		__pmNoMem("OpenRequestSocket: can't allocate socket address",
			  sizeof(*myAddr), PM_FATAL_ERR);
	    }
	    __pmSockAddrInit(myAddr, *family, INADDR_ANY, 0);
	}
	else if (strcmp(address, "INADDR_LOOPBACK") == 0) {
	    if ((myAddr = __pmSockAddrAlloc()) == NULL) {
		__pmNoMem("OpenRequestSocket: can't allocate socket address",
			  sizeof(*myAddr), PM_FATAL_ERR);
	    }
	    __pmSockAddrInit(myAddr, *family, INADDR_LOOPBACK, 0);
	}
	else {
	    if ((myAddr = __pmStringToSockAddr(address)) == NULL) {
		__pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s) invalid address\n",
			      port, address);
		goto fail;
	    }
	    *family = __pmSockAddrGetFamily(myAddr);
	}
	__pmSockAddrSetPort(myAddr, port);

	/* Create the socket. */
	if (*family == AF_INET)
	    fd = __pmCreateSocket();
	else if (*family == AF_INET6)
	    fd = __pmCreateIPv6Socket();
	else {
	    __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s) invalid address family: %d\n",
			  port, address, *family);
	    goto fail;
	}
    }

    if (fd < 0) {
	__pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmCreateSocket: %s\n",
		port, address, AddressFamily(*family), netstrerror());
	goto fail;
    }

    /* Ignore dead client connections. */
    one = 1;
#ifndef IS_MINGW
    if (__pmSetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one,
		       (__pmSockLen)sizeof(one)) < 0) {
	__pmNotifyErr(LOG_ERR,
		      "OpenRequestSocket(%d, %s, %s) __pmSetSockOpt(SO_REUSEADDR): %s\n",
		      port, address, AddressFamily(*family), netstrerror());
	goto fail;
    }
#else
    if (__pmSetSockOpt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&one,
		       (__pmSockLen)sizeof(one)) < 0) {
	__pmNotifyErr(LOG_ERR,
		      "OpenRequestSocket(%d, %s, %s) __pmSetSockOpt(EXCLUSIVEADDRUSE): %s\n",
		      port, address, AddressFamily(*family), netstrerror());
	goto fail;
    }
#endif

    /* and keep alive please - bad networks eat fds */
    if (__pmSetSockOpt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one,
		(__pmSockLen)sizeof(one)) < 0) {
	__pmNotifyErr(LOG_ERR,
		"OpenRequestSocket(%d, %s, %s) __pmSetSockOpt(SO_KEEPALIVE): %s\n",
		port, address, AddressFamily(*family), netstrerror());
	goto fail;
    }

    sts = __pmBind(fd, (void *)myAddr, __pmSockAddrSize());
    __pmSockAddrFree(myAddr);
    myAddr = NULL;
    if (sts < 0) {
	sts = neterror();
	__pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmBind: %s\n",
		port, address, AddressFamily(*family), netstrerror());
	if (sts == EADDRINUSE)
	    __pmNotifyErr(LOG_ERR, "%s may already be running\n", pmProgname);
	goto fail;
    }

    if (isUnix) {
	/*
	 * For unix domain sockets, grant rw access to the socket for all,
	 * otherwise, on linux platforms, connection will not be possible.
	 * This must be done AFTER binding the address. See Unix(7) for details.
	 */
	sts = chmod(address, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
	if (sts != 0) {
	    __pmNotifyErr(LOG_ERR,
		"OpenRequestSocket(%d, %s, %s) chmod(%s): %s\n",
		port, address, AddressFamily(*family), address, strerror(errno));
	    goto fail;
	}
    }

    sts = __pmListen(fd, backlog);	/* Max. pending connection requests */
    if (sts < 0) {
	__pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmListen: %s\n",
		port, address, AddressFamily(*family), netstrerror());
	goto fail;
    }

    if (fd > *maximum)
	*maximum = fd;
    __pmFD_SET(fd, fdset);
    return fd;

fail:
    if (fd != -1) {
        __pmCloseSocket(fd);
	/* We must unlink the socket file. */
	if (isUnix)
	    unlink(address);
    }
    if (myAddr)
        __pmSockAddrFree(myAddr);
    return -1;
}
Example #2
0
File: root.c Project: rwongone/pcp
/*
 * Connect to the pmdaroot socket as a client, perform version exchange
 */
int
pmdaRootConnect(const char *path)
{
    __pmSockAddr	*addr;
    char		*tmpdir;
    char		socketpath[MAXPATHLEN];
    char		errmsg[PM_MAXERRMSGLEN];
    int			fd, sts, version, features;

    /* Initialize the socket address. */
    if ((addr = __pmSockAddrAlloc()) == NULL)
	return -ENOMEM;

    if (path == NULL) {
	if ((tmpdir = pmGetOptionalConfig("PCP_TMP_DIR")) == NULL) {
	    __pmSockAddrFree(addr);
	    return PM_ERR_GENERIC;
	}
	snprintf(socketpath, sizeof(socketpath), "%s/pmcd/root.socket", tmpdir);
    } else
	strncpy(socketpath, path, sizeof(socketpath));
    socketpath[sizeof(socketpath)-1] = '\0';

    __pmSockAddrSetFamily(addr, AF_UNIX);
    __pmSockAddrSetPath(addr, socketpath);

    /* Create client socket connection */
    if ((fd = __pmCreateUnixSocket()) < 0) {
	__pmNotifyErr(LOG_ERR, "pmdaRootConnect: cannot create socket %s: %s\n",
			socketpath, osstrerror_r(errmsg, sizeof(errmsg)));
	__pmSockAddrFree(addr);
	return fd;
    }

    sts = __pmConnect(fd, addr, -1);
    __pmSockAddrFree(addr);
    if (sts < 0) {
	if (sts != -EPERM || (pmDebug & DBG_TRACE_LIBPMDA))
	    __pmNotifyErr(LOG_INFO,
			"pmdaRootConnect: cannot connect to %s: %s\n",
			socketpath, osstrerror_r(errmsg, sizeof(errmsg)));
	__pmCloseSocket(fd);
	return sts;
    }

    /* Check server connection information */
    if ((sts = __pmdaRecvRootPDUInfo(fd, &version, &features)) < 0) {
	__pmNotifyErr(LOG_ERR,
			"pmdaRootConnect: cannot verify %s server: %s\n",
			socketpath, pmErrStr_r(sts, errmsg, sizeof(errmsg)));
	__pmCloseSocket(fd);
	return sts;
    }

    if (pmDebug & DBG_TRACE_LIBPMDA)
	__pmNotifyErr(LOG_INFO,
		"pmdaRootConnect: %s server fd=%d version=%d features=0x%x\n",
			socketpath, fd, version, features);
    return fd;
}
Example #3
0
void
__pmServerCloseRequestPorts(void)
{
    int i, fd;

    for (i = 0; i < nReqPorts; i++) {
	/* No longer advertise our presence on the network. */
	if (reqPorts[i].presence != NULL)
	    __pmServerUnadvertisePresence(reqPorts[i].presence);
	if ((fd = reqPorts[i].fds[INET_FD]) >= 0)
	    __pmCloseSocket(fd);
	if ((fd = reqPorts[i].fds[IPV6_FD]) >= 0)
	    __pmCloseSocket(fd);
    }
#if defined(HAVE_STRUCT_SOCKADDR_UN)
    if (localSocketFd >= 0) {
        __pmCloseSocket(localSocketFd);
	localSocketFd = -EPROTO;

	/* We must remove the socket file. */
	if (unlink(localSocketPath) != 0 && oserror() != ENOENT) {
	    char	errmsg[PM_MAXERRMSGLEN];
	    __pmNotifyErr(LOG_ERR, "%s: can't unlink %s (uid=%d,euid=%d): %s",
			  pmProgname, localSocketPath, getuid(), geteuid(),
			  osstrerror_r(errmsg, sizeof(errmsg)));
	}
    }
#endif
}
Example #4
0
void
DeleteClient(ClientInfo *cp)
{
    int		i;

    for (i = 0; i < nClients; i++)
	if (cp == &client[i])
	    break;

    if (i == nClients) {
	fprintf(stderr, "DeleteClient: Botch: tried to delete non-existent client @" PRINTF_P_PFX "%p\n", cp);
	return;
    }

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_CONTEXT)
	fprintf(stderr, "DeleteClient [%d]\n", i);
#endif

    if (cp->fd >= 0) {
	__pmFD_CLR(cp->fd, &sockFds);
	__pmCloseSocket(cp->fd);
    }
    if (cp->pmcd_fd >= 0) {
	__pmFD_CLR(cp->pmcd_fd, &sockFds);
	__pmCloseSocket(cp->pmcd_fd);
    }
    if (i == nClients-1) {
	i--;
	while (i >= 0 && !client[i].status.connected)
	    i--;
	nClients = (i >= 0) ? i + 1 : 0;
    }
    if (cp->fd == maxSockFd || cp->pmcd_fd == maxSockFd) {
	maxSockFd = maxReqPortFd;
	for (i = 0; i < nClients; i++) {
	    if (cp->status.connected == 0)
		continue;
	    if (client[i].fd > maxSockFd)
		maxSockFd = client[i].fd;
	    if (client[i].pmcd_fd > maxSockFd)
		maxSockFd = client[i].pmcd_fd;
	}
    }
    __pmSockAddrFree(cp->addr);
    cp->addr = NULL;
    cp->status.connected = 0;
    cp->fd = -1;
    cp->pmcd_fd = -1;
    if (cp->pmcd_hostname != NULL) {
	free(cp->pmcd_hostname);
	cp->pmcd_hostname = NULL;
    }
}
Example #5
0
static void
http_client_disconnect(http_client *cp)
{
    if (cp->fd != -1)
	__pmCloseSocket(cp->fd);
    cp->fd = -1;
}
Example #6
0
void
Shutdown(void)
{
    int	i;

    for (i = 0; i < nAgents; i++) {
	AgentInfo *ap = &agent[i];
	if (!ap->status.connected)
	    continue;
	if (ap->inFd != -1) {
	    if (__pmSocketIPC(ap->inFd))
		__pmCloseSocket(ap->inFd);
	    else
		close(ap->inFd);
	}
	if (ap->outFd != -1) {
	    if (__pmSocketIPC(ap->outFd))
		__pmCloseSocket(ap->outFd);
	    else
		close(ap->outFd);
	}
	if (ap->ipcType == AGENT_SOCKET &&
	    ap->ipc.socket.addrDomain == AF_UNIX) {
	    /* remove the Unix domain socket */
	    unlink(ap->ipc.socket.name);
	}
    }
    if (HarvestAgents(SHUTDOWNWAIT) < 0) {
	/* terminate with prejudice any still remaining */
	for (i = 0; i < nAgents; i++) {
	    AgentInfo *ap = &agent[i];
	    if (ap->status.connected) {
		pid_t pid = ap->ipcType == AGENT_SOCKET ?
			    ap->ipc.socket.agentPid : ap->ipc.pipe.agentPid;
		__pmProcessTerminate(pid, 1);
	    }
	}
    }
    for (i = 0; i < nClients; i++)
	if (client[i].status.connected)
	    __pmCloseSocket(client[i].fd);
    __pmServerCloseRequestPorts();
    __pmSecureServerShutdown();
    __pmNotifyErr(LOG_INFO, "pmcd Shutdown\n");
    fflush(stderr);
}
Example #7
0
/* Called to shutdown pmproxy in an orderly manner */
void
Shutdown(void)
{
    int	i;

    for (i = 0; i < nClients; i++)
	if (client[i].status.connected)
	    __pmCloseSocket(client[i].fd);
    __pmServerCloseRequestPorts();
    __pmSecureServerShutdown();
    __pmNotifyErr(LOG_INFO, "pmproxy Shutdown\n");
    fflush(stderr);
}
Example #8
0
void
DeleteClient(ClientInfo *cp)
{
    int i;

    for (i = 0; i < nClients; i++)
        if (cp == &client[i])
            break;

    if (i == nClients) {
#ifdef PCP_DEBUG
        if (pmDebug & DBG_TRACE_APPL0) {
            __pmNotifyErr(LOG_ERR, "DeleteClient: tried to delete non-existent client\n");
            Shutdown();
            exit(1);
        }
#endif
        return;
    }
    if (cp->fd != -1) {
        __pmFD_CLR(cp->fd, &clientFds);
        __pmCloseSocket(cp->fd);
    }
    if (i == nClients-1) {
        i--;
        while (i >= 0 && !client[i].status.connected)
            i--;
        nClients = (i >= 0) ? i + 1 : 0;
    }
    if (cp->fd == maxClientFd) {
        maxClientFd = -1;
        for (i = 0; i < nClients; i++) {
            if (client[i].fd > maxClientFd)
                maxClientFd = client[i].fd;
        }
    }
    for (i = 0; i < cp->szProfile; i++) {
        if (cp->profile[i] != NULL) {
            __pmFreeProfile(cp->profile[i]);
            cp->profile[i] = NULL;
        }
    }
    __pmFreeAttrsSpec(&cp->attrs);
    __pmHashClear(&cp->attrs);
    __pmSockAddrFree(cp->addr);
    cp->addr = NULL;
    cp->status.connected = 0;
    cp->fd = -1;

    NotifyEndContext(cp-client);
}
Example #9
0
static void
ShutdownAgent(AgentInfo *ap)
{
    if (!ap->status.connected)
	return;
    if (ap->inFd != -1) {
	if (__pmSocketIPC(ap->inFd))
	    __pmCloseSocket(ap->inFd);
	else
	    close(ap->inFd);
    }
    if (ap->outFd != -1) {
	if (__pmSocketIPC(ap->outFd))
	    __pmCloseSocket(ap->outFd);
	else
	    close(ap->outFd);
    }
    if (ap->ipcType == AGENT_SOCKET &&
	ap->ipc.socket.addrDomain == AF_UNIX) {
	/* remove the Unix domain socket */
	unlink(ap->ipc.socket.name);
    }
}
Example #10
0
void
Shutdown(void)
{
    AgentInfo	*ap, *root = NULL;
    int		i;

    for (i = 0; i < nAgents; i++) {
	ap = &agent[i];
	if (ap->pmDomainId == PMDAROOT)
	    root = ap;
	if (ap->status.isRootChild)
	    ShutdownAgent(ap);
    }
    for (i = 0; i < nAgents; i++) {
	ap = &agent[i];
	if (ap->pmDomainId == PMDAROOT)
	    continue;
	if (!ap->status.isRootChild)
	    ShutdownAgent(ap);
    }
    if (HarvestAgents(SHUTDOWNWAIT) < 0) {
	/* terminate with prejudice any still remaining non-root PMDAs */
	for (i = 0; i < nAgents; i++) {
	    ap = &agent[i];
	    if (ap == root)
		continue;
	    TerminateAgent(ap);
	}
    }
    if (root) {
	TerminateAgent(root);
	ShutdownAgent(root);
	HarvestAgents(0);
    }
    for (i = 0; i < nClients; i++) {
	if (client[i].status.connected)
	    __pmCloseSocket(client[i].fd);
    }
    __pmServerCloseRequestPorts();
    __pmSecureServerShutdown();
    __pmNotifyErr(LOG_INFO, "pmcd Shutdown\n");
    fflush(stderr);
}
Example #11
0
File: trace.c Project: tongfw/pcp
static int
_pmtracereconnect(void)
{
#ifdef PMTRACE_DEBUG
    if (__pmstate & PMTRACE_STATE_NOAGENT) {
	fprintf(stderr, "_pmtracereconnect: reconnect attempt (skipped)\n");
	return 0;
    }
    else if (__pmstate &  PMTRACE_STATE_COMMS) {
	fprintf(stderr, "_pmtracereconnect: attempting PMDA reconnection\n");
    }
#endif

    if (_pmtimedout && time(NULL) < _pmttimeout) {	/* too soon to retry */
#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS)
	    fprintf(stderr, "_pmtracereconnect: too soon to retry "
			    "(%d seconds remain)\n", (int)(_pmttimeout - time(NULL)));
#endif
	return -ETIMEDOUT;
    }
    if (__pmfd >= 0) {
	__pmtracenomoreinput(__pmfd);
	__pmCloseSocket(__pmfd);
	__pmfd = -1;
    }
    if (_pmtraceconnect(1) < 0) {
#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS)
	    fprintf(stderr, "_pmtracereconnect: failed to reconnect\n");
#endif
	_pmtraceupdatewait();
	return -ETIMEDOUT;
    }
    else {
#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS)
	    fprintf(stderr, "_pmtracereconnect: reconnect succeeded!\n");
#endif
	_pmtimedout = 0;
    }
    return 0;
}
Example #12
0
	/*
	 * Opens a TCP socket and returns the descriptor
	 * Returns:
	 *	socket descriptor, or
	 *	-1 on error
	 */
int makeSocket(const char *host)
	{
	int sock;										/* Socket descriptor */
	int ret;
	int port;
	char *p;
	__pmFdSet wfds;
	struct timeval tv;
	struct timeval	*ptv;
	__pmSockAddr *myaddr;
	__pmHostEnt *servInfo;
	void *enumIx;
	int flags = 0;
	
	/* Check for port number specified in URL */
	p = strchr(host, ':');
	if(p)
	    {
		port = atoi(p + 1);
		*p = '\0';
	    }
	else
	    port = PORT_NUMBER;

	servInfo = __pmGetAddrInfo(host);
	if(servInfo == NULL) { errorSource = H_ERRNO; return -1; }

	sock = -1;
	enumIx = NULL;
	for (myaddr = __pmHostEntGetSockAddr(servInfo, &enumIx);
	     myaddr != NULL;
	     myaddr = __pmHostEntGetSockAddr(servInfo, &enumIx)) {
	    /* Create a socket */
	    if (__pmSockAddrIsInet(myaddr))
		sock = __pmCreateSocket();
	    else if (__pmSockAddrIsIPv6(myaddr))
		sock = __pmCreateIPv6Socket();
	    else
		sock = -1;

	    if (sock < 0) {
		__pmSockAddrFree(myaddr);
		continue; /* Try the next address */
	    }

	    /* Attempt to connect */
	    flags = __pmConnectTo(sock, myaddr, port);
	    __pmSockAddrFree(myaddr);

	    if (flags < 0) {
		/*
		 * Mark failure in case we fall out the end of the loop
		 * and try next address. sock has been closed in __pmConnectTo().
		 */
		sock = -1;
		continue;
	    }

	    /* FNDELAY and we're in progress - wait on select */
	    tv.tv_sec = timeout;
	    tv.tv_usec = 0;
	    ptv = (tv.tv_sec || tv.tv_usec) ? &tv : NULL;
	    __pmFD_ZERO(&wfds);
	    __pmFD_SET(sock, &wfds);
	    ret = __pmSelectWrite(sock+1, &wfds, ptv);

	    /* Was the connection successful? */
	    if (ret < 0) {
		if (oserror() == EINTR)
		    return _makeSocketErr(sock, FETCHER_ERROR, HF_CONNECTTIMEOUT);
		return _makeSocketErr(sock, ERRNO, 0);
	    }
	    ret = __pmConnectCheckError(sock);
	    if (ret == 0)
		break;

	    /* Unsuccessful connection. */
	    __pmCloseSocket(sock);
	    sock = -1;
	} /* loop over addresses */

	__pmHostEntFree(servInfo);

	if(sock == -1) { errorSource = ERRNO; return -1; }

	sock = __pmConnectRestoreFlags(sock, flags);
	if(sock < 0) { errorSource = ERRNO; return -1; }

	return sock;
	}
Example #13
0
void
CleanupAgent(AgentInfo* aPtr, int why, int status)
{
    int		exit_status = status;
    int		reason = 0;

    if (aPtr->ipcType == AGENT_DSO) {
	if (aPtr->ipc.dso.dlHandle != NULL) {
#ifdef HAVE_DLOPEN
	    dlclose(aPtr->ipc.dso.dlHandle);
#endif
	}
	pmcd_trace(TR_DEL_AGENT, aPtr->pmDomainId, -1, -1);
    }
    else {
	pmcd_trace(TR_DEL_AGENT, aPtr->pmDomainId, aPtr->inFd, aPtr->outFd);
	if (aPtr->inFd != -1) {
	    if (aPtr->ipcType == AGENT_SOCKET)
	      __pmCloseSocket(aPtr->inFd);
	    else {
	      close(aPtr->inFd);
	      __pmResetIPC(aPtr->inFd);
	    }
	    aPtr->inFd = -1;
	}
	if (aPtr->outFd != -1) {
	    if (aPtr->ipcType == AGENT_SOCKET)
	      __pmCloseSocket(aPtr->outFd);
	    else {
	      close(aPtr->outFd);
	      __pmResetIPC(aPtr->outFd);
	    }
	    aPtr->outFd = -1;
	}
	if (aPtr->ipcType == AGENT_SOCKET &&
	    aPtr->ipc.socket.addrDomain == AF_UNIX) {
	    /* remove the Unix domain socket */
	    unlink(aPtr->ipc.socket.name);
	}
    }

    __pmNotifyErr(LOG_INFO, "CleanupAgent ...\n");
    fprintf(stderr, "Cleanup \"%s\" agent (dom %d):", aPtr->pmDomainLabel, aPtr->pmDomainId);

    if (why == AT_EXIT) {
	/* waitpid has already been done */
	fprintf(stderr, " terminated");
	reason = (status << 8) | REASON_EXIT;
    }
    else {
	if (why == AT_CONFIG) {
	    fprintf(stderr, " unconfigured");
	} else {
	    reason = REASON_PROTOCOL;
	    fprintf(stderr, " protocol failure for fd=%d", status);
	    exit_status = -1;
	}
	if (aPtr->status.isChild || aPtr->status.isRootChild) {
	    pid_t	pid = (pid_t)-1;
	    pid_t	done;
	    int 	wait_status;
	    int 	slept = 0;

	    if (aPtr->ipcType == AGENT_PIPE)
		pid = aPtr->ipc.pipe.agentPid;
	    else if (aPtr->ipcType == AGENT_SOCKET)
		pid = aPtr->ipc.socket.agentPid;
	    for ( ; ; ) {
		done = (aPtr->status.isRootChild) ?
			waitpid_pmdaroot(&wait_status):
			waitpid_pmcd(&wait_status);
		if (done < (pid_t)0)
		    wait_status = 0;
		else if (done == pid) {
		    exit_status = wait_status;
		    break;
		}
		else if (done > 0)
		    continue;
		if (slept)
		    break;
		/* give PMDA a chance to notice the close() and exit */
		short_delay(10);
		slept = 1;
	    }
	}
    }
#ifndef IS_MINGW
    if (exit_status != -1) {
	if (WIFEXITED(exit_status)) {
	    fprintf(stderr, ", exit(%d)", WEXITSTATUS(exit_status));
	    reason = (WEXITSTATUS(exit_status) << 8) | reason;
	}
	else if (WIFSIGNALED(exit_status)) {
	    fprintf(stderr, ", signal(%d)", WTERMSIG(exit_status));
#ifdef WCOREDUMP
	    if (WCOREDUMP(exit_status))
		fprintf(stderr, ", dumped core");
#endif
	    reason = (WTERMSIG(exit_status) << 16) | reason;
	}
    }
#endif
    fputc('\n', stderr);
    aPtr->reason = reason;
    aPtr->status.connected = 0;
    aPtr->status.busy = 0;
    aPtr->status.notReady = 0;
    aPtr->status.flags = 0;
    AgentDied = 1;

    if (_pmcd_trace_mask)
	pmcd_dump_trace(stderr);

    MarkStateChanges(PMCD_DROP_AGENT);
}
Example #14
0
static int
http_client_connectunix(const char *path, struct timeval *timeout)
{
#if defined(HAVE_STRUCT_SOCKADDR_UN)
    __pmFdSet		wfds;
    __pmSockAddr	*myAddr;
    struct timeval	stv, *ptv;
    int			fdFlags = 0;
    int			fd = -1;
    int			sts;
    int			rc;

    /* Initialize the socket address. */
    if ((myAddr = __pmSockAddrAlloc()) == NULL) {
	if (pmDebug & DBG_TRACE_HTTP)
	    fprintf(stderr, "HTTP connect unix(%s): out of memory\n", path);
	return -ENOMEM;
    }
    __pmSockAddrSetFamily(myAddr, AF_UNIX);
    __pmSockAddrSetPath(myAddr, path);

    if ((fd = __pmCreateUnixSocket()) < 0) {
	if (pmDebug & DBG_TRACE_HTTP) {
	    char	errmsg[PM_MAXERRMSGLEN];
	    fprintf(stderr, "HTTP connect unix(%s) unable to create socket: %s\n",
		    path, osstrerror_r(errmsg, sizeof(errmsg)));
	}
	__pmSockAddrFree(myAddr);
	return fd;
    }

    /* Attempt to connect */
    fdFlags = __pmConnectTo(fd, myAddr, -1);
    __pmSockAddrFree(myAddr);
    if (fdFlags < 0) {
	__pmCloseSocket(fd);
	return -ECONNREFUSED;
    }

    /* FNDELAY and we're in progress - wait on select */
    stv = *timeout;
    ptv = (stv.tv_sec || stv.tv_usec) ? &stv : NULL;
    __pmFD_ZERO(&wfds);
    __pmFD_SET(fd, &wfds);
    sts = 0;
    if ((rc = __pmSelectWrite(fd+1, &wfds, ptv)) == 1)
	sts = __pmConnectCheckError(fd);
    else if (rc == 0)
	sts = ETIMEDOUT;
    else
	sts = (rc < 0) ? neterror() : EINVAL;

    if (sts != 0) {
	/* Unsuccessful connection. */
	if (sts == ENOENT)
	    sts = ECONNREFUSED;
	__pmCloseSocket(fd);
	fd = -sts;
    }

    if (fd < 0)
	return fd;

    /*
     * If we're here, it means we have a valid connection; restore the
     * flags and make sure this file descriptor is closed if exec() is
     * called
     */
    return __pmConnectRestoreFlags(fd, fdFlags);

#else
    if (pmDebug & DBG_TRACE_HTTP)
	__pmNotifyErr(LOG_ERR, "HTTP connect unix(%s) not supported\n", path);
    return -EOPNOTSUPP;
#endif
}
Example #15
0
static int
http_client_connectto(const char *host, int port, struct timeval *timeout)
{
    struct timeval	stv, *ptv;
    __pmHostEnt		*servInfo;
    __pmSockAddr	*myAddr;
    __pmFdSet		readyFds, allFds;
    void		*enumIx;
    int			fdFlags[FD_SETSIZE];
    int			i, fd, sts, maxFd;

    if ((servInfo = __pmGetAddrInfo(host)) == NULL) {
	if (pmDebug & DBG_TRACE_HTTP)
	    fprintf(stderr, "HTTP connect(%s, %d): hosterror=%d, ``%s''\n",
		    host, port, hosterror(), hoststrerror());
	return -EHOSTUNREACH;
    }
    /*
     * We want to respect the connect timeout that has been configured, but we
     * may have more than one address to try.  Do this by creating a socket for
     * each address and then using __pmSelectWrite() to wait for one of them to
     * respond.  That way, the timeout is applied to all of the addresses
     * simultaneously.  First, create the sockets, add them to the fd set and
     * try to establish connectections.
     */
    __pmFD_ZERO(&allFds);
    maxFd = -1;
    enumIx = NULL;
    for (myAddr = __pmHostEntGetSockAddr(servInfo, &enumIx);
	 myAddr != NULL;
	 myAddr = __pmHostEntGetSockAddr(servInfo, &enumIx)) {
	/* Create a socket */
	if (__pmSockAddrIsInet(myAddr))
	    fd = __pmCreateSocket();
	else if (__pmSockAddrIsIPv6(myAddr))
	    fd = __pmCreateIPv6Socket();
	else {
	    if (pmDebug & DBG_TRACE_HTTP)
		fprintf(stderr, "HTTP connect(%s, %d): bad address family %d\n",
			host, port, __pmSockAddrGetFamily(myAddr));
	    fd = -EINVAL;
	}
	if (fd < 0) {
	    __pmSockAddrFree(myAddr);
	    continue; /* Try the next address */
	}

	/* Attempt to connect */
	fdFlags[fd] = __pmConnectTo(fd, myAddr, port);
	__pmSockAddrFree(myAddr);
	if (fdFlags[fd] < 0) {
	    /*
	     * Mark failure in case we fall out the end of the loop
	     * and try next address
	     */
	    __pmCloseSocket(fd);
	    continue;
	}

	/* Add it to the fd set. */
	__pmFD_SET(fd, &allFds);
	if (fd > maxFd)
	    maxFd = fd;
    }
    __pmHostEntFree(servInfo);

    /* If we were unable to open any sockets, then give up. */
    if (maxFd == -1)
	return -ECONNREFUSED;

    /* FNDELAY and we're in progress - wait on select */
    __pmFD_COPY(&readyFds, &allFds);
    stv = *timeout;
    ptv = (stv.tv_sec || stv.tv_usec) ? &stv : NULL;
    sts = __pmSelectWrite(maxFd+1, &readyFds, ptv);

    /* Figure out what happened. */
    if (sts == 0)
	fd = -ETIMEDOUT;
    else if (sts < 0)
	fd = -neterror();
    else {
	/* Scan fd set, find first successfully connected socket (if any). */
	fd = -EINVAL;
	for (i = 0; i <= maxFd; ++i) {
	    if (__pmFD_ISSET(i, &readyFds)) {
		/* Successful connection? */
		sts = __pmConnectCheckError(i);
		if (sts == 0) {
		    fd = i;
		    break;
		}
		fd = -sts;
	    }
	}
    }

    /* Clean up the unused fds. */
    for (i = 0; i <= maxFd; ++i) {
	if (i != fd && __pmFD_ISSET(i, &allFds))
	    __pmCloseSocket(i);
    }

    if (fd < 0)
	return fd;

    /*
     * If we're here, it means we have a valid connection; restore the
     * flags and make sure this file descriptor is closed if exec() is
     * called
     */
    return __pmConnectRestoreFlags(fd, fdFlags[fd]);
}
Example #16
0
File: connect.c Project: tongfw/pcp
int
__pmConnectPMCD(pmHostSpec *hosts, int nhosts, int ctxflags, __pmHashCtl *attrs)
{
    int		sts = -1;
    int		fd = -1;	/* Fd for socket connection to pmcd */
    int		*ports;
    int		nports;
    int		portIx;
    int		version = -1;
    int		proxyport;
    pmHostSpec	*proxyhost;

    static int first_time = 1;
    static pmHostSpec proxy;

    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);
    if (first_time) {
	/*
	 * One-trip check for use of pmproxy(1) in lieu of pmcd(1),
	 * and to extract the optional environment variables ...
	 * PMCD_PORT, PMPROXY_HOST and PMPROXY_PORT.
	 * We also check for the presense of a certificate database
	 * and load it up if either a user or system (global) DB is
	 * found.
	 */
	first_time = 0;
	load_pmcd_ports();
	load_proxy_hostspec(&proxy);
    }

    if (hosts[0].nports == 0) {
	nports = global_nports;
	ports = global_portlist;
    }
    else {
	nports = hosts[0].nports;
	ports = hosts[0].ports;
    }

    if (proxy.name == NULL && nhosts == 1) {
	const char *name = (const char *)hosts[0].name;

	/*
	 * no proxy, connecting directly to pmcd
	 */
	PM_UNLOCK(__pmLock_libpcp);

	sts = -1;
	/* Try connecting via the local unix domain socket, if requested and supported. */
	if (nports == PM_HOST_SPEC_NPORTS_LOCAL || nports == PM_HOST_SPEC_NPORTS_UNIX) {
#if defined(HAVE_STRUCT_SOCKADDR_UN)
	    if ((fd = __pmAuxConnectPMCDUnixSocket(name)) >= 0) {
		if ((sts = __pmConnectHandshake(fd, name, ctxflags, attrs)) < 0) {
		    __pmCloseSocket(fd);
		}
		else
		    sts = fd;
		portIx = -1; /* no port */
	    }
#endif
	    /*
	     * If the connection failed, or is not supported, and the protocol was 'local:',
	     * then try connecting to localhost via the default port(s).
	     */
	    if (sts < 0) {
		if (nports == PM_HOST_SPEC_NPORTS_LOCAL) {
		    name = "localhost";
		    nports = global_nports;
		    ports = global_portlist;
		    sts = -1; /* keep trying */
		}
		else
		    sts = -2; /* no more connection attempts. */
	    }
	}

	/* If still not connected, try via the given host name and ports, if requested. */
	if (sts == -1) {
	    for (portIx = 0; portIx < nports; portIx++) {
		if ((fd = __pmAuxConnectPMCDPort(name, ports[portIx])) >= 0) {
		    if ((sts = __pmConnectHandshake(fd, name, ctxflags, attrs)) < 0) {
			__pmCloseSocket(fd);
		    }
		    else
			/* success */
			break;
		}
		else
		    sts = fd;
	    }
	}

	if (sts < 0) {
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_CONTEXT) {
		char	errmsg[PM_MAXERRMSGLEN];
		fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection port=",
		   hosts[0].name);
		for (portIx = 0; portIx < nports; portIx++) {
		    if (portIx == 0) fprintf(stderr, "%d", ports[portIx]);
		    else fprintf(stderr, ",%d", ports[portIx]);
		}
		fprintf(stderr, " failed: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg)));
	    }
#endif
	    return sts;
	}

#ifdef PCP_DEBUG
	if (pmDebug & DBG_TRACE_CONTEXT) {
	    if (portIx >= 0) {
		fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection port=%d fd=%d PDU version=%u\n",
			hosts[0].name, ports[portIx], fd, __pmVersionIPC(fd));
	    }
	    else {
		fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection path=%s fd=%d PDU version=%u\n",
			hosts[0].name, name, fd, __pmVersionIPC(fd));
	    }
	    __pmPrintIPC();
	}
#endif

	return fd;
    }

    /*
     * connecting to pmproxy, and then to pmcd ... not a direct
     * connection to pmcd
     */
    proxyhost = (nhosts > 1) ? &hosts[1] : &proxy;
    proxyport = (proxyhost->nports > 0) ? proxyhost->ports[0] : PROXY_PORT;

    for (portIx = 0; portIx < nports; portIx++) {
	fd = __pmAuxConnectPMCDPort(proxyhost->name, proxyport);
	if (fd < 0) {
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_CONTEXT) {
		char	errmsg[PM_MAXERRMSGLEN];
		fprintf(stderr, "__pmConnectPMCD(%s): proxy to %s port=%d failed: %s \n",
			hosts[0].name, proxyhost->name, proxyport, pmErrStr_r(-neterror(), errmsg, sizeof(errmsg)));
	    }
#endif
	    PM_UNLOCK(__pmLock_libpcp);
	    return fd;
	}
	if ((sts = version = negotiate_proxy(fd, hosts[0].name, ports[portIx])) < 0)
	    __pmCloseSocket(fd);
	else if ((sts = __pmConnectHandshake(fd, proxyhost->name, ctxflags, attrs)) < 0)
	    __pmCloseSocket(fd);
	else
	    /* success */
	    break;
    }

    if (sts < 0) {
#ifdef PCP_DEBUG
	if (pmDebug & DBG_TRACE_CONTEXT) {
	    char	errmsg[PM_MAXERRMSGLEN];
	    fprintf(stderr, "__pmConnectPMCD(%s): proxy connection to %s port=",
			hosts[0].name, proxyhost->name);
	    for (portIx = 0; portIx < nports; portIx++) {
		if (portIx == 0) fprintf(stderr, "%d", ports[portIx]);
		else fprintf(stderr, ",%d", ports[portIx]);
	    }
	    fprintf(stderr, " failed: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg)));
	}
#endif
	PM_UNLOCK(__pmLock_libpcp);
	return sts;
    }

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_CONTEXT) {
	fprintf(stderr, "__pmConnectPMCD(%s): proxy connection host=%s port=%d fd=%d version=%d\n",
	    hosts[0].name, proxyhost->name, ports[portIx], fd, version);
    }
#endif

    PM_UNLOCK(__pmLock_libpcp);
    return fd;
}
Example #17
0
static int stomp_connect(const char *hostname, int port)
{
    __pmSockAddr *myaddr;
    __pmHostEnt *servinfo;
    void *enumIx;
    struct timeval tv;
    struct timeval *ptv;
    __pmFdSet wfds;
    int ret;
    int flags = 0;

    if ((servinfo = __pmGetAddrInfo(hostname)) == NULL)
	return -1;

    fd = -1;
    enumIx = NULL;
    for (myaddr = __pmHostEntGetSockAddr(servinfo, &enumIx);
	 myaddr != NULL;
	 myaddr = __pmHostEntGetSockAddr(servinfo, &enumIx)) {
	/* Create a socket */
	if (__pmSockAddrIsInet(myaddr))
	    fd = __pmCreateSocket();
	else if (__pmSockAddrIsIPv6(myaddr))
	    fd = __pmCreateIPv6Socket();
	else
	    fd = -1;

	if (fd < 0) {
	    __pmSockAddrFree(myaddr);
	    continue; /* Try the next address */
	}

	/* Attempt to connect */
	flags = __pmConnectTo(fd, myaddr, port);
	__pmSockAddrFree(myaddr);

	if (flags < 0) {
	    /*
	     * Mark failure in case we fall out the end of the loop
	     * and try next address. fd has been closed in __pmConnectTo().
	     */
	    fd = -1;
	    continue;
	}

	/* FNDELAY and we're in progress - wait on select */
	tv.tv_sec = timeout;
	tv.tv_usec = 0;
	ptv = (tv.tv_sec || tv.tv_usec) ? &tv : NULL;
	__pmFD_ZERO(&wfds);
	__pmFD_SET(fd, &wfds);
	ret = __pmSelectWrite(fd+1, &wfds, ptv);

	/* Was the connection successful? */
	if (ret <= 0) {
	    if (oserror() == EINTR)
		return -2;
	    continue;
	}
	ret = __pmConnectCheckError(fd);
	if (ret == 0)
	    break;

	/* Unsuccessful connection. */
	__pmCloseSocket(fd);
	fd = -1;
    } /* loop over addresses */

    __pmHostEntFree(servinfo);

    if(fd == -1)
	return -4;

    fd = __pmConnectRestoreFlags(fd, flags);
    if(fd < 0)
	return -5;

    return fd;
}
Example #18
0
int
main(int argc, char **argv)
{
    int			c;
    int			sts;
    int			sep = __pmPathSeparator();
    int			use_localtime = 0;
    int			isdaemon = 0;
    char		*pmnsfile = PM_NS_DEFAULT;
    char		*username;
    char		*logfile = "pmlogger.log";
				    /* default log (not archive) file name */
    char		*endnum;
    int			i;
    task_t		*tp;
    optcost_t		ocp;
    __pmFdSet		readyfds;
    char		*p;
    char		*runtime = NULL;
    int	    		ctx;		/* handle corresponding to ctxp below */
    __pmContext  	*ctxp;		/* pmlogger has just this one context */
    int			niter;
    pid_t               target_pid = 0;

    __pmGetUsername(&username);

    /*
     * Warning:
     *		If any of the pmlogger options change, make sure the
     *		corresponding changes are made to pmnewlog when pmlogger
     *		options are passed through from the control file
     */
    while ((c = pmgetopt_r(argc, argv, &opts)) != EOF) {
	switch (c) {

	case 'c':		/* config file */
	    if (access(opts.optarg, F_OK) == 0)
		configfile = opts.optarg;
	    else {
		/* does not exist as given, try the standard place */
		char *sysconf = pmGetConfig("PCP_VAR_DIR");
		int sz = strlen(sysconf)+strlen("/config/pmlogger/")+strlen(opts.optarg)+1;
		if ((configfile = (char *)malloc(sz)) == NULL)
		    __pmNoMem("config file name", sz, PM_FATAL_ERR);
		snprintf(configfile, sz,
			"%s%c" "config%c" "pmlogger%c" "%s",
			sysconf, sep, sep, sep, opts.optarg);
		if (access(configfile, F_OK) != 0) {
		    /* still no good, error handling happens below */
		    free(configfile);
		    configfile = opts.optarg;
		}
	    }
	    break;

	case 'D':	/* debug flag */
	    sts = __pmParseDebug(opts.optarg);
	    if (sts < 0) {
		pmprintf("%s: unrecognized debug flag specification (%s)\n",
			pmProgname, opts.optarg);
		opts.errors++;
	    }
	    else
		pmDebug |= sts;
	    break;

	case 'h':		/* hostname for PMCD to contact */
	    pmcd_host_conn = opts.optarg;
	    break;

	case 'l':		/* log file name */
	    logfile = opts.optarg;
	    break;

	case 'L':		/* linger if not primary logger */
	    linger = 1;
	    break;

	case 'm':		/* note for port map file */
	    note = opts.optarg;
	    isdaemon = ((strcmp(note, "pmlogger_check") == 0) ||
			(strcmp(note, "pmlogger_daily") == 0));
	    break;

	case 'n':		/* alternative name space file */
	    pmnsfile = opts.optarg;
	    break;

	case 'p':
	    target_pid = (int)strtol(opts.optarg, &endnum, 10);
	    if (*endnum != '\0') {
		pmprintf("%s: invalid process identifier (%s)\n",
			 pmProgname, opts.optarg);
		opts.errors++;
	    } else if (!__pmProcessExists(target_pid)) {
		pmprintf("%s: PID error - no such process (%d)\n",
			 pmProgname, target_pid);
		opts.errors++;
	    }
	    break;

	case 'P':		/* this is the primary pmlogger */
	    primary = 1;
	    isdaemon = 1;
	    break;

	case 'r':		/* report sizes of pmResult records */
	    rflag = 1;
	    break;

	case 's':		/* exit size */
	    sts = ParseSize(opts.optarg, &exit_samples, &exit_bytes, &exit_time);
	    if (sts < 0) {
		pmprintf("%s: illegal size argument '%s' for exit size\n",
			pmProgname, opts.optarg);
		opts.errors++;
	    }
	    else if (exit_time.tv_sec > 0) {
		__pmAFregister(&exit_time, NULL, run_done_callback);
	    }
	    break;

	case 'T':		/* end time */
	    runtime = opts.optarg;
            break;

	case 't':		/* change default logging interval */
	    if (pmParseInterval(opts.optarg, &delta, &p) < 0) {
		pmprintf("%s: illegal -t argument\n%s", pmProgname, p);
		free(p);
		opts.errors++;
	    }
	    break;

	case 'U':		/* run as named user */
	    username = opts.optarg;
	    isdaemon = 1;
	    break;

	case 'u':		/* flush output buffers after each fetch */
	    /*
	     * all archive write I/O is unbuffered now, so maintain -u
	     * for backwards compatibility only
	     */
	    break;

	case 'v':		/* volume switch after given size */
	    sts = ParseSize(opts.optarg, &vol_switch_samples, &vol_switch_bytes,
			    &vol_switch_time);
	    if (sts < 0) {
		pmprintf("%s: illegal size argument '%s' for volume size\n", 
			pmProgname, opts.optarg);
		opts.errors++;
	    }
	    else if (vol_switch_time.tv_sec > 0) {
		vol_switch_afid = __pmAFregister(&vol_switch_time, NULL, 
						 vol_switch_callback);
            }
	    break;

        case 'V': 
	    archive_version = (int)strtol(opts.optarg, &endnum, 10);
	    if (*endnum != '\0' || archive_version != PM_LOG_VERS02) {
		pmprintf("%s: -V requires a version number of %d\n",
			 pmProgname, PM_LOG_VERS02); 
		opts.errors++;
	    }
	    break;

	case 'x':		/* recording session control fd */
	    rsc_fd = (int)strtol(opts.optarg, &endnum, 10);
	    if (*endnum != '\0' || rsc_fd < 0) {
		pmprintf("%s: -x requires a non-negative numeric argument\n", pmProgname);
		opts.errors++;
	    }
	    else {
		time(&rsc_start);
	    }
	    break;

	case 'y':
	    use_localtime = 1;
	    break;

	case '?':
	default:
	    opts.errors++;
	    break;
	}
    }

    if (primary && pmcd_host != NULL) {
	pmprintf(
	    "%s: -P and -h are mutually exclusive; use -P only when running\n"
	    "%s on the same (local) host as the PMCD to which it connects.\n",
		pmProgname, pmProgname);
	opts.errors++;
    }

    if (!opts.errors && opts.optind != argc - 1) {
	pmprintf("%s: insufficient arguments\n", pmProgname);
	opts.errors++;
    }

    if (opts.errors) {
	pmUsageMessage(&opts);
	exit(1);
    }

    if (rsc_fd != -1 && note == NULL) {
	/* add default note to indicate running with -x */
	static char	xnote[10];
	snprintf(xnote, sizeof(xnote), "-x %d", rsc_fd);
	note = xnote;
    }

    /* if we are running as a daemon, change user early */
    if (isdaemon)
	__pmSetProcessIdentity(username);

    __pmOpenLog("pmlogger", logfile, stderr, &sts);
    if (sts != 1) {
	fprintf(stderr, "%s: Warning: log file (%s) creation failed\n", pmProgname, logfile);
	/* continue on ... writing to stderr */
    }

    /* base name for archive is here ... */
    archBase = argv[opts.optind];

    if (pmcd_host_conn == NULL)
	pmcd_host_conn = "local:";

    /* initialise access control */
    if (__pmAccAddOp(PM_OP_LOG_ADV) < 0 ||
	__pmAccAddOp(PM_OP_LOG_MAND) < 0 ||
	__pmAccAddOp(PM_OP_LOG_ENQ) < 0) {
	fprintf(stderr, "%s: access control initialisation failed\n", pmProgname);
	exit(1);
    }

    if (pmnsfile != PM_NS_DEFAULT) {
	if ((sts = pmLoadASCIINameSpace(pmnsfile, 1)) < 0) {
	    fprintf(stderr, "%s: Cannot load namespace from \"%s\": %s\n", pmProgname, pmnsfile, pmErrStr(sts));
	    exit(1);
	}
    }

    if ((ctx = pmNewContext(PM_CONTEXT_HOST, pmcd_host_conn)) < 0) {
	fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", pmProgname, pmcd_host_conn, pmErrStr(ctx));
	exit(1);
    }
    pmcd_host = (char *)pmGetContextHostName(ctx);
    if (strlen(pmcd_host) == 0) {
	fprintf(stderr, "%s: pmGetContextHostName(%d) failed\n",
	    pmProgname, ctx);
	exit(1);
    }

    if (rsc_fd == -1) {
	/* no -x, so register client id with pmcd */
	__pmSetClientIdArgv(argc, argv);
    }

    /*
     * discover fd for comms channel to PMCD ... 
     */
    if ((ctxp = __pmHandleToPtr(ctx)) == NULL) {
	fprintf(stderr, "%s: botch: __pmHandleToPtr(%d) returns NULL!\n", pmProgname, ctx);
	exit(1);
    }
    pmcdfd = ctxp->c_pmcd->pc_fd;
    PM_UNLOCK(ctxp->c_lock);

    if (configfile != NULL) {
	if ((yyin = fopen(configfile, "r")) == NULL) {
	    fprintf(stderr, "%s: Cannot open config file \"%s\": %s\n",
		pmProgname, configfile, osstrerror());
	    exit(1);
	}
    }
    else {
	/* **ANY** Lex would read from stdin automagically */
	configfile = "<stdin>";
    }

    __pmOptFetchGetParams(&ocp);
    ocp.c_scope = 1;
    __pmOptFetchPutParams(&ocp);

    /* prevent early timer events ... */
    __pmAFblock();

    if (yyparse() != 0)
	exit(1);
    if (configfile != NULL)
	fclose(yyin);
    yyend();

#ifdef PCP_DEBUG
    fprintf(stderr, "Config parsed\n");
#endif

    fprintf(stderr, "Starting %slogger for host \"%s\" via \"%s\"\n",
            primary ? "primary " : "", pmcd_host, pmcd_host_conn);

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_LOG) {
	fprintf(stderr, "optFetch Cost Parameters: pmid=%d indom=%d fetch=%d scope=%d\n",
		ocp.c_pmid, ocp.c_indom, ocp.c_fetch, ocp.c_scope);

	fprintf(stderr, "\nAfter loading config ...\n");
	for (tp = tasklist; tp != NULL; tp = tp->t_next) {
	    if (tp->t_numvalid == 0)
		continue;
	    fprintf(stderr, " state: %sin log, %savail, %s, %s",
		PMLC_GET_INLOG(tp->t_state) ? "" : "not ",
		PMLC_GET_AVAIL(tp->t_state) ? "" : "un",
		PMLC_GET_MAND(tp->t_state) ? "mand" : "adv",
		PMLC_GET_ON(tp->t_state) ? "on" : "off");
	    fprintf(stderr, " delta: %ld usec", 
			(long)1000 * tp->t_delta.tv_sec + tp->t_delta.tv_usec);
	    fprintf(stderr, " numpmid: %d\n", tp->t_numpmid);
	    for (i = 0; i < tp->t_numpmid; i++) {
		fprintf(stderr, "  %s (%s):\n", pmIDStr(tp->t_pmidlist[i]), tp->t_namelist[i]);
	    }
	    __pmOptFetchDump(stderr, tp->t_fetch);
	}
    }
#endif

    if (!primary && tasklist == NULL && !linger) {
	fprintf(stderr, "Nothing to log, and not the primary logger instance ... good-bye\n");
	exit(1);
    }

    if ((sts = __pmLogCreate(pmcd_host, archBase, archive_version, &logctl)) < 0) {
	fprintf(stderr, "__pmLogCreate: %s\n", pmErrStr(sts));
	exit(1);
    }
    else {
	/*
	 * try and establish $TZ from the remote PMCD ...
	 * Note the label record has been set up, but not written yet
	 */
	char		*name = "pmcd.timezone";
	pmID		pmid;
	pmResult	*resp;

	__pmtimevalNow(&epoch);
	sts = pmUseContext(ctx);

	if (sts >= 0)
	    sts = pmLookupName(1, &name, &pmid);
	if (sts >= 0)
	    sts = pmFetch(1, &pmid, &resp);
	if (sts >= 0) {
	    if (resp->vset[0]->numval > 0) { /* pmcd.timezone present */
		strcpy(logctl.l_label.ill_tz, resp->vset[0]->vlist[0].value.pval->vbuf);
		/* prefer to use remote time to avoid clock drift problems */
		epoch = resp->timestamp;		/* struct assignment */
		if (! use_localtime)
		    pmNewZone(logctl.l_label.ill_tz);
	    }
#ifdef PCP_DEBUG
	    else if (pmDebug & DBG_TRACE_LOG) {
		fprintf(stderr,
			"main: Could not get timezone from host %s\n",
			pmcd_host);
	    }
#endif
	    pmFreeResult(resp);
	}
    }

    /* do ParseTimeWindow stuff for -T */
    if (runtime) {
        struct timeval res_end;    /* time window end */
        struct timeval start;
        struct timeval end;
        struct timeval last_delta;
        char *err_msg;             /* parsing error message */
        time_t now;
        struct timeval now_tv;

        time(&now);
        now_tv.tv_sec = now;
        now_tv.tv_usec = 0; 

        start = now_tv;
        end.tv_sec = INT_MAX;
        end.tv_usec = INT_MAX;
        sts = __pmParseTime(runtime, &start, &end, &res_end, &err_msg);
        if (sts < 0) {
	    fprintf(stderr, "%s: illegal -T argument\n%s", pmProgname, err_msg);
            exit(1);
        }

        last_delta = res_end;
        tsub(&last_delta, &now_tv);
	__pmAFregister(&last_delta, NULL, run_done_callback);

        last_stamp = res_end;
    }

    fprintf(stderr, "Archive basename: %s\n", archBase);

#ifndef IS_MINGW
    /* detach yourself from the launching process */
    if (isdaemon)
        setpgid(getpid(), 0);
#endif

    /* set up control port */
    init_ports();
    __pmFD_ZERO(&fds);
    for (i = 0; i < CFD_NUM; ++i) {
	if (ctlfds[i] >= 0)
	    __pmFD_SET(ctlfds[i], &fds);
    }
#ifndef IS_MINGW
    __pmFD_SET(pmcdfd, &fds);
#endif
    if (rsc_fd != -1)
	__pmFD_SET(rsc_fd, &fds);
    numfds = maxfd() + 1;

    if ((sts = do_preamble()) < 0)
	fprintf(stderr, "Warning: problem writing archive preamble: %s\n",
	    pmErrStr(sts));

    sts = 0;		/* default exit status */

    parse_done = 1;	/* enable callback processing */
    __pmAFunblock();

    for ( ; ; ) {
	int		nready;

#ifdef PCP_DEBUG
	if ((pmDebug & DBG_TRACE_APPL2) && (pmDebug & DBG_TRACE_DESPERATE)) {
	    fprintf(stderr, "before __pmSelectRead(%d,...): run_done_alarm=%d vol_switch_alarm=%d log_alarm=%d\n", numfds, run_done_alarm, vol_switch_alarm, log_alarm);
	}
#endif

	niter = 0;
	while (log_alarm && niter++ < 10) {
	    __pmAFblock();
	    log_alarm = 0;
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_APPL2)
		fprintf(stderr, "delayed callback: log_alarm\n");
#endif
	    for (tp = tasklist; tp != NULL; tp = tp->t_next) {
		if (tp->t_alarm) {
		    tp->t_alarm = 0;
		    do_work(tp);
		}
	    }
	    __pmAFunblock();
	}

	if (vol_switch_alarm) {
	    __pmAFblock();
	    vol_switch_alarm = 0;
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_APPL2)
		fprintf(stderr, "delayed callback: vol_switch_alarm\n");
#endif
	    newvolume(VOL_SW_TIME);
	    __pmAFunblock();
	}

	if (run_done_alarm) {
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_APPL2)
		fprintf(stderr, "delayed callback: run_done_alarm\n");
#endif
	    run_done(0, NULL);
	    /*NOTREACHED*/
	}

	__pmFD_COPY(&readyfds, &fds);
	nready = __pmSelectRead(numfds, &readyfds, NULL);

#ifdef PCP_DEBUG
	if ((pmDebug & DBG_TRACE_APPL2) && (pmDebug & DBG_TRACE_DESPERATE)) {
	    fprintf(stderr, "__pmSelectRead(%d,...) done: nready=%d run_done_alarm=%d vol_switch_alarm=%d log_alarm=%d\n", numfds, nready, run_done_alarm, vol_switch_alarm, log_alarm);
	}
#endif

	__pmAFblock();
	if (nready > 0) {

	    /* handle request on control port */
	    for (i = 0; i < CFD_NUM; ++i) {
		if (ctlfds[i] >= 0 && __pmFD_ISSET(ctlfds[i], &readyfds)) {
		    if (control_req(ctlfds[i])) {
			/* new client has connected */
			__pmFD_SET(clientfd, &fds);
			if (clientfd >= numfds)
			    numfds = clientfd + 1;
		    }
		}
	    }
	    if (clientfd >= 0 && __pmFD_ISSET(clientfd, &readyfds)) {
		/* process request from client, save clientfd in case client
		 * closes connection, resetting clientfd to -1
		 */
		int	fd = clientfd;

		if (client_req()) {
		    /* client closed connection */
		    __pmFD_CLR(fd, &fds);
		    __pmCloseSocket(clientfd);
		    clientfd = -1;
		    numfds = maxfd() + 1;
		    qa_case = 0;
		}
	    }
#ifndef IS_MINGW
	    if (pmcdfd >= 0 && __pmFD_ISSET(pmcdfd, &readyfds)) {
		/*
		 * do not expect this, given synchronous commumication with the
		 * pmcd ... either pmcd has terminated, or bogus PDU ... or its
		 * Win32 and we are operating under the different conditions of
		 * our AF.c implementation there, which has to deal with a lack
		 * of signal support on Windows - race condition exists between
		 * this check and the async event timer callback.
		 */
		__pmPDU		*pb;
		__pmPDUHdr	*php;
		sts = __pmGetPDU(pmcdfd, ANY_SIZE, TIMEOUT_NEVER, &pb);
		if (sts <= 0) {
		    if (sts < 0)
			fprintf(stderr, "Error: __pmGetPDU: %s\n", pmErrStr(sts));
		    disconnect(sts);
		}
		else {
		    php = (__pmPDUHdr *)pb;
		    fprintf(stderr, "Error: Unsolicited %s PDU from PMCD\n",
			__pmPDUTypeStr(php->type));
		    disconnect(PM_ERR_IPC);
		}
		if (sts > 0)
		    __pmUnpinPDUBuf(pb);
	    }
#endif
	    if (rsc_fd >= 0 && __pmFD_ISSET(rsc_fd, &readyfds)) {
		/*
		 * some action on the recording session control fd
		 * end-of-file means launcher has quit, otherwise we
		 * expect one of these commands
		 *	V<number>\n	- version
		 *	F<folio>\n	- folio name
		 *	P<name>\n	- launcher's name
		 *	R\n		- launcher can replay
		 *	D\n		- detach from launcher
		 *	Q\n		- quit pmlogger
		 */
		char	rsc_buf[MAXPATHLEN];
		char	*rp = rsc_buf;
		char	myc;
		int	fake_x = 0;

		for (rp = rsc_buf; ; rp++) {
		    if (read(rsc_fd, &myc, 1) <= 0) {
#ifdef PCP_DEBUG
			if (pmDebug & DBG_TRACE_APPL2)
			    fprintf(stderr, "recording session control: eof\n");
#endif
			if (rp != rsc_buf) {
			    *rp = '\0';
			    fprintf(stderr, "Error: incomplete recording session control message: \"%s\"\n", rsc_buf);
			}
			fake_x = 1;
			break;
		    }
		    if (rp >= &rsc_buf[MAXPATHLEN]) {
			fprintf(stderr, "Error: absurd recording session control message: \"%100.100s ...\"\n", rsc_buf);
			fake_x = 1;
			break;
		    }
		    if (myc == '\n') {
			*rp = '\0';
			break;
		    }
		    *rp = myc;
		}

#ifdef PCP_DEBUG
		if (pmDebug & DBG_TRACE_APPL2) {
		    if (fake_x == 0)
			fprintf(stderr, "recording session control: \"%s\"\n", rsc_buf);
		}
#endif

		if (fake_x)
		    do_dialog('X');
		else if (strcmp(rsc_buf, "Q") == 0 ||
		         strcmp(rsc_buf, "D") == 0 ||
			 strcmp(rsc_buf, "?") == 0)
		    do_dialog(rsc_buf[0]);
		else if (rsc_buf[0] == 'F')
		    folio_name = strdup(&rsc_buf[1]);
		else if (rsc_buf[0] == 'P')
		    rsc_prog = strdup(&rsc_buf[1]);
		else if (strcmp(rsc_buf, "R") == 0)
		    rsc_replay = 1;
		else if (rsc_buf[0] == 'V' && rsc_buf[1] == '0') {
		    /*
		     * version 0 of the recording session control ...
		     * this is all we grok at the moment
		     */
		    ;
		}
		else {
		    fprintf(stderr, "Error: illegal recording session control message: \"%s\"\n", rsc_buf);
		    do_dialog('X');
		}
	    }
	}
	else if (vol_switch_flag) {
	    newvolume(VOL_SW_SIGHUP);
	    vol_switch_flag = 0;
	}
	else if (nready < 0 && neterror() != EINTR)
	    fprintf(stderr, "Error: select: %s\n", netstrerror());

	__pmAFunblock();

	if (target_pid && !__pmProcessExists(target_pid))
	    exit(EXIT_SUCCESS);

	if (exit_code)
	    break;
    }
    exit(exit_code);
}
Example #19
0
File: trace.c Project: tongfw/pcp
static int
_pmauxtraceconnect(void)
{
    int			port = TRACE_PORT;
    char		hostname[MAXHOSTNAMELEN];
    struct timeval	timeout = { 3, 0 };     /* default 3 secs */
    __pmSockAddr	*myaddr;
    __pmHostEnt		*servinfo;
    void		*enumIx;
#ifndef IS_MINGW
    struct itimerval	_pmolditimer;
    void		(*old_handler)(int foo);
#endif
    int			rc, sts;
    int			flags = 0;
    char		*sptr, *endptr, *endnum;
    struct timeval	canwait = { 5, 000000 };
    struct timeval	stv;
    struct timeval	*pstv;
    __pmFdSet		wfds;

#ifdef PMTRACE_DEBUG
    if (__pmstate & PMTRACE_STATE_NOAGENT) {
	fprintf(stderr, "_pmtraceconnect: connecting to PMDA (skipped)\n");
	return 0;
    }
    else if (__pmstate & PMTRACE_STATE_COMMS)
	fprintf(stderr, "_pmtraceconnect: connecting to PMDA ...\n");
#endif

    /*
     * get optional stuff from environment ...
     *  PCP_TRACE_HOST, PCP_TRACE_PORT, PCP_TRACE_TIMEOUT, and
     *  PCP_TRACE_NOAGENT
     */
    if ((sptr = getenv(TRACE_ENV_HOST)) != NULL)
	strcpy(hostname, sptr);
    else {
       (void)gethostname(hostname, MAXHOSTNAMELEN);
       hostname[MAXHOSTNAMELEN-1] = '\0';
    }
    if ((sptr = getenv(TRACE_ENV_PORT)) != NULL) {
	port = (int)strtol(sptr, &endnum, 0);
	if (*endnum != '\0' || port < 0) {
	    fprintf(stderr, "trace warning: bad PCP_TRACE_PORT ignored.");
	    port = TRACE_PORT;
	}
    }
    if ((sptr = getenv(TRACE_ENV_TIMEOUT)) != NULL) {
	double timesec = strtod(sptr, &endptr);
	if (*endptr != '\0' || timesec < 0.0)
	    fprintf(stderr, "trace warning: bogus PCP_TRACE_TIMEOUT.");
	else {
	    timeout.tv_sec = (time_t)timesec;
	    timeout.tv_usec = (int)((timesec - (double)timeout.tv_sec)*1000000);
	}
    }
    if (getenv(TRACE_ENV_NOAGENT) != NULL)
	__pmstate |= PMTRACE_STATE_NOAGENT;

    if ((servinfo = __pmGetAddrInfo(hostname)) == NULL) {
#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS)
	    fprintf(stderr, "_pmtraceconnect(__pmGetAddrInfo(hostname=%s): "
		    "hosterror=%d, ``%s''\n", hostname, hosterror(),
		    hoststrerror());
#endif
	return -EHOSTUNREACH;
    }

    /* Try each address in turn until one connects. */
    sts = EHOSTUNREACH;
    __pmfd = -1;
    enumIx = NULL;
    for (myaddr = __pmHostEntGetSockAddr(servinfo, &enumIx);
	 myaddr != NULL;
	 myaddr = __pmHostEntGetSockAddr(servinfo, &enumIx)) {
	/* Create a socket */
	if (__pmSockAddrIsInet(myaddr))
	    __pmfd = __pmCreateSocket();
	else if (__pmSockAddrIsIPv6(myaddr))
	    __pmfd = __pmCreateIPv6Socket();
	else {
	    fprintf(stderr, "_pmtraceconnect(invalid address family): %d\n",
		    __pmSockAddrGetFamily(myaddr));
	}
	if (__pmfd < 0) {
	    sts = neterror();
	    __pmSockAddrFree(myaddr);
	    continue; /* Try the next address */
	}

	/* Set the port. */
	__pmSockAddrSetPort(myaddr, port);

#ifndef IS_MINGW
	/* arm interval timer */
	_pmmyitimer.it_value.tv_sec = timeout.tv_sec;
	_pmmyitimer.it_value.tv_usec = timeout.tv_usec;
	_pmmyitimer.it_interval.tv_sec = 0;
	_pmmyitimer.it_interval.tv_usec = 0;
	old_handler = signal(SIGALRM, _pmtracealarm);
	setitimer(ITIMER_REAL, &_pmmyitimer, &_pmolditimer);
#endif

#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS) {
	    char *name = __pmHostEntGetName (servinfo);
	    fprintf(stderr, "_pmtraceconnect: PMDA host=%s port=%d timeout=%d"
		    "secs\n", name == NULL ? "unknown" : name, port, (int)timeout.tv_sec);
	    if (name != NULL)
		free(name);
	}
#endif

	/* Attempt to connect */
	flags = __pmConnectTo(__pmfd, myaddr, port);
	__pmSockAddrFree(myaddr);

	if (flags < 0) {
	    /*
	     * Mark failure in case we fall out the end of the loop
	     * and try next address. __pmfd has been closed in __pmConnectTo().
	     */
	    sts = -flags;
	    __pmfd = -1;
	    continue;
	}

	/* FNDELAY and we're in progress - wait on select */
	stv = canwait;
	pstv = (stv.tv_sec || stv.tv_usec) ? &stv : NULL;
	__pmFD_ZERO(&wfds);
	__pmFD_SET(__pmfd, &wfds);
	if ((rc = __pmSelectWrite(__pmfd+1, &wfds, pstv)) == 1) {
	    sts = __pmConnectCheckError(__pmfd);
	}
	else if (rc == 0) {
	    sts = ETIMEDOUT;
	}
	else {
	    sts = (rc < 0) ? neterror() : EINVAL;
	}
 
#ifndef IS_MINGW
	/* re-arm interval timer */
	setitimer(ITIMER_REAL, &off_itimer, &_pmmyitimer);
	signal(SIGALRM, old_handler);
	if (_pmolditimer.it_value.tv_sec != 0 && _pmolditimer.it_value.tv_usec != 0) {
	    _pmolditimer.it_value.tv_usec -= timeout.tv_usec - _pmmyitimer.it_value.tv_usec;
	    while (_pmolditimer.it_value.tv_usec < 0) {
		_pmolditimer.it_value.tv_usec += 1000000;
		_pmolditimer.it_value.tv_sec--;
	    }
	    while (_pmolditimer.it_value.tv_usec > 1000000) {
		_pmolditimer.it_value.tv_usec -= 1000000;
		_pmolditimer.it_value.tv_sec++;
	    }
	    _pmolditimer.it_value.tv_sec -= timeout.tv_sec - _pmmyitimer.it_value.tv_sec;
	    if (_pmolditimer.it_value.tv_sec < 0) {
		/* missed the user's itimer, pretend there is 1 msec to go! */
		_pmolditimer.it_value.tv_sec = 0;
		_pmolditimer.it_value.tv_usec = 1000;
	    }
	    setitimer(ITIMER_REAL, &_pmolditimer, &_pmmyitimer);
	}
#endif

	/* Was the connection successful? */
	if (sts == 0)
	    break;

	/* Unsuccessful connection. */
	__pmCloseSocket(__pmfd);
	__pmfd = -1;
    } /* loop over addresses */

    __pmHostEntFree(servinfo);

    /* Was the connection successful? */
    if (__pmfd < 0) {
#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS)
	    fprintf(stderr, "_pmtraceconnect(socket failed): %s\n",
		    netstrerror());
#endif
	return -sts;
    }

    _pmtimedout = 0;

    /* Restore the original file status flags. */
    if (__pmSetFileStatusFlags(__pmfd, flags) < 0) {
#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS)
	    fprintf(stderr, ":_pmtraceconnect: cannot restore file status flags\n");
#endif
	return -oserror();
    }

    /* make sure this file descriptor is closed if exec() is called */
    if ((flags = __pmGetFileDescriptorFlags(__pmfd)) != -1)
	sts = __pmSetFileDescriptorFlags(__pmfd, flags | FD_CLOEXEC);
    else
	sts = -1;
    if (sts == -1)
	return -oserror();

    if (__pmtraceprotocol(TRACE_PROTOCOL_QUERY) == TRACE_PROTOCOL_ASYNC) {
	/* in the asynchronoous protocol - ensure no delay after close */
	if ((flags = __pmGetFileStatusFlags(__pmfd)) != -1)
	    sts = __pmSetFileStatusFlags(__pmfd, flags | FNDELAY);
	else
	    sts = -1;
	if (sts == -1)
	    return -oserror();
#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS)
	    fprintf(stderr, "_pmtraceconnect: async protocol setup complete\n");
#endif
    }
    else
#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS)
	    fprintf(stderr, "_pmtraceconnect: sync protocol setup complete\n");
#endif

    /* trace PMDA sends an ACK on successful connect */
    sts = _pmtracegetack(sts, 0);

    return sts;
}
Example #20
0
int
conn_cisco(cisco_t * cp)
{
    __pmFdSet		wfds;
    __pmSockAddr	*myaddr;
    void		*enumIx;
    int			flags = 0;
    int			fd;
    int			ret;

    fd = -1;
    enumIx = NULL;
    for (myaddr = __pmHostEntGetSockAddr(cp->hostinfo, &enumIx);
	 myaddr != NULL;
	 myaddr = __pmHostEntGetSockAddr(cp->hostinfo, &enumIx)) {
	/* Create a socket */
	if (__pmSockAddrIsInet(myaddr))
	    fd = __pmCreateSocket();
	else if (__pmSockAddrIsIPv6(myaddr))
	    fd = __pmCreateIPv6Socket();
	else
	    fd = -1;

	if (fd < 0) {
	    __pmSockAddrFree(myaddr);
	    continue; /* Try the next address */
	}

	/* Attempt to connect */
	flags = __pmConnectTo(fd, myaddr, cp->port);
	__pmSockAddrFree(myaddr);

	if (flags < 0) {
	    /*
	     * Mark failure in case we fall out the end of the loop
	     * and try next address. fd has been closed in __pmConnectTo().
	     */
	    setoserror(ECONNREFUSED);
	    fd = -1;
	    continue;
	}

	/* FNDELAY and we're in progress - wait on select */
	__pmFD_ZERO(&wfds);
	__pmFD_SET(fd, &wfds);
	ret = __pmSelectWrite(fd+1, &wfds, NULL);

	/* Was the connection successful? */
	if (ret == 0)
	    setoserror(ETIMEDOUT);
	else if (ret > 0) {
	    ret = __pmConnectCheckError(fd);
	    if (ret == 0)
		break;
	    setoserror(ret);
	}
	
	/* Unsuccessful connection. */
	__pmCloseSocket(fd);
	fd = -1;
    } /* loop over addresses */

    if (fd == -1) {
	fprintf(stderr, "conn_cisco(%s): connect: %s\n",
		cp->host, netstrerror());
	return -1;
    }

    fd = __pmConnectRestoreFlags(fd, flags);
    if (fd < 0) {
	fprintf(stderr, "conn_cisco(%s): setsockopt: %s\n",
		cp->host, netstrerror());
	return -1;
    }

    return fd;
}