コード例 #1
0
ファイル: trace.c プロジェクト: tongfw/pcp
static int
_pmtracereconnect(void)
{
#ifdef PMTRACE_DEBUG
    if (__pmstate & PMTRACE_STATE_NOAGENT) {
	fprintf(stderr, "_pmtracereconnect: reconnect attempt (skipped)\n");
	return 0;
    }
    else if (__pmstate &  PMTRACE_STATE_COMMS) {
	fprintf(stderr, "_pmtracereconnect: attempting PMDA reconnection\n");
    }
#endif

    if (_pmtimedout && time(NULL) < _pmttimeout) {	/* too soon to retry */
#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS)
	    fprintf(stderr, "_pmtracereconnect: too soon to retry "
			    "(%d seconds remain)\n", (int)(_pmttimeout - time(NULL)));
#endif
	return -ETIMEDOUT;
    }
    if (__pmfd >= 0) {
	__pmtracenomoreinput(__pmfd);
	__pmCloseSocket(__pmfd);
	__pmfd = -1;
    }
    if (_pmtraceconnect(1) < 0) {
#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS)
	    fprintf(stderr, "_pmtracereconnect: failed to reconnect\n");
#endif
	_pmtraceupdatewait();
	return -ETIMEDOUT;
    }
    else {
#ifdef PMTRACE_DEBUG
	if (__pmstate & PMTRACE_STATE_COMMS)
	    fprintf(stderr, "_pmtracereconnect: reconnect succeeded!\n");
#endif
	_pmtimedout = 0;
    }
    return 0;
}
コード例 #2
0
ファイル: pdu.c プロジェクト: goodwinos/pcp
int
__pmtracegetPDU(int fd, int timeout, __pmTracePDU **result)
{
    int			need, len;
    char		*handle;
    static int		maxsize = TRACE_PDU_CHUNK;
    __pmTracePDU	*pdubuf;
    __pmTracePDU	*pdubuf_prev;
    __pmTracePDUHdr	*php;

    /*
     *	This stuff is a little tricky.  What we try to do is read()
     *	an amount of data equal to the largest PDU we have (or are
     *	likely to have) seen thus far.  In the majority of cases
     *	this returns exactly one PDU's worth, i.e. read() returns
     *	a length equal to php->len.
     *
     *	For this to work, we have a special "mode" of -1
     *	to pduread() which means read, but return after the
     *	first read(), rather than trying to read up to the request
     *	length with multiple read()s, which would of course "hang"
     *	after the first PDU arrived.
     *
     *   We need to handle the following tricky cases:
     *   1. We get _more_ than we need for a single PDU -- happens
     *      when PDU's arrive together.  This requires "moreinput"
     *      to handle leftovers here (it gets even uglier if we
     *      have part, but not all of the second PDU).
     *   2. We get _less_ than we need for a single PDU -- this
     *      requires at least another read(), and possibly acquiring
     *      another pdubuf and doing a memcpy() for the partial PDU
     *      from the earlier call.
     */
    if (__pmtracemoreinput(fd)) {
	/* some leftover from last time ... handle -> start of PDU */
	pdubuf = more[fd].pdubuf;
	len = more[fd].len;
	__pmtracenomoreinput(fd);
    }
    else {
	if ((pdubuf = __pmtracefindPDUbuf(maxsize)) == NULL)
	    return -oserror();
	len = pduread(fd, (void *)pdubuf, maxsize, -1, timeout);
    }
    php = (__pmTracePDUHdr *)pdubuf;

    if (len < (int)sizeof(__pmTracePDUHdr)) {
	if (len == -1) {
	    if (oserror() == ECONNRESET||
		oserror() == ETIMEDOUT || oserror() == ENETDOWN ||
		oserror() == ENETUNREACH || oserror() == EHOSTDOWN ||
		oserror() == EHOSTUNREACH || oserror() == ECONNREFUSED)
		/*
		 * failed as a result of pmdatrace exiting and the
		 * connection being reset, or as a result of the kernel
		 * ripping down the connection (most likely because the
		 * host at the other end just took a dive)
		 *
		 * treat this like end of file on input
		 *
		 * from irix/kern/fs/nfs/bds.c seems like all of the
		 * following are peers here:
		 *  ECONNRESET (pmdatrace terminated?)
		 *  ETIMEDOUT ENETDOWN ENETUNREACH EHOSTDOWN EHOSTUNREACH
		 *  ECONNREFUSED
		 * peers for bds but not here:
		 *  ENETRESET ENONET ESHUTDOWN (cache_fs only?)
		 *  ECONNABORTED (accept, user req only?)
		 *  ENOTCONN (udp?)
		 *  EPIPE EAGAIN (nfs, bds & ..., but not ip or tcp?)
		 */
		len = 0;
	    else
		fprintf(stderr, "__pmtracegetPDU: fd=%d hdr: %s",
			fd, osstrerror());
	}
	else if (len > 0)
	    fprintf(stderr, "__pmtracegetPDU: fd=%d hdr: len=%d, not %d?",
			fd, len, (int)sizeof(__pmTracePDUHdr));
	else if (len == PMTRACE_ERR_TIMEOUT)
	    return PMTRACE_ERR_TIMEOUT;
	else if (len < 0)
	    fprintf(stderr, "__pmtracegetPDU: fd=%d hdr: %s", fd, pmtraceerrstr(len));
	return len ? PMTRACE_ERR_IPC : 0;
    }

    php->len = ntohl(php->len);
    if (php->len < 0) {
	fprintf(stderr, "__pmtracegetPDU: fd=%d illegal len=%d in hdr\n", fd, php->len);
	return PMTRACE_ERR_IPC;
    }

    if (len == php->len)
	/* return below */
	;
    else if (len > php->len) {
	/*
	 * read more than we need for this one, save it up for next time
	 */
	handle = (char *)pdubuf;
	moreinput(fd, (__pmTracePDU *)&handle[php->len], len - php->len);
    }
    else {
	int	tmpsize;

	/*
	 * need to read more ...
	 */
	__pmtracepinPDUbuf(pdubuf);
	pdubuf_prev = pdubuf;
	if (php->len > maxsize)
	    tmpsize = TRACE_PDU_CHUNK * ( 1 + php->len / TRACE_PDU_CHUNK);
	else
	    tmpsize = maxsize;
	if ((pdubuf = __pmtracefindPDUbuf(tmpsize)) == NULL) {
	    __pmtraceunpinPDUbuf(pdubuf_prev);
	    return -oserror();
	}
	if (php->len > maxsize)
	    maxsize = tmpsize;
	memmove((void *)pdubuf, (void *)php, len);
	__pmtraceunpinPDUbuf(pdubuf_prev);
	php = (__pmTracePDUHdr *)pdubuf;
	need = php->len - len;
	handle = (char *)pdubuf;
	/* block until all of the PDU is received this time */
	len = pduread(fd, (void *)&handle[len], need, 0, timeout);
	if (len != need) {
	    if (len == PMTRACE_ERR_TIMEOUT)
		return PMTRACE_ERR_TIMEOUT;
	    if (len < 0)
		fprintf(stderr, "__pmtracegetPDU: error (%d) fd=%d: %s\n", (int)oserror(), fd, osstrerror());
	    else
		fprintf(stderr, "__pmtracegetPDU: len=%d, not %d? (fd=%d)\n", len, need, fd);
	    fprintf(stderr, "hdr: len=0x%08x type=0x%08x from=0x%08x\n",
			php->len, (int)ntohl(php->type), (int)ntohl(php->from));
	    return PMTRACE_ERR_IPC;
	}
    }

    *result = (__pmTracePDU *)php;
    php->type = ntohl(php->type);
    php->from = ntohl(php->from);
#ifdef PMTRACE_DEBUG
    if (__pmstate & PMTRACE_STATE_PDU) {
	int		j;
	int		jend = (int)(php->len+(int)sizeof(__pmTracePDU)-1)/(int)sizeof(__pmTracePDU);
	char	*p;

	/* for Purify ... */
	p = (char *)*result + php->len;
	while (p < (char *)*result + jend*sizeof(__pmTracePDU))
	    *p++ = '~';	/* buffer end */

	fprintf(stderr, "[%" FMT_PID "]__pmtracegetPDU: %s fd=%d len=%d from=%d",
		(pid_t)getpid(), pdutypestr(php->type), fd, php->len, php->from);

	for (j = 0; j < jend; j++) {
	    if ((j % 8) == 0)
		fprintf(stderr, "\n%03d: ", j);
	    fprintf(stderr, "%8x ", (*result)[j]);
	}
	putc('\n', stderr);
    }
#endif

    return php->type;
}