Răsfoiți Sursa

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

Adam Ierymenko 11 ani în urmă
părinte
comite
f0223490be

+ 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