/* * Reads the metadata of an HTTP response. * Perhaps a little inefficient, as it reads 1 byte at a time, but * I don't think it's that much of a loss (most headers aren't HUGE). * Returns: * # of bytes read on success, or * -1 on error */ int _http_read_header(int sock, char *headerPtr) { fd_set rfds; struct timeval tv; int bytesRead = 0, newlines = 0, ret, selectRet; while(newlines != 2 && bytesRead != HEADER_BUF_SIZE) { FD_ZERO(&rfds); FD_SET(sock, &rfds); tv.tv_sec = timeout; tv.tv_usec = 0; if(timeout >= 0) selectRet = select(sock+1, &rfds, NULL, NULL, &tv); else /* No timeout, can block indefinately */ selectRet = select(sock+1, &rfds, NULL, NULL, NULL); if(selectRet == 0) { errorSource = FETCHER_ERROR; http_errno = HF_HEADTIMEOUT; errorInt = timeout; return -1; } else if(selectRet == -1) { setoserror(neterror()); errorSource = ERRNO; return -1; } ret = recv(sock, headerPtr, 1, 0); if(ret == -1) { setoserror(neterror()); errorSource = ERRNO; return -1; } bytesRead++; if(*headerPtr == '\r') /* Ignore CR */ { /* Basically do nothing special, just don't set newlines * to 0 */ headerPtr++; continue; } else if(*headerPtr == '\n') /* LF is the separator */ newlines++; else newlines = 0; headerPtr++; } headerPtr -= 3; /* Snip the trailing LF's */ *headerPtr = '\0'; return bytesRead; }
static int _pmtraceremaperr(int sts) { int save_oserror; int socket_closed; /* * sts is negative. * Use __pmSocketClosed() to decode it, since it may have come from * __pmSecureSocketsError(). __pmSocketClosed uses oserror() and expects it to * be non-negative. */ save_oserror = oserror(); setoserror(-sts); socket_closed = __pmSocketClosed(); setoserror(save_oserror); #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceremaperr: status %d remapped to %d\n", sts, socket_closed ? PMTRACE_ERR_IPC : sts); #endif if (socket_closed) { _pmtimedout = 1; return PMTRACE_ERR_IPC; } return sts; }
static int secure_file_contents(const char *filename, char **passwd, size_t *length) { struct stat stat; size_t size = *length; char *pass = NULL; FILE *file = NULL; int sts; if ((file = fopen(filename, "r")) == NULL) goto fail; if (fstat(fileno(file), &stat) < 0) goto fail; if (stat.st_size > size) { setoserror(E2BIG); goto fail; } if ((pass = (char *)PORT_Alloc(stat.st_size)) == NULL) { setoserror(ENOMEM); goto fail; } sts = fread(pass, 1, stat.st_size, file); if (sts < 1) { setoserror(EINVAL); goto fail; } while (sts > 0 && (pass[sts-1] == '\r' || pass[sts-1] == '\n')) pass[--sts] = '\0'; *passwd = pass; *length = sts; fclose(file); return 0; fail: sts = -oserror(); if (file) fclose(file); if (pass) PORT_Free(pass); return sts; }
/* * Open a regular file for reading, checking that its regular and accessible */ FILE * openfile(const char *fname) { struct stat sbuf; FILE *fp = fopen(fname, "r"); if (!fp) return NULL; if (fstat(fileno(fp), &sbuf) < 0) { fclose(fp); return NULL; } if (!S_ISREG(sbuf.st_mode)) { fclose(fp); setoserror(ENOENT); return NULL; } return fp; }
static int pduread(int fd, char *buf, int len, int part, int timeout) { int socketipc = __pmSocketIPC(fd); int status = 0; int have = 0; int onetrip = 1; struct timeval dead_hand; struct timeval now; if (timeout == -2 /*TIMEOUT_ASYNC*/) return -EOPNOTSUPP; /* * Handle short reads that may split a PDU ... * * The original logic here assumed that recv() would only split a * PDU at a word (__pmPDU) boundary ... with the introduction of * secure connections, SSL and possibly compression all lurking * below the socket covers, this is no longer a safe assumption. * * So, we keep nibbling at the input stream until we have all that * we have requested, or we timeout, or error. */ while (len) { struct timeval wait; #if defined(IS_MINGW) /* cannot select on a pipe on Win32 - yay! */ if (!__pmSocketIPC(fd)) { COMMTIMEOUTS cwait = { 0 }; if (timeout != TIMEOUT_NEVER) cwait.ReadTotalTimeoutConstant = timeout * 1000.0; else cwait.ReadTotalTimeoutConstant = def_timeout * 1000.0; SetCommTimeouts((HANDLE)_get_osfhandle(fd), &cwait); } else #endif /* * either never timeout (i.e. block forever), or timeout */ if (timeout != TIMEOUT_NEVER) { if (timeout > 0) { wait.tv_sec = timeout; wait.tv_usec = 0; } else wait = def_wait; if (onetrip) { /* * Need all parts of the PDU to be received by dead_hand * This enforces a low overall timeout for the whole PDU * (as opposed to just a timeout for individual calls to * recv). A more invasive alternative (better) approach * would see all I/O performed in the main event loop, * and I/O routines transformed to continuation-passing * style. */ gettimeofday(&dead_hand, NULL); dead_hand.tv_sec += wait.tv_sec; dead_hand.tv_usec += wait.tv_usec; while (dead_hand.tv_usec >= 1000000) { dead_hand.tv_usec -= 1000000; dead_hand.tv_sec++; } onetrip = 0; } status = __pmSocketReady(fd, &wait); if (status > 0) { gettimeofday(&now, NULL); if (now.tv_sec > dead_hand.tv_sec || (now.tv_sec == dead_hand.tv_sec && now.tv_usec > dead_hand.tv_usec)) status = 0; } if (status == 0) { if (__pmGetInternalState() != PM_STATE_APPL) { /* special for PMCD and friends * Note, on Linux select would return 'time remaining' * in timeout value, so report the expected timeout */ int tosec, tomsec; if ( timeout != TIMEOUT_NEVER && timeout > 0 ) { tosec = (int)timeout; tomsec = 0; } else { tosec = (int)def_wait.tv_sec; tomsec = 1000*(int)def_wait.tv_usec; } __pmNotifyErr(LOG_WARNING, "pduread: timeout (after %d.%03d " "sec) while attempting to read %d " "bytes out of %d in %s on fd=%d", tosec, tomsec, len - have, len, part == HEADER ? "HDR" : "BODY", fd); } return PM_ERR_TIMEOUT; } else if (status < 0) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "pduread: select() on fd=%d: %s", fd, netstrerror_r(errmsg, sizeof(errmsg))); setoserror(neterror()); return status; } } if (socketipc) { status = __pmRecv(fd, buf, len, 0); setoserror(neterror()); } else { status = read(fd, buf, len); } __pmOverrideLastFd(fd); if (status < 0) /* error */ return status; else if (status == 0) /* return what we have, or nothing */ break; have += status; buf += status; len -= status; #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_PDU) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "pduread(%d, ...): have %d, last read %d, still need %d\n", fd, have, status, len); } #endif } return have; }
/* * Actually downloads the page, registering a hit (donation) * If the fileBuf passed in is NULL, the url is downloaded and then * freed; otherwise the necessary space is allocated for fileBuf. * Returns size of download on success, -1 on error is set, */ int http_fetch(const char *url_tmp, char **fileBuf) { fd_set rfds; struct timeval tv; char headerBuf[HEADER_BUF_SIZE]; char *tmp, *url, *pageBuf, *requestBuf = NULL, *host, *charIndex; int sock, bytesRead = 0, contentLength = -1, bufsize = REQUEST_BUF_SIZE; int i, ret = -1, tempSize, selectRet, found = 0, /* For redirects */ redirectsFollowed = 0; if(url_tmp == NULL) { errorSource = FETCHER_ERROR; http_errno = HF_NULLURL; return -1; } /* Copy the url passed in into a buffer we can work with, change, etc. */ url = malloc(strlen(url_tmp)+1); if(url == NULL) { errorSource = ERRNO; return -1; } strncpy(url, url_tmp, strlen(url_tmp) + 1); /* This loop allows us to follow redirects if need be. An afterthought, * added to provide this basic functionality. Will hopefully be designed * better in 2.x.x ;) */ /* while(!found && (followRedirects < 0 || redirectsFollowed < followRedirects) ) */ do { /* Seek to the file path portion of the url */ charIndex = strstr(url, "://"); if(charIndex != NULL) { /* url contains a protocol field */ charIndex += strlen("://"); host = charIndex; charIndex = strchr(charIndex, '/'); } else { host = (char *)url; charIndex = strchr(url, '/'); } /* Compose a request string */ requestBuf = malloc(bufsize); if(requestBuf == NULL) { free(url); errorSource = ERRNO; return -1; } requestBuf[0] = 0; if(charIndex == NULL) { /* The url has no '/' in it, assume the user is making a root-level * request */ tempSize = strlen("GET /") + strlen(HTTP_VERSION) + 2; if(_checkBufSize(&requestBuf, &bufsize, tempSize) || snprintf(requestBuf, bufsize, "GET / %s\r\n", HTTP_VERSION) < 0) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } } else { tempSize = strlen("GET ") + strlen(charIndex) + strlen(HTTP_VERSION) + 4; /* + 4 is for ' ', '\r', '\n', and NULL */ if(_checkBufSize(&requestBuf, &bufsize, tempSize) || snprintf(requestBuf, bufsize, "GET %s %s\r\n", charIndex, HTTP_VERSION) < 0) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } } /* Null out the end of the hostname if need be */ if(charIndex != NULL) *charIndex = 0; /* Use Host: even though 1.0 doesn't specify it. Some servers * won't play nice if we don't send Host, and it shouldn't * hurt anything */ ret = bufsize - strlen(requestBuf); /* Space left in buffer */ tempSize = (int)strlen("Host: ") + (int)strlen(host) + 3; /* +3 for "\r\n\0" */ if(_checkBufSize(&requestBuf, &bufsize, tempSize + 128)) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } strcat(requestBuf, "Host: "); strcat(requestBuf, host); strcat(requestBuf, "\r\n"); if(!hideReferer && referer != NULL) /* NO default referer */ { tempSize = (int)strlen("Referer: ") + (int)strlen(referer) + 3; /* + 3 is for '\r', '\n', and NULL */ if(_checkBufSize(&requestBuf, &bufsize, tempSize)) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } strcat(requestBuf, "Referer: "); strcat(requestBuf, referer); strcat(requestBuf, "\r\n"); } if(!hideUserAgent && userAgent == NULL) { tempSize = (int)strlen("User-Agent: ") + (int)strlen(DEFAULT_USER_AGENT) + (int)strlen(VERSION) + 4; /* + 4 is for '\', '\r', '\n', and NULL */ if(_checkBufSize(&requestBuf, &bufsize, tempSize)) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } strcat(requestBuf, "User-Agent: "); strcat(requestBuf, DEFAULT_USER_AGENT); strcat(requestBuf, "/"); strcat(requestBuf, VERSION); strcat(requestBuf, "\r\n"); } else if(!hideUserAgent) { tempSize = (int)strlen("User-Agent: ") + (int)strlen(userAgent) + 3; /* + 3 is for '\r', '\n', and NULL */ if(_checkBufSize(&requestBuf, &bufsize, tempSize)) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } strcat(requestBuf, "User-Agent: "); strcat(requestBuf, userAgent); strcat(requestBuf, "\r\n"); } tempSize = (int)strlen("Connection: Close\r\n\r\n"); if(_checkBufSize(&requestBuf, &bufsize, tempSize)) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } strcat(requestBuf, "Connection: Close\r\n\r\n"); /* Now free any excess memory allocated to the buffer */ tmp = realloc(requestBuf, strlen(requestBuf) + 1); if(tmp == NULL) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } requestBuf = tmp; sock = makeSocket(host); /* errorSource set within makeSocket */ if(sock == -1) { free(url); free(requestBuf); return -1;} free(url); url = NULL; if(write(sock, requestBuf, strlen(requestBuf)) == -1) { close(sock); free(requestBuf); errorSource = ERRNO; return -1; } free(requestBuf); requestBuf = NULL; /* Grab enough of the response to get the metadata */ ret = _http_read_header(sock, headerBuf); /* errorSource set within */ if(ret < 0) { close(sock); return -1; } /* Get the return code */ charIndex = strstr(headerBuf, "HTTP/"); if(charIndex == NULL) { close(sock); errorSource = FETCHER_ERROR; http_errno = HF_FRETURNCODE; return -1; } while(*charIndex != ' ') charIndex++; charIndex++; ret = sscanf(charIndex, "%d", &i); if(ret != 1) { close(sock); errorSource = FETCHER_ERROR; http_errno = HF_CRETURNCODE; return -1; } if(i<200 || i>307) { close(sock); errorInt = i; /* Status code, to be inserted in error string */ errorSource = FETCHER_ERROR; http_errno = HF_STATUSCODE; return -1; } /* If a redirect, repeat operation until final URL is found or we * redirect followRedirects times. Note the case sensitive "Location", * should probably be made more robust in the future (without relying * on the non-standard strcasecmp()). * This bit mostly by Dean Wilder, tweaked by me */ if(i >= 300) { redirectsFollowed++; /* Pick up redirect URL, allocate new url, and repeat process */ charIndex = strstr(headerBuf, "Location:"); if(!charIndex) { close(sock); errorInt = i; /* Status code, to be inserted in error string */ errorSource = FETCHER_ERROR; http_errno = HF_CANTREDIRECT; return -1; } charIndex += strlen("Location:"); /* Skip any whitespace... */ while(*charIndex != '\0' && isspace((int)*charIndex)) charIndex++; if(*charIndex == '\0') { close(sock); errorInt = i; /* Status code, to be inserted in error string */ errorSource = FETCHER_ERROR; http_errno = HF_CANTREDIRECT; return -1; } i = strcspn(charIndex, " \r\n"); if(i > 0) { url = (char *)malloc(i + 1); strncpy(url, charIndex, i); url[i] = '\0'; } else /* Found 'Location:' but contains no URL! We'll handle it as * 'found', hopefully the resulting document will give the user * a hint as to what happened. */ found = 1; } else found = 1; } while(!found && (followRedirects < 0 || redirectsFollowed <= followRedirects) ); if(url) /* Redirection code may malloc this, then exceed followRedirects */ { free(url); url = NULL; } if(redirectsFollowed >= followRedirects && !found) { close(sock); errorInt = followRedirects; /* To be inserted in error string */ errorSource = FETCHER_ERROR; http_errno = HF_MAXREDIRECTS; return -1; } /* * Parse out about how big the data segment is. * Note that under current HTTP standards (1.1 and prior), the * Content-Length field is not guaranteed to be accurate or even present. * I just use it here so I can allocate a ballpark amount of memory. * * Note that some servers use different capitalization */ charIndex = strstr(headerBuf, "Content-Length:"); if(charIndex == NULL) charIndex = strstr(headerBuf, "Content-length:"); if(charIndex != NULL) { ret = sscanf(charIndex + strlen("content-length: "), "%d", &contentLength); if(ret < 1) { close(sock); errorSource = FETCHER_ERROR; http_errno = HF_CONTENTLEN; return -1; } } /* Allocate enough memory to hold the page */ if(contentLength == -1) contentLength = DEFAULT_PAGE_BUF_SIZE; pageBuf = (char *)malloc(contentLength); if(pageBuf == NULL) { close(sock); errorSource = ERRNO; return -1; } /* Begin reading the body of the file */ while(ret > 0) { FD_ZERO(&rfds); FD_SET(sock, &rfds); tv.tv_sec = timeout; tv.tv_usec = 0; if(timeout >= 0) selectRet = select(sock+1, &rfds, NULL, NULL, &tv); else /* No timeout, can block indefinately */ selectRet = select(sock+1, &rfds, NULL, NULL, NULL); if(selectRet == 0) { errorSource = FETCHER_ERROR; http_errno = HF_DATATIMEOUT; errorInt = timeout; close(sock); free(pageBuf); return -1; } else if(selectRet == -1) { setoserror(neterror()); close(sock); free(pageBuf); errorSource = ERRNO; return -1; } ret = recv(sock, pageBuf + bytesRead, contentLength, 0); if(ret == -1) { setoserror(neterror()); close(sock); free(pageBuf); errorSource = ERRNO; return -1; } bytesRead += ret; if(ret > 0) { /* To be tolerant of inaccurate Content-Length fields, we'll * allocate another read-sized chunk to make sure we have * enough room. */ tmp = (char *)realloc(pageBuf, bytesRead + contentLength); if(tmp == NULL) { close(sock); free(pageBuf); errorSource = ERRNO; return -1; } pageBuf = tmp; } } /* * The download buffer is too large. Trim off the safety padding. * Note that we add one NULL byte to the end of the data, as it may not * already be NULL terminated and we can't be sure what type of data it * is or what the caller will do with it. */ tmp = (char *)realloc(pageBuf, bytesRead + 1); /* tmp shouldn't be null, since we're _shrinking_ the buffer, * and if it DID fail, we could go on with the too-large buffer, * but something would DEFINATELY be wrong, so we'll just give * an error message */ if(tmp == NULL) { close(sock); free(pageBuf); errorSource = ERRNO; return -1; } pageBuf = tmp; pageBuf[bytesRead] = '\0'; /* NULL terminate the data */ if(fileBuf == NULL) /* They just wanted us to "hit" the url */ free(pageBuf); else *fileBuf = pageBuf; close(sock); return bytesRead; }
int DoFetch(ClientInfo *cip, __pmPDU* pb) { int i, j; int sts; int ctxnum; __pmTimeval when; int nPmids; pmID *pmidList; static pmResult *endResult = NULL; static int maxnpmids = 0; /* sizes endResult */ DomPmidList *dList; /* NOTE: NOT indexed by agent index */ static int nDoms = 0; static pmResult **results = NULL; static int *resIndex = NULL; __pmFdSet waitFds; __pmFdSet readyFds; int nWait; int maxFd; struct timeval timeout; if (nAgents > nDoms) { if (results != NULL) free(results); if (resIndex != NULL) free(resIndex); results = (pmResult **)malloc((nAgents + 1) * sizeof (pmResult *)); resIndex = (int *)malloc((nAgents + 1) * sizeof(int)); if (results == NULL || resIndex == NULL) { __pmNoMem("DoFetch.results", (nAgents + 1) * sizeof (pmResult *) + (nAgents + 1) * sizeof(int), PM_FATAL_ERR); } nDoms = nAgents; } memset(results, 0, (nAgents + 1) * sizeof(results[0])); sts = __pmDecodeFetch(pb, &ctxnum, &when, &nPmids, &pmidList); if (sts < 0) return sts; /* Check that a profile has been received from the specified context */ if (ctxnum < 0 || ctxnum >= cip->szProfile || cip->profile[ctxnum] == NULL) { __pmUnpinPDUBuf(pb); if (ctxnum < 0 || ctxnum >= cip->szProfile) __pmNotifyErr(LOG_ERR, "DoFetch: bad ctxnum=%d\n", ctxnum); else __pmNotifyErr(LOG_ERR, "DoFetch: no profile for ctxnum=%d\n", ctxnum); return PM_ERR_NOPROFILE; } if (nPmids > maxnpmids) { int need; if (endResult != NULL) free(endResult); need = (int)sizeof(pmResult) + (nPmids - 1) * (int)sizeof(pmValueSet *); if ((endResult = (pmResult *)malloc(need)) == NULL) { __pmNoMem("DoFetch.endResult", need, PM_FATAL_ERR); } maxnpmids = nPmids; } dList = SplitPmidList(nPmids, pmidList); /* For each domain in the split pmidList, dispatch the per-domain subset * of pmIDs to the appropriate agent. For DSO agents, the pmResult will * come back immediately. If a request cannot be sent to an agent, a * suitable pmResult (containing metric not available values) will be * returned. */ __pmFD_ZERO(&waitFds); nWait = 0; maxFd = -1; for (i = 0; dList[i].domain != -1; i++) { j = mapdom[dList[i].domain]; results[j] = SendFetch(&dList[i], &agent[j], cip, ctxnum); if (results[j] == NULL) { /* Wait for agent's response */ int fd = agent[j].outFd; agent[j].status.busy = 1; __pmFD_SET(fd, &waitFds); if (fd > maxFd) maxFd = fd; nWait++; } } /* Construct pmResult for bad-pmID list */ if (dList[i].listSize != 0) results[nAgents] = MakeBadResult(dList[i].listSize, dList[i].list, PM_ERR_NOAGENT); /* Wait for results to roll in from agents */ while (nWait > 0) { __pmFD_COPY(&readyFds, &waitFds); if (nWait > 1) { timeout.tv_sec = _pmcd_timeout; timeout.tv_usec = 0; retry: setoserror(0); sts = __pmSelectRead(maxFd+1, &readyFds, &timeout); if (sts == 0) { __pmNotifyErr(LOG_INFO, "DoFetch: select timeout"); /* Timeout, terminate agents with undelivered results */ for (i = 0; i < nAgents; i++) { if (agent[i].status.busy) { /* Find entry in dList for this agent */ for (j = 0; dList[j].domain != -1; j++) if (dList[j].domain == agent[i].pmDomainId) break; results[i] = MakeBadResult(dList[j].listSize, dList[j].list, PM_ERR_NOAGENT); pmcd_trace(TR_RECV_TIMEOUT, agent[i].outFd, PDU_RESULT, 0); CleanupAgent(&agent[i], AT_COMM, agent[i].inFd); } } break; } else if (sts < 0) { if (neterror() == EINTR) goto retry; /* this is not expected to happen! */ __pmNotifyErr(LOG_ERR, "DoFetch: fatal select failure: %s\n", netstrerror()); Shutdown(); exit(1); } } /* Read results from agents that have them ready */ for (i = 0; i < nAgents; i++) { AgentInfo *ap = &agent[i]; int pinpdu; if (!ap->status.busy || !__pmFD_ISSET(ap->outFd, &readyFds)) continue; ap->status.busy = 0; __pmFD_CLR(ap->outFd, &waitFds); nWait--; pinpdu = sts = __pmGetPDU(ap->outFd, ANY_SIZE, _pmcd_timeout, &pb); if (sts > 0) pmcd_trace(TR_RECV_PDU, ap->outFd, sts, (int)((__psint_t)pb & 0xffffffff)); if (sts == PDU_RESULT) { if ((sts = __pmDecodeResult(pb, &results[i])) >= 0) if (results[i]->numpmid != aFreq[i]) { pmFreeResult(results[i]); sts = PM_ERR_IPC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_ERR, "DoFetch: \"%s\" agent given %d pmIDs, returned %d\n", ap->pmDomainLabel, aFreq[i], results[i]->numpmid); #endif } } else { if (sts == PDU_ERROR) { int s; if ((s = __pmDecodeError(pb, &sts)) < 0) sts = s; else if (sts >= 0) sts = PM_ERR_GENERIC; pmcd_trace(TR_RECV_ERR, ap->outFd, PDU_RESULT, sts); } else if (sts >= 0) { pmcd_trace(TR_WRONG_PDU, ap->outFd, PDU_RESULT, sts); sts = PM_ERR_IPC; } } if (pinpdu > 0) __pmUnpinPDUBuf(pb); if (sts < 0) { /* Find entry in dList for this agent */ for (j = 0; dList[j].domain != -1; j++) if (dList[j].domain == agent[i].pmDomainId) break; results[i] = MakeBadResult(dList[j].listSize, dList[j].list, sts); if (sts == PM_ERR_PMDANOTREADY) { /* the agent is indicating it can't handle PDUs for now */ int k; extern int CheckError(AgentInfo *ap, int sts); for (k = 0; k < dList[j].listSize; k++) results[i]->vset[k]->numval = PM_ERR_AGAIN; sts = CheckError(&agent[i], sts); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "RESULT error from \"%s\" agent : %s\n", ap->pmDomainLabel, pmErrStr(sts)); } #endif if (sts == PM_ERR_IPC || sts == PM_ERR_TIMEOUT) CleanupAgent(ap, AT_COMM, ap->outFd); } } } endResult->numpmid = nPmids; __pmtimevalNow(&endResult->timestamp); /* The order of the pmIDs in the per-domain results is the same as in the * original request, but on a per-domain basis. resIndex is an array of * indices (one per agent) of the next metric to be retrieved from each * per-domain result's vset. */ memset(resIndex, 0, (nAgents + 1) * sizeof(resIndex[0])); for (i = 0; i < nPmids; i++) { j = mapdom[((__pmID_int *)&pmidList[i])->domain]; endResult->vset[i] = results[j]->vset[resIndex[j]++]; } pmcd_trace(TR_XMIT_PDU, cip->fd, PDU_RESULT, endResult->numpmid); sts = 0; if (cip->status.changes) { /* notify client of PMCD state change */ sts = __pmSendError(cip->fd, FROM_ANON, (int)cip->status.changes); if (sts > 0) sts = 0; cip->status.changes = 0; } if (sts == 0) sts = __pmSendResult(cip->fd, FROM_ANON, endResult); if (sts < 0) { pmcd_trace(TR_XMIT_ERR, cip->fd, PDU_RESULT, sts); CleanupClient(cip, sts); } /* * pmFreeResult() all the accumulated results. */ for (i = 0; dList[i].domain != -1; i++) { j = mapdom[dList[i].domain]; if (agent[j].ipcType == AGENT_DSO && agent[j].status.connected && !agent[j].status.madeDsoResult) /* Living DSO's manage their own pmResult skeleton unless * MakeBadResult was called to create the result. The value sets * within the skeleton need to be freed though! */ __pmFreeResultValues(results[j]); else /* For others it is dynamically allocated in __pmDecodeResult or * MakeBadResult */ pmFreeResult(results[j]); } if (results[nAgents] != NULL) pmFreeResult(results[nAgents]); __pmUnpinPDUBuf(pmidList); return 0; }
static int pduread(int fd, char *buf, int len, int mode, int timeout) { /* * handle short reads that may split a PDU ... */ int status = 0; int have = 0; __pmFdSet onefd; static int done_default = 0; static struct timeval def_wait = { 10, 0 }; if (timeout == TRACE_TIMEOUT_DEFAULT) { if (!done_default) { double def_timeout; char *timeout_str; char *end_ptr; if ((timeout_str = getenv(TRACE_ENV_REQTIMEOUT)) != NULL) { def_timeout = strtod(timeout_str, &end_ptr); if (*end_ptr != '\0' || def_timeout < 0.0) { status = PMTRACE_ERR_ENVFORMAT; return status; } else { pmtimevalFromReal(def_timeout, &def_wait); } } done_default = 1; } } while (len) { struct timeval wait; /* * either never timeout (i.e. block forever), or timeout */ if (timeout != TRACE_TIMEOUT_NEVER) { if (timeout > 0) { wait.tv_sec = timeout; wait.tv_usec = 0; } else wait = def_wait; __pmFD_ZERO(&onefd); __pmFD_SET(fd, &onefd); status = __pmSelectRead(fd+1, &onefd, &wait); if (status == 0) return PMTRACE_ERR_TIMEOUT; else if (status < 0) { setoserror(neterror()); return status; } } status = (int)__pmRead(fd, buf, len); if (status <= 0) { /* EOF or error */ setoserror(neterror()); return status; } if (mode == -1) /* special case, see __pmtracegetPDU */ return status; have += status; buf += status; len -= status; } return have; }
int __pmStringValue(const char *buf, pmAtomValue *avp, int type) { const char *p = buf; char *endbuf; int vtype = IS_UNKNOWN; int seendot = 0; int base; double d; __int64_t temp_l; __uint64_t temp_ul; /* * for strtol() et al, start with optional white space, then * optional sign, then optional hex prefix, then stuff ... */ while (*p && isspace((int)*p)) p++; if (*p && *p == '-') p++; if (*p && *p == '0' && p[1] && tolower((int)p[1]) == 'x') { p += 2; } else { vtype &= ~IS_HEX; /* hex MUST start with 0x or 0X */ } /* * does it smell like a hex number or a floating point number? */ while (*p) { if (!isdigit((int)*p)) { vtype &= ~IS_INTEGER; if (!isxdigit((int)*p) ) { vtype &= ~IS_HEX; if (*p == '.') seendot++; } } p++; } if (seendot != 1) /* more or less than one '.' and it is not a floating point number */ vtype &= ~IS_FLOAT; endbuf = (char *)buf; base = (vtype & IS_HEX) ? 16:10; switch (type) { case PM_TYPE_32: temp_l = strtol(buf, &endbuf, base); if (oserror() != ERANGE) { /* * ugliness here is for cases where pmstore is compiled * 64-bit (e.g. on ia64) and then strtol() may return * values larger than 32-bits with no error indication * ... if this is being compiled 32-bit, then the * condition will be universally false, and a smart * compiler may notice and warn. */ #ifdef HAVE_64BIT_LONG if (temp_l > 0x7fffffffLL || temp_l < (-0x7fffffffLL - 1)) setoserror(ERANGE); else #endif { avp->l = (__int32_t)temp_l; } } break; case PM_TYPE_U32: temp_ul = strtoul(buf, &endbuf, base); if (oserror() != ERANGE) { #ifdef HAVE_64BIT_LONG if (temp_ul > 0xffffffffLL) setoserror(ERANGE); else #endif { avp->ul = (__uint32_t)temp_ul; } } break; case PM_TYPE_64: avp->ll = strtoll(buf, &endbuf, base); /* trust library to set error code to ERANGE as appropriate */ break; case PM_TYPE_U64: /* trust library to set error code to ERANGE as appropriate */ avp->ull = strtoull(buf, &endbuf, base); break; case PM_TYPE_FLOAT: if (vtype & IS_HEX) { /* * strtod from GNU libc would try to convert it using an * algorithm we don't want used here */ endbuf = (char *)buf; } else { d = strtod(buf, &endbuf); if (fabs(d) < FLT_MIN || fabs(d) > FLT_MAX) { setoserror(ERANGE); } else { avp->f = (float)d; } } break; case PM_TYPE_DOUBLE: if (vtype & IS_HEX) { /* * strtod from GNU libc would try to convert it using an * algorithm we don't want used here */ endbuf = (char *)buf; } else { avp->d = strtod(buf, &endbuf); } break; case PM_TYPE_STRING: if ((avp->cp = strdup(buf)) == NULL) return -ENOMEM; endbuf = ""; break; } if (*endbuf != '\0') return PM_ERR_TYPE; if (oserror() == ERANGE) return -oserror(); return 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; }