RPC.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*
  2. * ZeroTier One - Global Peer to Peer Ethernet
  3. * Copyright (C) 2012-2013 ZeroTier Networks LLC
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * ZeroTier may be used and distributed under the terms of the GPLv3, which
  21. * are available at: http://www.gnu.org/licenses/gpl-3.0.html
  22. *
  23. * If you would like to embed ZeroTier into a commercial application or
  24. * redistribute it in a modified binary form, please contact ZeroTier Networks
  25. * LLC. Start here: http://www.zerotier.com/
  26. */
  27. #ifndef __WINDOWS__
  28. #include <dlfcn.h>
  29. #endif
  30. #include "Utils.hpp"
  31. #include "RuntimeEnvironment.hpp"
  32. #include "RPC.hpp"
  33. #include "Switch.hpp"
  34. #include "Topology.hpp"
  35. namespace ZeroTier {
  36. #ifndef __WINDOWS__
  37. RPC::LocalService::LocalService(const char *dllPath)
  38. throw(std::invalid_argument) :
  39. _handle((void *)0),
  40. _init((void *)0),
  41. _do((void *)0),
  42. _free((void *)0),
  43. _destroy((void *)0)
  44. {
  45. _handle = dlopen(dllPath,RTLD_LAZY|RTLD_LOCAL);
  46. if (!_handle)
  47. throw std::invalid_argument("Unable to load DLL: dlopen() failed");
  48. _init = dlsym(_handle,"ZeroTierPluginInit");
  49. if (!_init) {
  50. dlclose(_handle);
  51. throw std::invalid_argument("Unable to resolve symbol ZeroTierPluginInit in DLL");
  52. }
  53. _do = dlsym(_handle,"ZeroTierPluginDo");
  54. if (!_do) {
  55. dlclose(_handle);
  56. throw std::invalid_argument("Unable to resolve symbol ZeroTierPluginDo in DLL");
  57. }
  58. _free = dlsym(_handle,"ZeroTierPluginFree");
  59. if (!_free) {
  60. dlclose(_handle);
  61. throw std::invalid_argument("Unable to resolve symbol ZeroTierPluginFree in DLL");
  62. }
  63. _destroy = dlsym(_handle,"ZeroTierPluginDestroy");
  64. if (!_destroy) {
  65. dlclose(_handle);
  66. throw std::invalid_argument("Unable to resolve symbol ZeroTierPluginDestroy in DLL");
  67. }
  68. if (((int (*)())_init)() < 0) {
  69. dlclose(_handle);
  70. throw std::invalid_argument("ZeroTierPluginInit() returned error");
  71. }
  72. }
  73. RPC::LocalService::~LocalService()
  74. {
  75. if (_handle) {
  76. if (_destroy)
  77. ((void (*)())_destroy)();
  78. dlclose(_handle);
  79. }
  80. }
  81. std::pair< int,std::vector<std::string> > RPC::LocalService::operator()(const std::vector<std::string> &args)
  82. {
  83. unsigned int alengths[4096];
  84. const void *argptrs[4096];
  85. const unsigned int *rlengths = (const unsigned int *)0;
  86. const void **resultptrs = (const void **)0;
  87. std::vector<std::string> results;
  88. if (args.size() > 4096)
  89. throw std::runtime_error("args[] too long");
  90. for(unsigned int i=0;i<args.size();++i) {
  91. alengths[i] = args[i].length();
  92. argptrs[i] = (const void *)args[i].data();
  93. }
  94. int rcount = ((int (*)(unsigned int,const unsigned int *,const void **,const unsigned int **,const void ***))_do)((unsigned int)args.size(),alengths,argptrs,&rlengths,&resultptrs);
  95. for(int i=0;i<rcount;++i)
  96. results.push_back(std::string((const char *)resultptrs[i],rlengths[i]));
  97. ((void (*)(int,const unsigned int *,const void **))_free)(rcount,rlengths,resultptrs);
  98. return std::pair< int,std::vector<std::string> >(rcount,results);
  99. }
  100. #endif // __WINDOWS__
  101. RPC::RPC(const RuntimeEnvironment *renv) :
  102. _r(renv)
  103. {
  104. }
  105. RPC::~RPC()
  106. {
  107. for(std::map<uint64_t,RemoteCallOutstanding>::iterator co(_remoteCallsOutstanding.begin());co!=_remoteCallsOutstanding.end();++co) {
  108. if (co->second.handler)
  109. co->second.handler(co->second.arg,co->first,co->second.peer,ZT_RPC_ERROR_CANCELLED,std::vector<std::string>());
  110. }
  111. #ifndef __WINDOWS__
  112. for(std::map<std::string,LocalService *>::iterator s(_rpcServices.begin());s!=_rpcServices.end();++s)
  113. delete s->second;
  114. #endif
  115. }
  116. std::pair< int,std::vector<std::string> > RPC::callLocal(const std::string &name,const std::vector<std::string> &args)
  117. {
  118. #ifdef __WINDOWS__
  119. return std::pair< int,std::vector<std::string> >(ZT_RPC_ERROR_NOT_FOUND,std::vector<std::string>());
  120. #else
  121. Mutex::Lock _l(_rpcServices_m);
  122. std::map<std::string,LocalService *>::iterator s(_rpcServices.find(name));
  123. if (s == _rpcServices.end())
  124. return std::pair< int,std::vector<std::string> >(ZT_RPC_ERROR_NOT_FOUND,std::vector<std::string>());
  125. return ((*(s->second))(args));
  126. #endif
  127. }
  128. void RPC::loadLocal(const char *name,const char *path)
  129. throw(std::invalid_argument)
  130. {
  131. #ifdef __WINDOWS__
  132. throw std::invalid_argument("RPC plugins not supported on Windows (yet?)");
  133. #else
  134. LocalService *s = new LocalService(path);
  135. Mutex::Lock _l(_rpcServices_m);
  136. _rpcServices[std::string(name)] = s;
  137. #endif
  138. }
  139. uint64_t RPC::callRemote(
  140. const Address &peer,
  141. const std::string &name,
  142. const std::vector<std::string> &args,
  143. void (*handler)(void *,uint64_t,const Address &,int,const std::vector<std::string> &),
  144. void *arg)
  145. throw(std::invalid_argument,std::out_of_range)
  146. {
  147. Packet outp(peer,_r->identity.address(),Packet::VERB_RPC);
  148. if (name.length() > 0xffff)
  149. throw std::invalid_argument("function name too long");
  150. outp.append((uint16_t)name.length());
  151. outp.append(name);
  152. for(std::vector<std::string>::const_iterator a(args.begin());a!=args.end();++a) {
  153. if (a->length() > 0xffff)
  154. throw std::invalid_argument("argument too long");
  155. outp.append((uint16_t)a->length());
  156. outp.append(*a);
  157. }
  158. outp.compress();
  159. uint64_t id = outp.packetId();
  160. {
  161. Mutex::Lock _l(_remoteCallsOutstanding_m);
  162. RemoteCallOutstanding &rc = _remoteCallsOutstanding[id];
  163. rc.callTime = Utils::now();
  164. rc.peer = peer;
  165. rc.handler = handler;
  166. rc.arg = arg;
  167. }
  168. _r->sw->send(outp,true);
  169. return id;
  170. }
  171. void RPC::clean()
  172. {
  173. Mutex::Lock _l(_remoteCallsOutstanding_m);
  174. uint64_t now = Utils::now();
  175. for(std::map<uint64_t,RemoteCallOutstanding>::iterator co(_remoteCallsOutstanding.begin());co!=_remoteCallsOutstanding.end();) {
  176. if ((now - co->second.callTime) >= ZT_RPC_TIMEOUT) {
  177. if (co->second.handler)
  178. co->second.handler(co->second.arg,co->first,co->second.peer,ZT_RPC_ERROR_EXPIRED_NO_RESPONSE,std::vector<std::string>());
  179. _remoteCallsOutstanding.erase(co++);
  180. } else ++co;
  181. }
  182. }
  183. } // namespace ZeroTier