/* * Hostname extracted and cached for later use during protocol negotiations */ static void GetProxyHostname(void) { __pmHostEnt *hep; char host[MAXHOSTNAMELEN]; if (gethostname(host, MAXHOSTNAMELEN) < 0) { __pmNotifyErr(LOG_ERR, "%s: gethostname failure\n", pmProgname); DontStart(); } host[MAXHOSTNAMELEN-1] = '\0'; hep = __pmGetAddrInfo(host); if (hep == NULL) { __pmNotifyErr(LOG_ERR, "%s: __pmGetAddrInfo failure\n", pmProgname); DontStart(); } else { hostname = __pmHostEntGetName(hep); if (!hostname) { /* no reverse DNS lookup for local hostname */ hostname = strdup(host); if (!hostname) /* out of memory, we're having a bad day!?! */ __pmNoMem("PMPROXY.hostname", strlen(host), PM_FATAL_ERR); } __pmHostEntFree(hep); } }
/* * Return 1 if hostname corresponds to the current host, 0 if not and < 0 for * an error. */ int __pmIsLocalhost(const char *hostname) { int sts = 0; if (strcasecmp(hostname, "localhost") == 0 || strncmp(hostname, "local:", 6) == 0 || strncmp(hostname, "unix:", 5) == 0) return 1; else { char lhost[MAXHOSTNAMELEN+1]; __pmHostEnt *servInfo1; if (gethostname(lhost, MAXHOSTNAMELEN) < 0) return -oserror(); if ((servInfo1 = __pmGetAddrInfo(lhost)) != NULL) { __pmHostEnt *servInfo2; __pmSockAddr *addr1, *addr2; void *enumIx1, *enumIx2; if ((servInfo2 = __pmGetAddrInfo(hostname)) == NULL) { __pmHostEntFree(servInfo1); return -EHOSTUNREACH; } enumIx1 = NULL; for (addr1 = __pmHostEntGetSockAddr(servInfo1, &enumIx1); addr1 != NULL; addr1 = __pmHostEntGetSockAddr(servInfo1, &enumIx1)) { enumIx2 = NULL; for (addr2 = __pmHostEntGetSockAddr(servInfo2, &enumIx2); addr2 != NULL; addr2 = __pmHostEntGetSockAddr(servInfo2, &enumIx2)) { if (__pmSockAddrCompare(addr1, addr2) == 0) { __pmHostEntFree(servInfo1); __pmHostEntFree(servInfo2); return 1; } } } __pmHostEntFree(servInfo1); __pmHostEntFree(servInfo2); } } return sts; }
/* * 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; }
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]); }
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 do_preamble(void) { int sts; int i; int j; pid_t mypid = getpid(); pmResult *res; __pmPDU *pb; pmAtomValue atom; __pmTimeval tmp; char path[MAXPATHLEN]; char host[MAXHOSTNAMELEN]; int free_cp; /* start to build the pmResult */ res = (pmResult *)malloc(sizeof(pmResult) + (n_metric - 1) * sizeof(pmValueSet *)); if (res == NULL) return -oserror(); res->numpmid = n_metric; last_stamp = res->timestamp = epoch; /* struct assignment */ tmp.tv_sec = (__int32_t)epoch.tv_sec; tmp.tv_usec = (__int32_t)epoch.tv_usec; for (i = 0; i < n_metric; i++) res->vset[i] = NULL; for (i = 0; i < n_metric; i++) { res->vset[i] = (pmValueSet *)malloc(sizeof(pmValueSet)); if (res->vset[i] == NULL) { sts = -oserror(); goto done; } res->vset[i]->pmid = desc[i].pmid; res->vset[i]->numval = 1; /* special case for each value 0 .. n_metric-1 */ free_cp = 0; if (desc[i].pmid == PMID(2,3,3)) { __pmHostEnt *servInfo; /* my fully qualified hostname, cloned from the pmcd PMDA */ (void)gethostname(host, MAXHOSTNAMELEN); host[MAXHOSTNAMELEN-1] = '\0'; if ((servInfo = __pmGetAddrInfo(host)) == NULL) atom.cp = host; else { atom.cp = __pmHostEntGetName(servInfo); __pmHostEntFree(servInfo); if (atom.cp == NULL) atom.cp = host; else free_cp = 1; } } else if (desc[i].pmid == PMID(2,3,0)) { /* my control port number, from ports.c */ atom.l = ctlport; } else if (desc[i].pmid == PMID(2,3,2)) { /* * the full pathname to the base of the archive, cloned * from GetPort() in ports.c */ if (__pmAbsolutePath(archBase)) atom.cp = archBase; else { if (getcwd(path, MAXPATHLEN) == NULL) atom.cp = archBase; else { strcat(path, "/"); strcat(path, archBase); atom.cp = path; } } } sts = __pmStuffValue(&atom, &res->vset[i]->vlist[0], desc[i].type); if (free_cp) free(atom.cp); if (sts < 0) goto done; res->vset[i]->vlist[0].inst = (int)mypid; res->vset[i]->valfmt = sts; } if ((sts = __pmEncodeResult(fileno(logctl.l_mfp), res, &pb)) < 0) goto done; __pmOverrideLastFd(fileno(logctl.l_mfp)); /* force use of log version */ /* and start some writing to the archive log files ... */ sts = __pmLogPutResult2(&logctl, pb); __pmUnpinPDUBuf(pb); if (sts < 0) goto done; for (i = 0; i < n_metric; i++) { if ((sts = __pmLogPutDesc(&logctl, &desc[i], 1, &names[i])) < 0) goto done; if (desc[i].indom == PM_INDOM_NULL) continue; for (j = 0; j < i; j++) { if (desc[i].indom == desc[j].indom) break; } if (j == i) { /* need indom ... force one with my PID as the only instance */ int *instid; char **instname; if ((instid = (int *)malloc(sizeof(*instid))) == NULL) { sts = -oserror(); goto done; } *instid = (int)mypid; snprintf(path, sizeof(path), "%" FMT_PID, mypid); if ((instname = (char **)malloc(sizeof(char *)+strlen(path)+1)) == NULL) { free(instid); sts = -oserror(); goto done; } /* * this _is_ correct ... instname[] is a one element array * with the string value immediately following */ instname[0] = (char *)&instname[1]; strcpy(instname[0], path); /* * Note. DO NOT free instid and instname ... they get hidden * away in addindom() below __pmLogPutInDom() */ if ((sts = __pmLogPutInDom(&logctl, desc[i].indom, &tmp, 1, instid, instname)) < 0) goto done; } } /* fudge the temporal index */ fseek(logctl.l_mfp, sizeof(__pmLogLabel)+2*sizeof(int), SEEK_SET); fseek(logctl.l_mdfp, sizeof(__pmLogLabel)+2*sizeof(int), SEEK_SET); __pmLogPutIndex(&logctl, &tmp); fseek(logctl.l_mfp, 0L, SEEK_END); fseek(logctl.l_mdfp, 0L, SEEK_END); sts = 0; /* * and now free stuff */ done: for (i = 0; i < n_metric; i++) { if (res->vset[i] != NULL) free(res->vset[i]); } free(res); return sts; }
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; }