/* * 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; }
/* * 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; }
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 }
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; } }
static void http_client_disconnect(http_client *cp) { if (cp->fd != -1) __pmCloseSocket(cp->fd); cp->fd = -1; }
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); }
/* 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); }
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); }
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); } }
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); }
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; }
/* * 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; }
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); }
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 }
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]); }
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; }
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; }
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); }
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; }
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; }