summaryrefslogtreecommitdiff
path: root/src/libpcp_qmc/src/qmc_source.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libpcp_qmc/src/qmc_source.cpp')
-rw-r--r--src/libpcp_qmc/src/qmc_source.cpp425
1 files changed, 425 insertions, 0 deletions
diff --git a/src/libpcp_qmc/src/qmc_source.cpp b/src/libpcp_qmc/src/qmc_source.cpp
new file mode 100644
index 0000000..3935217
--- /dev/null
+++ b/src/libpcp_qmc/src/qmc_source.cpp
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2013 Red Hat.
+ * Copyright (c) 2007 Aconex. All Rights Reserved.
+ * Copyright (c) 1998,2005 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+#include "qmc_source.h"
+
+QString QmcSource::localHost;
+QList<QmcSource*> QmcSource::sourceList;
+
+QmcSource::QmcSource(int type, QString &source, int flags)
+{
+ my.status = -1;
+ my.flags = flags;
+ my.type = type;
+ my.tz = 0;
+ my.dupFlag = false;
+
+ if (localHost.length() == 0) {
+ char buf[MAXHOSTNAMELEN];
+ gethostname(buf, MAXHOSTNAMELEN);
+ buf[MAXHOSTNAMELEN-1] = '\0';
+ localHost = buf;
+ }
+
+ this->retryConnect(type, source);
+}
+
+void
+QmcSource::retryConnect(int type, QString &source)
+{
+ int oldTZ;
+ int oldContext;
+ int offset;
+ int sts;
+ char *tzs;
+ QString hostSpec;
+
+ my.attrs = QString::null;
+ switch(type) {
+ case PM_CONTEXT_LOCAL:
+ my.desc = "Local context";
+ my.host = my.source = localHost;
+ my.proxy = "";
+ break;
+
+ case PM_CONTEXT_HOST:
+ my.desc = "host \"";
+ my.desc.append(source);
+ my.desc.append(QChar('\"'));
+ my.host = source;
+ my.proxy = getenv("PMPROXY_HOST");
+ if ((offset = my.host.indexOf('?')) >= 0) {
+ my.attrs = my.host;
+ my.attrs.remove(0, offset+1);
+ my.host.truncate(offset);
+ }
+ if ((offset = my.host.indexOf('@')) >= 0) {
+ my.proxy = my.host;
+ my.proxy.remove(0, offset+1);
+ }
+ my.source = my.host;
+ break;
+
+ case PM_CONTEXT_ARCHIVE:
+ my.desc = "archive \"";
+ my.desc.append(source);
+ my.desc.append(QChar('\"'));
+ my.source = source;
+ my.proxy = "";
+ break;
+ }
+
+ oldContext = pmWhichContext();
+
+ hostSpec = source;
+ if (my.attrs != QString::null)
+ hostSpec.append("?").append(my.attrs);
+
+ my.status = pmNewContext(type | my.flags, (const char *)hostSpec.toAscii());
+ if (my.status >= 0) {
+ my.handles.append(my.status);
+
+ // Fetch the server-side host name for this context, properly as of pcp 3.8.3+.
+ my.context_hostname = pmGetContextHostName (my.status); // NB: may leak memory
+ if (my.context_hostname == "") // may be returned for errors or PM_CONTEXT_LOCAL
+ my.context_hostname = localHost;
+
+ if (my.type == PM_CONTEXT_ARCHIVE) {
+ pmLogLabel lp;
+ sts = pmGetArchiveLabel(&lp);
+ if (sts < 0) {
+ pmprintf("%s: Unable to obtain log label for \"%s\": %s\n",
+ pmProgname, (const char *)my.desc.toAscii(),
+ pmErrStr(sts));
+ my.host = "unknown?";
+ my.status = sts;
+ goto done;
+ }
+ else {
+ my.host = lp.ll_hostname;
+ my.start = lp.ll_start;
+ }
+ sts = pmGetArchiveEnd(&my.end);
+ if (sts < 0) {
+ pmprintf("%s: Unable to determine end of \"%s\": %s\n",
+ pmProgname, (const char *)my.desc.toAscii(),
+ pmErrStr(sts));
+ my.status = sts;
+ goto done;
+ }
+ }
+ else {
+ gettimeofday(&my.start, NULL);
+ my.end = my.start;
+ }
+
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcSource::QmcSource: Created context "
+ << my.handles.last() << " to " << my.desc << endl;
+ }
+
+ oldTZ = pmWhichZone(&tzs);
+ my.tz = pmNewContextZone();
+ if (my.tz < 0)
+ pmprintf("%s: Warning: Unable to obtain timezone for %s: %s\n",
+ pmProgname, (const char *)my.desc.toAscii(),
+ pmErrStr(my.tz));
+ else {
+ sts = pmWhichZone(&tzs);
+ if (sts >= 0)
+ my.timezone = tzs;
+ else
+ pmprintf("%s: Warning: Unable to obtain timezone for %s: %s\n",
+ pmProgname, (const char *)my.desc.toAscii(),
+ pmErrStr(sts));
+ }
+
+ if (oldTZ >= 0) {
+ sts = pmUseZone(oldTZ);
+ if (sts < 0) {
+ pmprintf("%s: Warning: Unable to switch timezones."
+ " Using timezone for %s: %s\n",
+ pmProgname, (const char *)my.desc.toAscii(),
+ pmErrStr(sts));
+ }
+ }
+ }
+ else if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcSource::QmcSource: Context to " << source
+ << " failed: " << pmErrStr(my.status) << endl;
+ }
+
+ done:
+ sourceList.append(this);
+
+ if (oldContext >= 0) {
+ sts = pmUseContext(oldContext);
+ if (sts < 0) {
+ pmprintf("%s: Warning: Unable to switch contexts."
+ " Using context to %s: %s\n",
+ pmProgname, (const char *)my.desc.toAscii(),
+ pmErrStr(sts));
+ }
+ }
+}
+
+QmcSource::~QmcSource()
+{
+ int i;
+
+ for (i = 0; i < sourceList.size(); i++)
+ if (sourceList[i] == this)
+ break;
+ if (i < sourceList.size())
+ sourceList.removeAt(i);
+}
+
+QString
+QmcSource::timeString(const struct timeval *timeval)
+{
+ QString timestring;
+ char timebuf[32], *ddmm, *year;
+ struct tm tmp;
+ time_t secs = (time_t)timeval->tv_sec;
+
+ ddmm = pmCtime(&secs, timebuf);
+ ddmm[10] = '\0';
+ year = &ddmm[20];
+ year[4] = '\0';
+ pmLocaltime(&secs, &tmp);
+
+ timestring.sprintf("%02d:%02d:%02d.%03d",
+ tmp.tm_hour, tmp.tm_min, tmp.tm_sec, (int)(timeval->tv_usec/1000));
+ timestring.prepend(" ");
+ timestring.prepend(ddmm);
+ timestring.append(" ");
+ timestring.append(year);
+ return timestring;
+}
+
+QString
+QmcSource::timeStringBrief(const struct timeval *timeval)
+{
+ QString timestring;
+ struct tm tmp;
+ time_t secs = (time_t)timeval->tv_sec;
+
+ pmLocaltime(&secs, &tmp);
+ timestring.sprintf("%02d:%02d:%02d.%03d",
+ tmp.tm_hour, tmp.tm_min, tmp.tm_sec, (int)(timeval->tv_usec/1000));
+ return timestring;
+}
+
+bool
+QmcSource::compare(int type, QString &source, int flags)
+{
+ if (this->type() != type)
+ return false;
+ if (this->flags() != flags)
+ return false;
+ return this->source() == source;
+}
+
+QmcSource*
+QmcSource::getSource(int type, QString &source, int flags, bool matchHosts)
+{
+ int i;
+ QmcSource *src = NULL;
+
+ for (i = 0; i < sourceList.size(); i++) {
+ src = sourceList[i];
+ if (matchHosts && type == PM_CONTEXT_HOST) {
+ if (src->type() == PM_CONTEXT_ARCHIVE && src->host() == source) {
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcSource::getSource: Matched host "
+ << source << " to archive " << src->source()
+ << " (source " << i << ")" << endl;
+ }
+ break;
+ }
+ }
+ else if (src->compare(type, source, flags)) {
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcSource::getSource: Matched " << source
+ << " to source " << i << endl;
+ }
+ if (src->status() < 0)
+ src->retryConnect(type, source);
+ break;
+ }
+ }
+
+ if (i == sourceList.size() &&
+ !(matchHosts == true && type == PM_CONTEXT_HOST)) {
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ if (type != PM_CONTEXT_LOCAL)
+ cerr << "QmcSource::getSource: Creating new source for "
+ << source << endl;
+ else
+ cerr << "QmcSource::getSource: Creating new local context"
+ << endl;
+ }
+ src = new QmcSource(type, source, flags);
+ }
+
+ if (src == NULL && pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcSource::getSource: Unable to map host "
+ << source << " to an arch context" << endl;
+ }
+
+ return src;
+}
+
+int
+QmcSource::dupContext()
+{
+ int sts = 0;
+
+ if (my.status < 0)
+ return my.status;
+
+ if (my.dupFlag == false && my.handles.size() == 1) {
+ sts = pmUseContext(my.handles[0]);
+ if (sts >= 0) {
+ sts = my.handles[0];
+ my.dupFlag = true;
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcSource::dupContext: Using original context for "
+ << my.desc << endl;
+ }
+ }
+ else
+ pmprintf("%s: Error: Unable to switch to context for \"%s\": %s\n",
+ pmProgname, (const char *)my.desc.toAscii(),
+ pmErrStr(sts));
+ }
+ else if (my.handles.size()) {
+ sts = pmUseContext(my.handles[0]);
+ if (sts >= 0) {
+ sts = pmDupContext();
+ if (sts >= 0) {
+ my.handles.append(sts);
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcSource::dupContext: " << my.desc
+ << " duplicated, handle[" << my.handles.size() - 1
+ << "] = " << sts << endl;
+ }
+ }
+ else
+ pmprintf("%s: Error: "
+ "Unable to duplicate context to \"%s\": %s\n",
+ pmProgname, (const char *)my.desc.toAscii(),
+ pmErrStr(sts));
+ }
+ else
+ pmprintf("%s: Error: Unable to switch to context for \"%s\": %s\n",
+ pmProgname, (const char *)my.desc.toAscii(),
+ pmErrStr(sts));
+ }
+ // No active contexts, create a new context
+ else {
+ sts = pmNewContext(my.type, sourceAscii());
+ if (sts >= 0) {
+ my.handles.append(sts);
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcSource::dupContext: new context to " << my.desc
+ << " created, handle = " << sts << endl;
+ }
+ }
+ }
+
+ if (sts < 0 && pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcSource::dupContext: context to " << my.desc
+ << " failed: " << pmErrStr(my.status) << endl;
+ }
+
+ return sts;
+}
+
+int
+QmcSource::delContext(int handle)
+{
+ int i;
+ int sts;
+
+ for (i = 0; i < my.handles.size(); i++)
+ if (my.handles[i] == handle)
+ break;
+
+ if (i == my.handles.size()) {
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcSource::delContext: Attempt to delete " << handle
+ << " from list for " << my.desc << ", but it is not listed"
+ << endl;
+ }
+ return PM_ERR_NOCONTEXT;
+ }
+
+ sts = pmDestroyContext(my.handles[i]);
+ my.handles.removeAt(i);
+
+ // If this is a valid source, but no more contexts remain,
+ // then we should delete ourselves
+ if (my.handles.size() == 0 && my.status >= 0) {
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcSource::delContext: No contexts remain, removing "
+ << my.desc << endl;
+ }
+ delete this;
+ }
+
+ return sts;
+}
+
+QTextStream&
+operator<<(QTextStream &stream, const QmcSource &rhs)
+{
+ stream << rhs.my.desc;
+ return stream;
+}
+
+void
+QmcSource::dump(QTextStream &stream)
+{
+ stream << " sts = " << my.status << ", type = " << my.type
+ << ", source = " << my.source << endl
+ << " host = " << my.host << ", timezone = " << my.timezone
+ << ", tz hndl = " << my.tz << endl;
+ if (my.status >= 0)
+ stream << " start = " << timeString(&my.start) << ", end = "
+ << timeString(&my.end) << ", dupFlag = "
+ << (my.dupFlag == true ? "true" : "false") << endl << " "
+ << my.handles.size() << " contexts: ";
+ for (int i = 0; i < my.handles.size(); i++)
+ stream << my.handles[i] << ' ';
+ stream << endl;
+}
+
+void
+QmcSource::dumpList(QTextStream &stream)
+{
+ stream << sourceList.size() << " sources:" << endl;
+ for (int i = 0; i < sourceList.size(); i++) {
+ stream << '[' << i << "] " << *(sourceList[i]) << endl;
+ sourceList[i]->dump(stream);
+ }
+}