فهرست منبع

Make GUI work with new control client API, make control client look for user authtoken.secret if system unreadable.

Adam Ierymenko 11 سال پیش
والد
کامیت
f0223490be
9فایلهای تغییر یافته به همراه185 افزوده شده و 232 حذف شده
  1. 35 28
      ZeroTierUI/ZeroTierUI.pro
  2. 11 1
      ZeroTierUI/aboutwindow.cpp
  3. 78 82
      ZeroTierUI/mainwindow.cpp
  4. 1 1
      ZeroTierUI/mainwindow.h
  5. 0 3
      ZeroTierUI/networkwidget.cpp
  6. 33 94
      ZeroTierUI/networkwidget.ui
  7. 3 2
      main.cpp
  8. 23 20
      node/Node.cpp
  9. 1 1
      node/Node.hpp

+ 35 - 28
ZeroTierUI/ZeroTierUI.pro

@@ -12,16 +12,21 @@ mac:QMAKE_INFO_PLIST = Info.plist
 mac:LIBS += -framework Cocoa
 
 SOURCES += main.cpp \
-    mainwindow.cpp \
-    aboutwindow.cpp \
+		mainwindow.cpp \
+		aboutwindow.cpp \
+		networkwidget.cpp \
+		installdialog.cpp \
+		licensedialog.cpp \
+		onetimedialog.cpp \
     ../node/C25519.cpp \
     ../node/CertificateOfMembership.cpp \
     ../node/Defaults.cpp \
-    ../node/Demarc.cpp \
     ../node/EthernetTap.cpp \
     ../node/HttpClient.cpp \
     ../node/Identity.cpp \
     ../node/InetAddress.cpp \
+    ../node/IpcConnection.cpp \
+    ../node/IpcListener.cpp \
     ../node/Logger.cpp \
     ../node/Multicaster.cpp \
     ../node/Network.cpp \
@@ -35,24 +40,25 @@ SOURCES += main.cpp \
     ../node/Salsa20.cpp \
     ../node/Service.cpp \
     ../node/SHA512.cpp \
+    ../node/SocketManager.cpp \
     ../node/SoftwareUpdater.cpp \
     ../node/Switch.cpp \
     ../node/SysEnv.cpp \
+    ../node/TcpSocket.cpp \
     ../node/Topology.cpp \
     ../node/UdpSocket.cpp \
     ../node/Utils.cpp \
     ../ext/lz4/lz4.c \
-    ../ext/lz4/lz4hc.c \
-    networkwidget.cpp \
-    installdialog.cpp \
-    licensedialog.cpp \
-    onetimedialog.cpp
+    ../ext/lz4/lz4hc.c
 
 HEADERS  += mainwindow.h \
-    aboutwindow.h \
-    ../node/Node.hpp \
-    ../node/Utils.hpp \
-    ../node/Defaults.hpp \
+		aboutwindow.h \
+		networkwidget.h \
+		installdialog.h \
+		mac_doprivileged.h \
+		licensedialog.h \
+		main.h \
+		onetimedialog.h \
     ../node/Address.hpp \
     ../node/Array.hpp \
     ../node/AtomicCounter.hpp \
@@ -61,14 +67,15 @@ HEADERS  += mainwindow.h \
     ../node/C25519.hpp \
     ../node/CertificateOfMembership.hpp \
     ../node/CMWC4096.hpp \
-    ../node/Condition.hpp \
     ../node/Constants.hpp \
-    ../node/Demarc.hpp \
+    ../node/Defaults.hpp \
     ../node/Dictionary.hpp \
     ../node/EthernetTap.hpp \
     ../node/HttpClient.hpp \
     ../node/Identity.hpp \
     ../node/InetAddress.hpp \
+    ../node/IpcConnection.hpp \
+    ../node/IpcListener.hpp \
     ../node/Logger.hpp \
     ../node/MAC.hpp \
     ../node/Multicaster.hpp \
@@ -76,10 +83,12 @@ HEADERS  += mainwindow.h \
     ../node/Mutex.hpp \
     ../node/Network.hpp \
     ../node/NetworkConfig.hpp \
+    ../node/Node.hpp \
     ../node/NodeConfig.hpp \
     ../node/NonCopyable.hpp \
     ../node/Packet.hpp \
     ../node/PacketDecoder.hpp \
+    ../node/Path.hpp \
     ../node/Peer.hpp \
     ../node/Poly1305.hpp \
     ../node/RuntimeEnvironment.hpp \
@@ -87,28 +96,26 @@ HEADERS  += mainwindow.h \
     ../node/Service.hpp \
     ../node/SHA512.hpp \
     ../node/SharedPtr.hpp \
+    ../node/Socket.hpp \
+    ../node/SocketManager.hpp \
     ../node/SoftwareUpdater.hpp \
     ../node/Switch.hpp \
     ../node/SysEnv.hpp \
+    ../node/TcpSocket.hpp \
     ../node/Thread.hpp \
     ../node/Topology.hpp \
     ../node/UdpSocket.hpp \
+    ../node/Utils.hpp \
     ../ext/lz4/lz4.h \
-    ../ext/lz4/lz4hc.h \
-    networkwidget.h \
-    installdialog.h \
-    mac_doprivileged.h \
-    licensedialog.h \
-    main.h \
-    onetimedialog.h
+    ../ext/lz4/lz4hc.h
 
 FORMS    += mainwindow.ui \
-    aboutwindow.ui \
-    networkwidget.ui \
-    installdialog.ui \
-    licensedialog.ui \
-    quickstartdialog.ui \
-    onetimedialog.ui
+		aboutwindow.ui \
+		networkwidget.ui \
+		installdialog.ui \
+		licensedialog.ui \
+		quickstartdialog.ui \
+		onetimedialog.ui
 
 RESOURCES += \
 		resources.qrc
@@ -117,4 +124,4 @@ mac:OBJECTIVE_SOURCES += \
 		mac_doprivileged.mm
 
 OTHER_FILES += \
-    stylesheet.css
+		stylesheet.css

+ 11 - 1
ZeroTierUI/aboutwindow.cpp

@@ -39,7 +39,17 @@ AboutWindow::AboutWindow(QWidget *parent) :
 	ui(new Ui::AboutWindow)
 {
 	ui->setupUi(this);
-	ui->aboutTextLabel->setText(QString("ZeroTier One\nVersion ")+ZeroTier::Node::versionString()+"\nQt Graphical User Interface\n\n(c)2011-2014 ZeroTier Networks LLC\n\nReleased under the terms of the GNU\nGeneral Public License v3.0, see: http://gplv3.fsf.org for terms.\n\nAuthor(s): Adam Ierymenko");
+	ui->aboutTextLabel->setText(QString("ZeroTier One\nVersion ")+ZeroTier::Node::versionString()+"\nDesktop Graphical User Interface\n\n(c)2011-2014 ZeroTier Networks LLC\n\nReleased under the terms of the GNU\nGeneral Public License v3.0, see: http://gplv3.fsf.org for terms.\n\nAuthor(s): Adam Ierymenko");
+
+#ifdef __WINDOWS__
+	QWidgetList widgets = this->findChildren<QWidget*>();
+	foreach(QWidget *widget, widgets) {
+		QFont font(widget->font());
+		font.setPointSizeF(font.pointSizeF() * 0.75);
+		widget->setFont(font);
+	}
+	this->raise();
+#endif
 }
 
 AboutWindow::~AboutWindow()

+ 78 - 82
ZeroTierUI/mainwindow.cpp

@@ -63,32 +63,32 @@
 #endif
 
 // Globally visible
-ZeroTier::Node::LocalClient *zeroTierClient = (ZeroTier::Node::LocalClient *)0;
+ZeroTier::Node::NodeControlClient *zeroTierClient = (ZeroTier::Node::NodeControlClient *)0;
 
 // Main window instance for app
 QMainWindow *mainWindow = (MainWindow *)0;
 
 // Handles message from ZeroTier One service
-static void handleZTMessage(void *arg,unsigned long id,const char *line)
+static void handleZTMessage(void *arg,const char *line)
 {
-	static std::map< unsigned long,std::vector<std::string> > ztReplies;
+	static std::vector<std::string> ztReplies;
 	static QMutex ztReplies_m;
 
 	ztReplies_m.lock();
-	if (*line) {
-		ztReplies[id].push_back(std::string(line));
-		ztReplies_m.unlock();
-	} else { // empty lines conclude transmissions
-		std::map< unsigned long,std::vector<std::string> >::iterator r(ztReplies.find(id));
-		if (r != ztReplies.end()) {
+
+	if (line) {
+		if ((line[0] == '.')&&(line[1] == (char)0)) {
 			// The message is packed into an event and sent to the main window where
 			// the actual parsing code lives.
-			MainWindow::ZTMessageEvent *event = new MainWindow::ZTMessageEvent(r->second);
-			ztReplies.erase(r);
-			ztReplies_m.unlock();
+			MainWindow::ZTMessageEvent *event = new MainWindow::ZTMessageEvent(ztReplies);
+			ztReplies.clear();
 			QCoreApplication::postEvent(mainWindow,event); // must post since this may be another thread
-		} else ztReplies_m.unlock();
+		} else if (line[0]) {
+			ztReplies.push_back(std::string(line));
+		}
 	}
+
+	ztReplies_m.unlock();
 }
 
 MainWindow::MainWindow(QWidget *parent) :
@@ -136,7 +136,7 @@ MainWindow::~MainWindow()
 {
 	delete ui;
 	delete zeroTierClient;
-	zeroTierClient = (ZeroTier::Node::LocalClient *)0;
+	zeroTierClient = (ZeroTier::Node::NodeControlClient *)0;
 	mainWindow = (MainWindow *)0;
 }
 
@@ -147,75 +147,72 @@ void MainWindow::timerEvent(QTimerEvent *event) // event can be null since code
 	if (this->pollServiceTimerId < 0)
 		return;
 
+	// Show quick start dialog on first launch, then reset timer to normal rate
 	if (this->firstTimerTick) {
 		this->firstTimerTick = false;
 		this->killTimer(this->pollServiceTimerId);
-
 		if (!settings->value("shown_quickStart",false).toBool()) {
 			on_actionQuick_Start_triggered();
 			settings->setValue("shown_quickStart",true);
 			settings->sync();
 		}
-
-		this->pollServiceTimerId = this->startTimer(1500);
+		this->pollServiceTimerId = this->startTimer(2000);
 	}
 
 	if (!zeroTierClient) {
-		std::string authToken;
-		if (!ZeroTier::Utils::readFile(ZeroTier::Node::LocalClient::authTokenDefaultUserPath().c_str(),authToken)) {
 #ifdef __APPLE__
-			if (QFile::exists("/Library/Application Support/ZeroTier/One/zerotier-one")) {
-				// Authorize user by copying auth token into local home directory
-				QMessageBox::information(this,"Authorization Needed","Administrator privileges are required to allow the current user to control ZeroTier One on this computer. (You only have to do this once.)",QMessageBox::Ok,QMessageBox::NoButton);
-
-				std::string homePath(QDir::homePath().toStdString());
-				QString zt1Caches(QDir::homePath() + "/Library/Caches/ZeroTier/One");
-				QDir::root().mkpath(zt1Caches);
-				std::string tmpPath((zt1Caches + "/auth.sh").toStdString());
-
-				FILE *scr = fopen(tmpPath.c_str(),"w");
-				if (!scr) {
-					QMessageBox::critical(this,"Cannot Authorize","Unable to authorize this user to administrate ZeroTier One. (Cannot write to temporary Library/Caches/ZeroTier/One folder.)",QMessageBox::Ok,QMessageBox::NoButton);
-					QApplication::exit(1);
-					return;
-				}
-
-				fprintf(scr,"#!/bin/bash\n");
-				fprintf(scr,"export PATH=\"/bin:/usr/bin:/sbin:/usr/sbin\"\n");
-				fprintf(scr,"if [ -f '/Library/Application Support/ZeroTier/One/authtoken.secret' ]; then\n");
-				fprintf(scr,"  mkdir -p '%s/Library/Application Support/ZeroTier/One'\n",homePath.c_str());
-				fprintf(scr,"  chown %d '%s/Library/Application Support/ZeroTier'\n",(int)getuid(),homePath.c_str());
-				fprintf(scr,"  chgrp %d '%s/Library/Application Support/ZeroTier'\n",(int)getgid(),homePath.c_str());
-				fprintf(scr,"  chmod 0700 '%s/Library/Application Support/ZeroTier'\n",homePath.c_str());
-				fprintf(scr,"  chown %d '%s/Library/Application Support/ZeroTier/One'\n",(int)getuid(),homePath.c_str());
-				fprintf(scr,"  chgrp %d '%s/Library/Application Support/ZeroTier/One'\n",(int)getgid(),homePath.c_str());
-				fprintf(scr,"  chmod 0700 '%s/Library/Application Support/ZeroTier/One'\n",homePath.c_str());
-				fprintf(scr,"  cp -f '/Library/Application Support/ZeroTier/One/authtoken.secret' '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",homePath.c_str());
-				fprintf(scr,"  chown %d '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",(int)getuid(),homePath.c_str());
-				fprintf(scr,"  chgrp %d '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",(int)getgid(),homePath.c_str());
-				fprintf(scr,"  chmod 0600 '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",homePath.c_str());
-				fprintf(scr,"fi\n");
-				fprintf(scr,"exit 0\n");
-
-				fclose(scr);
-				chmod(tmpPath.c_str(),0755);
-
-				macExecutePrivilegedShellCommand((std::string("'")+tmpPath+"' >>/dev/null 2>&1").c_str());
-
-				unlink(tmpPath.c_str());
+		if ((!QFile::exists(ZeroTier::Node::NodeControlClient::authTokenDefaultUserPath()))&&(QFile::exists("/Library/Application Support/ZeroTier/One/zerotier-one"))) {
+			// Authorize user by copying auth token into local home directory
+			QMessageBox::information(this,"Authorization Needed","Administrator privileges are required to allow the current user to control ZeroTier One on this computer. (You only have to do this once.)",QMessageBox::Ok,QMessageBox::NoButton);
+
+			std::string homePath(QDir::homePath().toStdString());
+			QString zt1Caches(QDir::homePath() + "/Library/Caches/ZeroTier/One");
+			QDir::root().mkpath(zt1Caches);
+			std::string tmpPath((zt1Caches + "/auth.sh").toStdString());
+
+			FILE *scr = fopen(tmpPath.c_str(),"w");
+			if (!scr) {
+				QMessageBox::critical(this,"Cannot Authorize","Unable to authorize this user to administrate ZeroTier One. (Cannot write to temporary Library/Caches/ZeroTier/One folder.)",QMessageBox::Ok,QMessageBox::NoButton);
+				QApplication::exit(1);
+				return;
 			}
-#endif
 
-			if (!ZeroTier::Utils::readFile(ZeroTier::Node::LocalClient::authTokenDefaultUserPath().c_str(),authToken)) {
-				if (!ZeroTier::Utils::readFile(ZeroTier::Node::LocalClient::authTokenDefaultSystemPath().c_str(),authToken)) {
-					QMessageBox::critical(this,"Cannot Authorize","Unable to authorize this user to administrate ZeroTier One. (Did you enter your password correctly?)",QMessageBox::Ok,QMessageBox::NoButton);
-					QApplication::exit(1);
-					return;
-				}
+			fprintf(scr,"#!/bin/bash\n");
+			fprintf(scr,"export PATH=\"/bin:/usr/bin:/sbin:/usr/sbin\"\n");
+			fprintf(scr,"if [ -f '/Library/Application Support/ZeroTier/One/authtoken.secret' ]; then\n");
+			fprintf(scr,"  mkdir -p '%s/Library/Application Support/ZeroTier/One'\n",homePath.c_str());
+			fprintf(scr,"  chown %d '%s/Library/Application Support/ZeroTier'\n",(int)getuid(),homePath.c_str());
+			fprintf(scr,"  chgrp %d '%s/Library/Application Support/ZeroTier'\n",(int)getgid(),homePath.c_str());
+			fprintf(scr,"  chmod 0700 '%s/Library/Application Support/ZeroTier'\n",homePath.c_str());
+			fprintf(scr,"  chown %d '%s/Library/Application Support/ZeroTier/One'\n",(int)getuid(),homePath.c_str());
+			fprintf(scr,"  chgrp %d '%s/Library/Application Support/ZeroTier/One'\n",(int)getgid(),homePath.c_str());
+			fprintf(scr,"  chmod 0700 '%s/Library/Application Support/ZeroTier/One'\n",homePath.c_str());
+			fprintf(scr,"  cp -f '/Library/Application Support/ZeroTier/One/authtoken.secret' '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",homePath.c_str());
+			fprintf(scr,"  chown %d '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",(int)getuid(),homePath.c_str());
+			fprintf(scr,"  chgrp %d '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",(int)getgid(),homePath.c_str());
+			fprintf(scr,"  chmod 0600 '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",homePath.c_str());
+			fprintf(scr,"fi\n");
+			fprintf(scr,"exit 0\n");
+
+			fclose(scr);
+			chmod(tmpPath.c_str(),0755);
+
+			macExecutePrivilegedShellCommand((std::string("'")+tmpPath+"' >>/dev/null 2>&1").c_str());
+
+			unlink(tmpPath.c_str());
+		}
+#endif // __APPLE__
+
+		try {
+			zeroTierClient = new ZeroTier::Node::NodeControlClient((const char *)0,&handleZTMessage,this);
+			const char *err = zeroTierClient->error();
+			if (err) {
+				delete zeroTierClient;
+				zeroTierClient = (ZeroTier::Node::NodeControlClient *)0;
 			}
+		} catch ( ... ) {
+			zeroTierClient = (ZeroTier::Node::NodeControlClient *)0;
 		}
-
-		zeroTierClient = new ZeroTier::Node::LocalClient(authToken.c_str(),0,&handleZTMessage,this);
 	}
 
 	if (++this->cyclesSinceResponseFromService >= 3) {
@@ -227,9 +224,11 @@ void MainWindow::timerEvent(QTimerEvent *event) // event can be null since code
 		ui->networkListWidget->setVisible(false);
 	}
 
-	zeroTierClient->send("info");
-	zeroTierClient->send("listnetworks");
-	zeroTierClient->send("listpeers");
+	if (zeroTierClient) {
+		zeroTierClient->send("info");
+		zeroTierClient->send("listnetworks");
+		zeroTierClient->send("listpeers");
+	}
 }
 
 void MainWindow::customEvent(QEvent *event)
@@ -237,15 +236,14 @@ void MainWindow::customEvent(QEvent *event)
 	ZTMessageEvent *m = (ZTMessageEvent *)event; // only one custom event type so far
 	if (m->ztMessage.size() == 0)
 		return;
-
-	this->cyclesSinceResponseFromService = 0;
-
-	std::vector<std::string> hdr(ZeroTier::Node::LocalClient::splitLine(m->ztMessage[0]));
+	std::vector<std::string> hdr(ZeroTier::Node::NodeControlClient::splitLine(m->ztMessage[0]));
 	if (hdr.size() < 2)
 		return;
 	if (hdr[0] != "200")
 		return;
 
+	this->cyclesSinceResponseFromService = 0;
+
 	if (hdr[1] == "info") {
 		if (hdr.size() >= 3)
 			this->myAddress = hdr[2].c_str();
@@ -256,7 +254,7 @@ void MainWindow::customEvent(QEvent *event)
 	} else if (hdr[1] == "listnetworks") {
 		std::map< std::string,std::vector<std::string> > newNetworks;
 		for(unsigned long i=1;i<m->ztMessage.size();++i) {
-			std::vector<std::string> l(ZeroTier::Node::LocalClient::splitLine(m->ztMessage[i]));
+			std::vector<std::string> l(ZeroTier::Node::NodeControlClient::splitLine(m->ztMessage[i]));
 			// 200 listnetworks <nwid> <name> <status> <config age> <type> <dev> <ips>
 			if ((l.size() == 9)&&(l[2].length() == 16))
 				newNetworks[l[2]] = l;
@@ -309,12 +307,10 @@ void MainWindow::customEvent(QEvent *event)
 		}
 	} else if (hdr[1] == "listpeers") {
 		this->numPeers = 0;
-		for(unsigned long i=1;i<m->ztMessage.size();++i) {
-			std::vector<std::string> l(ZeroTier::Node::LocalClient::splitLine(m->ztMessage[i]));
-			if ((l.size() >= 5)&&((l[3] != "-")||(l[4] != "-")))
-				++this->numPeers; // number of direct peers online -- check for active IPv4 and/or IPv6 address
-		}
-	}
+		for(unsigned long i=1;i<m->ztMessage.size();++i)
+			++this->numPeers;
+	} else
+		return;
 
 	if (!ui->networkListWidget->count()) {
 		ui->noNetworksLabel->setText("You Have Not Joined Any Networks");
@@ -335,7 +331,7 @@ void MainWindow::customEvent(QEvent *event)
 	st += this->myVersion;
 	st += ", ";
 	st += QString::number(this->numPeers);
-	st += " direct links to peers";
+	st += " peers";
 	ui->statusLabel->setText(st);
 }
 

+ 1 - 1
ZeroTierUI/mainwindow.h

@@ -49,7 +49,7 @@ class MainWindow;
 
 // Globally visible instance of local client for communicating with ZT1
 // Can be null if not connected, or will point to current
-extern ZeroTier::Node::LocalClient *zeroTierClient;
+extern ZeroTier::Node::NodeControlClient *zeroTierClient;
 
 // Globally visible pointer to main app window
 extern QMainWindow *mainWindow;

+ 0 - 3
ZeroTierUI/networkwidget.cpp

@@ -80,9 +80,6 @@ NetworkWidget::~NetworkWidget()
 void NetworkWidget::setStatus(const std::string &status,const std::string &age)
 {
 	ui->statusLabel->setText(QString(status.c_str()));
-	if (status == "OK")
-		ui->ageLabel->setText(QString("[") + age.c_str() + "s ago]");
-	else ui->ageLabel->setText(QString());
 }
 
 void NetworkWidget::setNetworkName(const std::string &name)

+ 33 - 94
ZeroTierUI/networkwidget.ui

@@ -178,12 +178,6 @@
       </item>
       <item>
        <widget class="QWidget" name="networkStatsWidget" native="true">
-        <property name="sizePolicy">
-         <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-          <horstretch>0</horstretch>
-          <verstretch>0</verstretch>
-         </sizepolicy>
-        </property>
         <layout class="QFormLayout" name="formLayout">
          <property name="fieldGrowthPolicy">
           <enum>QFormLayout::ExpandingFieldsGrow</enum>
@@ -232,6 +226,12 @@
          </item>
          <item row="2" column="1">
           <widget class="QLabel" name="networkTypeLabel">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
            <property name="font">
             <font>
              <pointsize>12</pointsize>
@@ -280,101 +280,40 @@
            </property>
           </widget>
          </item>
-         <item row="3" column="1">
-          <widget class="QWidget" name="widget" native="true">
+         <item row="4" column="1">
+          <widget class="QLabel" name="deviceLabel">
            <property name="sizePolicy">
             <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
              <horstretch>0</horstretch>
              <verstretch>0</verstretch>
             </sizepolicy>
            </property>
-           <layout class="QHBoxLayout" name="horizontalLayout_3">
-            <property name="spacing">
-             <number>12</number>
-            </property>
-            <property name="leftMargin">
-             <number>0</number>
-            </property>
-            <property name="topMargin">
-             <number>0</number>
-            </property>
-            <property name="rightMargin">
-             <number>0</number>
-            </property>
-            <property name="bottomMargin">
-             <number>0</number>
-            </property>
-            <item>
-             <widget class="QLabel" name="statusLabel">
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="font">
-               <font>
-                <pointsize>12</pointsize>
-                <weight>75</weight>
-                <bold>true</bold>
-               </font>
-              </property>
-              <property name="statusTip">
-               <string>Status of this network.</string>
-              </property>
-              <property name="text">
-               <string>?</string>
-              </property>
-              <property name="textFormat">
-               <enum>Qt::PlainText</enum>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QLabel" name="ageLabel">
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="font">
-               <font>
-                <pointsize>10</pointsize>
-               </font>
-              </property>
-              <property name="statusTip">
-               <string>How recently did this network refresh its settings?</string>
-              </property>
-              <property name="text">
-               <string>[0s ago]</string>
-              </property>
-              <property name="textFormat">
-               <enum>Qt::PlainText</enum>
-              </property>
-              <property name="textInteractionFlags">
-               <set>Qt::NoTextInteraction</set>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <spacer name="horizontalSpacer_2">
-              <property name="orientation">
-               <enum>Qt::Horizontal</enum>
-              </property>
-              <property name="sizeHint" stdset="0">
-               <size>
-                <width>40</width>
-                <height>1</height>
-               </size>
-              </property>
-             </spacer>
-            </item>
-           </layout>
+           <property name="font">
+            <font>
+             <pointsize>12</pointsize>
+             <weight>75</weight>
+             <bold>true</bold>
+            </font>
+           </property>
+           <property name="statusTip">
+            <string>The name of the network device on your system.</string>
+           </property>
+           <property name="text">
+            <string>?</string>
+           </property>
+           <property name="textFormat">
+            <enum>Qt::PlainText</enum>
+           </property>
           </widget>
          </item>
-         <item row="4" column="1">
-          <widget class="QLabel" name="deviceLabel">
+         <item row="3" column="1">
+          <widget class="QLabel" name="statusLabel">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
            <property name="font">
             <font>
              <pointsize>12</pointsize>
@@ -383,7 +322,7 @@
             </font>
            </property>
            <property name="statusTip">
-            <string>The name of the network device on your system.</string>
+            <string>Status of this network.</string>
            </property>
            <property name="text">
             <string>?</string>

+ 3 - 2
main.cpp

@@ -161,8 +161,9 @@ static int main(int argc,char **argv)
 	try {
 		volatile bool done = false;
 		Node::NodeControlClient client(hp,&_CBresultHandler,(void *)&done);
-		if (client.error()) {
-			fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?)"ZT_EOL_S,argv[0]);
+		const char *err = client.error();
+		if (err) {
+			fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (%s)"ZT_EOL_S,argv[0],err);
 			return 1;
 		}
 		client.send(query.c_str());

+ 23 - 20
node/Node.cpp

@@ -109,27 +109,30 @@ Node::NodeControlClient::NodeControlClient(const char *hp,void (*resultHandler)(
 	std::string at;
 	if (authToken)
 		at = authToken;
-	else if (!Utils::readFile((std::string(hp) + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),at))
-		impl->err = "no authentication token specified and authtoken.secret not readable";
-	else {
-		std::string myid;
-		if (Utils::readFile((std::string(hp) + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),myid)) {
-			std::string myaddr(myid.substr(0,myid.find(':')));
-			if (myaddr.length() != 10)
-				impl->err = "invalid address extracted from identity.public";
-			else {
-				try {
-					impl->resultHandler = resultHandler;
-					impl->arg = arg;
-					impl->ipcc = new IpcConnection((std::string(ZT_IPC_ENDPOINT_BASE) + myaddr).c_str(),&_CBipcResultHandler,_impl);
-					impl->ipcc->printf("auth %s"ZT_EOL_S,at.c_str());
-				} catch ( ... ) {
-					impl->ipcc = (IpcConnection *)0;
-					impl->err = "failure connecting to running ZeroTier One service";
-				}
-			}
-		} else impl->err = "unable to read identity.public";
+	else if (!Utils::readFile(authTokenDefaultSystemPath(),at)) {
+		if (!Utils::readFile(authTokenDefaultUserPath(),at)) {
+			impl->err = "no authentication token specified and authtoken.secret not readable";
+			return;
+		}
 	}
+
+	std::string myid;
+	if (Utils::readFile((std::string(hp) + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),myid)) {
+		std::string myaddr(myid.substr(0,myid.find(':')));
+		if (myaddr.length() != 10)
+			impl->err = "invalid address extracted from identity.public";
+		else {
+			try {
+				impl->resultHandler = resultHandler;
+				impl->arg = arg;
+				impl->ipcc = new IpcConnection((std::string(ZT_IPC_ENDPOINT_BASE) + myaddr).c_str(),&_CBipcResultHandler,_impl);
+				impl->ipcc->printf("auth %s"ZT_EOL_S,at.c_str());
+			} catch ( ... ) {
+				impl->ipcc = (IpcConnection *)0;
+				impl->err = "failure connecting to running ZeroTier One service";
+			}
+		}
+	} else impl->err = "unable to read identity.public";
 }
 
 Node::NodeControlClient::~NodeControlClient()

+ 1 - 1
node/Node.hpp

@@ -58,7 +58,7 @@ public:
 		 *
 		 * Initialization may fail. Call error() to check.
 		 *
-		 * @param hp Home path of ZeroTier One instance
+		 * @param hp Home path of ZeroTier One instance or NULL for default system home path
 		 * @param resultHandler Function to call when commands provide results
 		 * @param arg First argument to result handler
 		 * @param authToken Authentication token or NULL (default) to read from authtoken.secret in home path