1 /*
2  * Copyright (c)2019 ZeroTier, Inc.
3  *
4  * Use of this software is governed by the Business Source License included
5  * in the LICENSE.TXT file in the project's root directory.
6  *
7  * Change Date: 2025-01-01
8  *
9  * On the date above, in accordance with the Business Source License, use
10  * of this software will be governed by version 2.0 of the Apache License.
11  */
12 /****/
13 
14 #pragma region Includes
15 
16 #if defined(_WIN32) || defined(_WIN64)
17 
18 #include <WinSock2.h>
19 #include <Windows.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 
23 #include "ZeroTierOneService.h"
24 
25 #include "../../version.h"
26 #include "../../include/ZeroTierOne.h"
27 
28 #include "../../node/Constants.hpp"
29 #include "../../node/Utils.hpp"
30 #include "../../osdep/OSUtils.hpp"
31 #include "../../service/OneService.hpp"
32 
33 #pragma endregion // Includes
34 
35 #ifdef ZT_DEBUG_SERVICE
36 FILE *SVCDBGfile = (FILE *)0;
37 ZeroTier::Mutex SVCDBGfile_m;
38 #endif
39 
ZeroTierOneService()40 ZeroTierOneService::ZeroTierOneService() :
41 	CServiceBase(ZT_SERVICE_NAME,TRUE,TRUE,FALSE),
42 	_service((ZeroTier::OneService *)0)
43 {
44 #ifdef ZT_DEBUG_SERVICE
45 	SVCDBGfile_m.lock();
46 	if (!SVCDBGfile)
47 		SVCDBGfile = fopen(ZT_DEBUG_SERVICE,"a");
48 	SVCDBGfile_m.unlock();
49 #endif
50 
51 	ZT_SVCDBG("ZeroTierOneService::ZeroTierOneService()\r\n");
52 }
53 
~ZeroTierOneService(void)54 ZeroTierOneService::~ZeroTierOneService(void)
55 {
56 	ZT_SVCDBG("ZeroTierOneService::~ZeroTierOneService()\r\n");
57 
58 #ifdef ZT_DEBUG_SERVICE
59 	SVCDBGfile_m.lock();
60 	if (SVCDBGfile) {
61 		fclose(SVCDBGfile);
62 		SVCDBGfile = (FILE *)0;
63 	}
64 	SVCDBGfile_m.unlock();
65 #endif
66 }
67 
threadMain()68 void ZeroTierOneService::threadMain()
69 	throw()
70 {
71 	ZT_SVCDBG("ZeroTierOneService::threadMain()\r\n");
72 
73 restart_node:
74 	try {
75 		{
76 			ZeroTier::Mutex::Lock _l(_lock);
77 			delete _service;
78 			_service = (ZeroTier::OneService *)0; // in case newInstance() fails
79 			_service = ZeroTier::OneService::newInstance(_path.c_str(), ZT_DEFAULT_PORT);
80 		}
81 		switch(_service->run()) {
82 			case ZeroTier::OneService::ONE_UNRECOVERABLE_ERROR: {
83 				std::string err("ZeroTier One encountered an unrecoverable error: ");
84 				err.append(_service->fatalErrorMessage());
85 				err.append(" (restarting in 5 seconds)");
86 				WriteEventLogEntry(const_cast <PSTR>(err.c_str()),EVENTLOG_ERROR_TYPE);
87 				Sleep(5000);
88 			}	goto restart_node;
89 
90 			case ZeroTier::OneService::ONE_IDENTITY_COLLISION: {
91 				std::string homeDir(ZeroTier::OneService::platformDefaultHomePath());
92 				delete _service;
93 				_service = (ZeroTier::OneService *)0;
94 				std::string oldid;
95 				ZeroTier::OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid);
96 				if (oldid.length()) {
97 					ZeroTier::OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid);
98 					ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str());
99 					ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str());
100 				}
101 			}	goto restart_node;
102 
103 			default: // normal termination
104 				break;
105 		}
106 	} catch ( ... ) {
107 		// sanity check, shouldn't happen since Node::run() should catch all its own errors
108 		// could also happen if we're out of memory though!
109 		WriteEventLogEntry("unexpected exception (out of memory?) (trying again in 5 seconds)",EVENTLOG_ERROR_TYPE);
110 		Sleep(5000);
111 		goto restart_node;
112 	}
113 
114 	{
115 		ZeroTier::Mutex::Lock _l(_lock);
116 		delete _service;
117 		_service = (ZeroTier::OneService *)0;
118 	}
119 }
120 
OnStart(DWORD dwArgc,PSTR * lpszArgv)121 void ZeroTierOneService::OnStart(DWORD dwArgc, PSTR *lpszArgv)
122 {
123 	ZT_SVCDBG("ZeroTierOneService::OnStart()\r\n");
124 
125 	if ((dwArgc > 1)&&(lpszArgv[1])&&(strlen(lpszArgv[1]) > 0)) {
126 		this->_path = lpszArgv[1];
127 	} else {
128 		this->_path = ZeroTier::OneService::platformDefaultHomePath();
129 	}
130 
131 	try {
132 		_thread = ZeroTier::Thread::start(this);
133 	} catch ( ... ) {
134 		throw (DWORD)ERROR_EXCEPTION_IN_SERVICE;
135 	}
136 }
137 
OnStop()138 void ZeroTierOneService::OnStop()
139 {
140 	ZT_SVCDBG("ZeroTierOneService::OnStop()\r\n");
141 
142 	_lock.lock();
143 	ZeroTier::OneService *s = _service;
144 	_lock.unlock();
145 
146 	if (s) {
147 		s->terminate();
148 		ZeroTier::Thread::join(_thread);
149 	}
150 }
151 
OnShutdown()152 void ZeroTierOneService::OnShutdown()
153 {
154 	ZT_SVCDBG("ZeroTierOneService::OnShutdown()\r\n");
155 
156 	// stop thread on system shutdown (if it hasn't happened already)
157 	OnStop();
158 }
159 
160 #endif
161