| 
					
				 | 
			
			
				@@ -57,14 +57,20 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "version.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "include/ZeroTierOne.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "ext/json-parser/json.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "node/Constants.hpp" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "node/Identity.hpp" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "node/CertificateOfMembership.hpp" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "node/Utils.hpp" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "node/NetworkController.hpp" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "osdep/OSUtils.hpp" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "osdep/Http.hpp" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "service/OneService.hpp" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #ifdef ZT_ENABLE_NETWORK_CONTROLLER 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "controller/SqliteNetworkController.hpp" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #endif 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -92,7 +98,7 @@ static void cliPrintHelp(const char *pn,FILE *out) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	fprintf(out,"  -D<path>           - ZeroTier home path for parameter auto-detect"ZT_EOL_S); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	fprintf(out,"  -p<port>           - HTTP port (default: auto)"ZT_EOL_S); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	fprintf(out,"  -T<token>          - Authentication token (default: auto)"ZT_EOL_S); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	fprintf(out,"  -H<ip>             - HTTP IP address (default: 127.0.0.1)"ZT_EOL_S""ZT_EOL_S); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	//fprintf(out,"  -H<ip>             - HTTP IP address (default: 127.0.0.1)"ZT_EOL_S""ZT_EOL_S); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	fprintf(out,"Available commands:"ZT_EOL_S); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	fprintf(out,"  info               - Display status info"ZT_EOL_S); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	fprintf(out,"  listpeers          - List all peers"ZT_EOL_S); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -254,6 +260,34 @@ static int cli(int argc,char **argv) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				printf("%s",cliFixJsonCRs(responseBody).c_str()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				json_value *j = json_parse(responseBody.c_str(),responseBody.length()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				bool good = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (j) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if (j->type == json_object) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						const char *address = (const char *)0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						bool online = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						const char *version = (const char *)0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						for(unsigned int k=0;k<j->u.object.length;++k) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							if ((!strcmp(j->u.object.values[k].name,"address"))&&(j->u.object.values[k].value->type == json_string)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								address = j->u.object.values[k].value->u.string.ptr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							else if ((!strcmp(j->u.object.values[k].name,"version"))&&(j->u.object.values[k].value->type == json_string)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								version = j->u.object.values[k].value->u.string.ptr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							else if ((!strcmp(j->u.object.values[k].name,"online"))&&(j->u.object.values[k].value->type == json_boolean)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								online = (j->u.object.values[k].value->u.boolean != 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						if ((address)&&(version)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							printf("200 info %s %s %s"ZT_EOL_S,address,(online ? "ONLINE" : "OFFLINE"),version); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							good = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					json_value_free(j); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (good) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					printf("%u %s invalid JSON response"ZT_EOL_S,scode,command.c_str()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			printf("%u %s %s"ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -273,6 +307,88 @@ static int cli(int argc,char **argv) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				printf("%s",cliFixJsonCRs(responseBody).c_str()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				printf("200 listpeers <ztaddr> <paths> <latency> <version> <role>"ZT_EOL_S); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				json_value *j = json_parse(responseBody.c_str(),responseBody.length()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (j) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if (j->type == json_array) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						for(unsigned int p=0;p<j->u.array.length;++p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							json_value *jp = j->u.array.values[p]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							if (jp->type == json_object) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								const char *address = (const char *)0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								std::string paths; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								int64_t latency = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								int64_t versionMajor = -1,versionMinor = -1,versionRev = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								const char *role = (const char *)0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								for(unsigned int k=0;k<jp->u.object.length;++k) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									if ((!strcmp(jp->u.object.values[k].name,"address"))&&(jp->u.object.values[k].value->type == json_string)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										address = jp->u.object.values[k].value->u.string.ptr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									else if ((!strcmp(jp->u.object.values[k].name,"versionMajor"))&&(jp->u.object.values[k].value->type == json_integer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										versionMajor = jp->u.object.values[k].value->u.integer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									else if ((!strcmp(jp->u.object.values[k].name,"versionMinor"))&&(jp->u.object.values[k].value->type == json_integer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										versionMinor = jp->u.object.values[k].value->u.integer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									else if ((!strcmp(jp->u.object.values[k].name,"versionRev"))&&(jp->u.object.values[k].value->type == json_integer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										versionRev = jp->u.object.values[k].value->u.integer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									else if ((!strcmp(jp->u.object.values[k].name,"role"))&&(jp->u.object.values[k].value->type == json_string)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										role = jp->u.object.values[k].value->u.string.ptr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									else if ((!strcmp(jp->u.object.values[k].name,"latency"))&&(jp->u.object.values[k].value->type == json_integer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										latency = jp->u.object.values[k].value->u.integer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									else if ((!strcmp(jp->u.object.values[k].name,"paths"))&&(jp->u.object.values[k].value->type == json_array)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										for(unsigned int pp=0;pp<jp->u.object.values[k].value->u.array.length;++pp) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+											json_value *jpath = jp->u.object.values[k].value->u.array.values[pp]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+											if (jpath->type == json_object) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+												const char *paddr = (const char *)0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+												int64_t lastSend = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+												int64_t lastReceive = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+												bool fixed = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+												bool active = false; // fixed/active/inactive 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+												for(unsigned int kk=0;kk<jpath->u.object.length;++kk) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													if ((!strcmp(jpath->u.object.values[kk].name,"address"))&&(jpath->u.object.values[kk].value->type == json_string)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														paddr = jpath->u.object.values[kk].value->u.string.ptr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													else if ((!strcmp(jpath->u.object.values[kk].name,"lastSend"))&&(jpath->u.object.values[kk].value->type == json_integer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														lastSend = jpath->u.object.values[kk].value->u.integer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													else if ((!strcmp(jpath->u.object.values[kk].name,"lastReceive"))&&(jpath->u.object.values[kk].value->type == json_integer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														lastReceive = jpath->u.object.values[kk].value->u.integer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													else if ((!strcmp(jpath->u.object.values[kk].name,"fixed"))&&(jpath->u.object.values[kk].value->type == json_boolean)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														fixed = (jpath->u.object.values[kk].value->u.boolean != 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													else if ((!strcmp(jpath->u.object.values[kk].name,"active"))&&(jpath->u.object.values[kk].value->type == json_boolean)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														active = (jpath->u.object.values[kk].value->u.boolean != 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+												} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+												if (paddr) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													int64_t now = (int64_t)OSUtils::now(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													if (lastSend > 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														lastSend = now - lastSend; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													if (lastReceive > 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														lastReceive = now - lastReceive; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													char pathtmp[256]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													Utils::snprintf(pathtmp,sizeof(pathtmp),"%s;%lld;%lld;%s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														paddr, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														lastSend, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														lastReceive, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														(fixed ? "fixed" : (active ? "active" : "inactive"))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													if (paths.length()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+														paths.push_back(','); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+													paths.append(pathtmp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+												} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+											} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								if ((address)&&(role)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									char verstr[64]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									if ((versionMajor >= 0)&&(versionMinor >= 0)&&(versionRev >= 0)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										Utils::snprintf(verstr,sizeof(verstr),"%lld.%lld.%lld",versionMajor,versionMinor,versionRev); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										verstr[0] = '-'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										verstr[1] = (char)0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									printf("200 listpeers %s %s %lld %s %s"ZT_EOL_S,address,(paths.length()) ? paths.c_str() : "-",latency,verstr,role); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					json_value_free(j); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			printf("%u %s %s"ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); 
			 |