Ejemplo n.º 1
0
	/*
	 * 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;
	}
Ejemplo n.º 2
0
Archivo: trace.c Proyecto: tongfw/pcp
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
Archivo: pmcpp.c Proyecto: Aconex/pcp
/*
 * 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;
}
Ejemplo n.º 5
0
Archivo: pdu.c Proyecto: rwongone/pcp
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;
}
Ejemplo n.º 6
0
	/* 
	 * 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;
	}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
Archivo: pdu.c Proyecto: goodwinos/pcp
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;
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
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;
}