Advertisement
Guest User

Untitled

a guest
Apr 15th, 2016
1,947
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 118.65 KB | None | 0 0
  1. #include <rpc-endpoint.h>
  2. #include <rpc-connection.h>
  3. #include <t1.h>
  4. #include "../version.h"
  5. #include <t1-network.h>
  6. #include <t1enums.h>
  7. #include <objects-service.h>
  8. #include "serverobject.h"
  9. #include "certificates.h"
  10. #include "../generated/tech1network-rpc-main.h"
  11.  
  12. #include <boost/thread.hpp>
  13. #include <boost/enable_shared_from_this.hpp>
  14. #include <boost/filesystem/convenience.hpp>
  15. #include <boost/regex.hpp>
  16. #include <fileutils.h>
  17. #include <stringutils.h>
  18. #include <timeutils.h>
  19. #include <socketutils.h>
  20. #include <crypto-utils.h>
  21. #include <jsonutils.h>
  22. #include <map>
  23.  
  24.  
  25. const char* webdog_custom_path_str = "webdog-custom.txt";
  26. using namespace Constellation;
  27.  
  28. static Tech1* tech1;
  29. extern EventType event_connected_to;
  30. extern EventType event_disconnected_from;
  31.  
  32. // prototypes
  33.  
  34. static Settings root_under_admin;
  35.  
  36. static Settings network_folder;
  37. Settings NetworkNode; // used in webview.cpp
  38. static Settings NetworkFolder;
  39. static Settings NetworkNodeStats;
  40. static Settings NetworkNodeVirtual;
  41.  
  42. static Settings NetworkNodeAdd;
  43. static Settings node_add_dot_dot_dot;
  44.  
  45. static bool going_down = false;
  46.  
  47. static const std::list<std::string> whitelist_economy(csv_explode(
  48.     "LocalServer,RemoteServer,ChannelsFolder,Channel,ChannelInfo,TemplatesFolder,Template,Map,MapLevel,SystemWideOptions,Health"));
  49. static const std::list<std::string> whitelist_cloud(csv_explode(
  50.     "LocalServer,ChannelsFolder,Channel,ChannelInfo,ChannelFlags,ChannelStats,IpCamerasFolder,Grabber,GrabberCaps,ZoneCaps,GrabberFeedback"));
  51. static const std::list<std::string> whitelist_amerge(
  52.     csv_explode("LocalServer"));
  53.  
  54. // stornix
  55. static const std::list<std::string> blacklist_cluster2client(
  56.     csv_explode("StornixVolumeStat,StornixDisksStat,NetworkFolder"));
  57. static const std::list<std::string> blacklist_cluster2cluster(
  58.     csv_explode("Health,Cloud,Audit,NetworkFolder,TimeSetup"));
  59.  
  60. class NetworkDirTracker;
  61. static boost::shared_ptr<NetworkDirTracker> network_tracker;
  62. class NetworkNodeAddTracker;
  63. static boost::shared_ptr<NetworkNodeAddTracker> network_node_add_tracker;
  64.  
  65. static boost::mutex amerge_session_mutex;
  66.  static boost::shared_ptr<class AmergeRpcSession> amerge_session;
  67.  
  68. static boost::mutex rm_mutex;
  69.  static boost::shared_ptr<Endpoint> clientrm;
  70.  static boost::shared_ptr<Endpoint> serverrm;
  71.  
  72. class RpcClient;
  73. class RpcServer;
  74. static boost::shared_ptr<RpcClient> client;
  75.  
  76. class LocalOperatorTracker;
  77. static boost::shared_ptr<LocalOperatorTracker> local_operator_tracker;
  78.  
  79. static void update_node_ip_callback(int64_t session_id, const std::string& ip_address);
  80. static void update_node_address_callback(int64_t session_id, const std::string& ip_address, int port_rpc, int port_video);
  81. static void socket_error_callback(int64_t session_id, const std::string& error_message);
  82.  
  83. extern void netclient_found_remote_service( // will hold reference on service
  84.         const std::string& key,
  85.         const Settings& network_node,
  86.         const boost::shared_ptr<Interface>& service
  87.         );
  88. extern void netclient_lost_remote_service(
  89.         const std::string& key
  90.         );
  91. extern void netclient_lost_all_services_for_node(
  92.         const Settings& network_node
  93.         );
  94. extern void netserver_add_remote_service_list_receiver(
  95.     const std::string& required_server_guid,
  96.     const boost::shared_ptr<NetClientDir>& client,
  97.     const Settings& root_under_client_user,
  98.     bool economy_mode
  99.     );
  100.  
  101. extern int64_t rpc_inject_socket(const boost::shared_ptr<CloudConnectSocket>&, Rpc::Callbacks session_callbacks);
  102.  
  103.  
  104. // cloud-connect
  105. extern void cloud_connect_init(Tech1* t1);
  106. extern void cloud_connect_after_load();
  107. extern void cloud_connect_done();
  108.  
  109. extern void client_cloud_connect(const boost::shared_ptr<CloudConnectRequest>& request);
  110. extern void cloud_disconnect(const std::string& server_id);
  111.  
  112. bool is_cc_t1cloud_folder(const std::string& name)
  113. {
  114.     return name.substr(0, 12) == "cloudtrassir";
  115. }
  116. std::string get_cc_t1cloud_foldername(const std::string& accountid)
  117. {
  118.     return "cloudtrassir" + accountid;
  119. }
  120. bool is_cc_to_t1cloud(const std::string& name)
  121. {
  122.     return name.substr(0, 8) == "vtrassir";
  123. }
  124. std::string get_cc_cloudid_for_t1cloud(const std::string& accountid)
  125. {
  126.     return "vtrassir" + accountid;
  127.  
  128. }
  129. static
  130. std::string extract_address_from_name(const std::string& name)
  131. {
  132.     std::string ip = name.substr(name.find_last_of("(") + 1);
  133.     if (!ip.empty()) {
  134.         ip = ip.substr(0, ip.find_last_of(")"));
  135.     }
  136.     return ip;
  137. }
  138.  
  139. extern void cloud_client_start_thread(const Settings& user);
  140. extern void cloud_client_logout();
  141.  
  142. static
  143. void create_network_prototypes(const Settings& root)
  144. {
  145.     {
  146.         SettingsLock lock(root);
  147.         NetworkNode = root->dir_create("NetworkNode", Settings());
  148.         NetworkNodeStats = root->dir_create("NetworkNodeStats", Settings());
  149.         NetworkNodeAdd = root->dir_create("NetworkNodeAdd", Settings());
  150.         NetworkFolder = root->dir_create("NetworkFolder", Settings());
  151.         NetworkNodeVirtual = root->dir_create("NetworkNodeVirtual", NetworkNode);
  152.     }
  153.  
  154.     for (int i=0; i<2; ++i) {
  155.         Settings nn = i==0 ? NetworkNode : NetworkNodeVirtual;
  156.         SettingsLock lock(nn);
  157.         nn->create_value_string("origin_account", RIGHTS_VIEW, RIGHTS_ROOT, "");
  158.         nn->create_value_string("name", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
  159.         nn->create_value_string("ip_address", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
  160.         nn->create_value_string("ip_addresses", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
  161.         nn->create_value_string("accepted_fingerprint", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
  162.         nn->create_value_integer("port_rpc", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, 3080);
  163.         nn->create_value_integer("port_video", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, 3081);
  164.         nn->create_value_string("username", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
  165.         nn->create_value_string("password", RIGHTS_PASSWORD, RIGHTS_SETUP, "");
  166.         nn->create_value_integer("should_be_connected", RIGHTS_VIEW, RIGHTS_SETUP, 1);
  167.         nn->create_value_integer("economy_mode", RIGHTS_VIEW, RIGHTS_SETUP, 0);
  168.         nn->create_value_integer("network_recurse_level", RIGHTS_VIEW, RIGHTS_SETUP, 1);
  169.         nn->create_value_integer("relay_count", RIGHTS_VIEW, RIGHTS_ROOT, 0);
  170.         nn->create_value_integer("buffering", RIGHTS_VIEW, RIGHTS_SETUP, 0);
  171.         nn->create_value_integer("disable_mainstream", RIGHTS_VIEW, RIGHTS_SETUP, 0);
  172.         nn->create_value_string("icon", RIGHTS_VIEW, RIGHTS_ROOT, ":/settings/server.gif");
  173.         nn->create_value_string("reachable_via_this_node", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_ROOT, "");
  174.         nn->create_value_string("last_cc_timestamp", RIGHTS_VIEW, RIGHTS_SETUP, "0");
  175.         nn->create_value_integer("address_from_cc_success", RIGHTS_VIEW, RIGHTS_SETUP, 0);
  176.  
  177.         nn->create_value_integer("use_cloud_connect", RIGHTS_VIEW, RIGHTS_SETUP, 0);
  178.         nn->create_value_string("cloud_id", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
  179.  
  180.         nn->create_value_integer("autocredentials", RIGHTS_VIEW, RIGHTS_SETUP, 0);
  181.         nn->create_value_integer("generated", RIGHTS_VIEW, RIGHTS_SETUP, 0);
  182.  
  183.         nn->evolve_into_prototype(
  184.                 Dir::SAVE_TO_DISK|
  185.                 Dir::TRANSMIT_TO_CLIENT|
  186.                 (i==0 ? Dir::SHOW_IN_TREE : 0)|
  187.                 Dir::CDEF_IGNORE|
  188.                 Dir::ACL_VIEW|Dir::ACL_SETUP
  189.                 );
  190.     }
  191.  
  192.     {
  193.         SettingsLock lock(NetworkNodeStats);
  194.         NetworkNodeStats->create_value_string("fingerprint", RIGHTS_VIEW, RIGHTS_ROOT, "");
  195.         NetworkNodeStats->create_value_integer("connected", RIGHTS_VIEW, RIGHTS_ROOT, 0);
  196.         NetworkNodeStats->create_value_string("last_error", RIGHTS_VIEW, RIGHTS_ROOT, "");
  197.         NetworkNodeStats->create_value_string("resolve_warning", RIGHTS_VIEW, RIGHTS_ROOT, "");
  198.         NetworkNodeStats->create_value_string("connected_using", RIGHTS_VIEW, RIGHTS_ROOT, "");
  199.  
  200.         NetworkNodeStats->evolve_into_prototype(
  201.             Dir::TRANSMIT_TO_CLIENT|
  202.             Dir::CDEF_IGNORE
  203.             );
  204.     }
  205.  
  206.     {
  207.         SettingsLock lock(NetworkNodeAdd);
  208.         NetworkNodeAdd->create_value_string("new_node_id", RIGHTS_SETUP, RIGHTS_SETUP, "");
  209.         NetworkNodeAdd->create_value_string("new_origin_account", RIGHTS_SETUP, RIGHTS_SETUP, "");
  210.         NetworkNodeAdd->create_value_string("new_node_name", RIGHTS_SETUP, RIGHTS_SETUP, "");
  211.         NetworkNodeAdd->create_value_integer("new_node_port_rpc", RIGHTS_SETUP, RIGHTS_SETUP, 3080);
  212.         NetworkNodeAdd->create_value_integer("new_node_port_video", RIGHTS_SETUP, RIGHTS_SETUP, 3081);
  213.         NetworkNodeAdd->create_value_string("new_node_username", RIGHTS_ROOT, RIGHTS_SETUP, "");
  214.         NetworkNodeAdd->create_value_string("new_node_password", RIGHTS_PASSWORD, RIGHTS_SETUP, "");
  215.         NetworkNodeAdd->create_value_integer("create_now", RIGHTS_ROOT, RIGHTS_SETUP, 0);
  216.         NetworkNodeAdd->create_value_string("delete_node_id", RIGHTS_ROOT, RIGHTS_SETUP, "");
  217.  
  218.         NetworkNodeAdd->create_value_integer("new_node_use_cloud_connect", RIGHTS_ROOT, RIGHTS_SETUP, 0);
  219.         NetworkNodeAdd->create_value_string("new_node_cloud_id", RIGHTS_ROOT, RIGHTS_SETUP, "");
  220.  
  221.         NetworkNodeAdd->create_value_integer("new_node_generated", RIGHTS_VIEW, RIGHTS_SETUP, 0);
  222.         NetworkNodeAdd->create_value_integer("new_node_autocredentials", RIGHTS_VIEW, RIGHTS_SETUP, 0);
  223.         NetworkNodeAdd->create_value_integer("new_node_economy", RIGHTS_VIEW, RIGHTS_SETUP, 0);
  224.  
  225.         NetworkNodeAdd->evolve_into_prototype(
  226.                 Dir::TRANSMIT_TO_CLIENT|
  227.                 Dir::SHOW_IN_TREE
  228.                 );
  229.     }
  230.     {
  231.         SettingsLock lock(NetworkFolder);
  232.         NetworkFolder->create_value_string("icon", 0, RIGHTS_ROOT, ":/settings/setup-network.png");
  233.         NetworkFolder->create_value_integer("cloud_connect_enable", RIGHTS_VIEW, RIGHTS_SETUP, 0);
  234.         NetworkFolder->create_value_string("upnp_gate", RIGHTS_VIEW, RIGHTS_SETUP, "discovering");
  235.         NetworkFolder->create_value_integer("limit_client_count", RIGHTS_VIEW, RIGHTS_SETUP, 100);
  236.         NetworkFolder->create_value_string("offline_passwords", RIGHTS_PASSWORD, RIGHTS_ROOT, "");
  237.         NetworkFolder->evolve_into_prototype(
  238.                 Dir::SAVE_TO_DISK|
  239.                 Dir::TRANSMIT_TO_CLIENT|
  240.                 Dir::SHOW_IN_TREE|
  241.                 Dir::FORCE_SUBOBJECTS_FIND|
  242.                 Dir::ACL_VIEW|Dir::ACL_SETUP
  243.                 );
  244.     }
  245. }
  246.  
  247. struct PasswordData
  248. {
  249.     std::string server_guid;
  250.     std::string offline_password;
  251.     uint64_t last_successful_login_ts;
  252.  
  253.     PasswordData(const std::string& server_guid, const std::string& password, uint64_t ts):
  254.         server_guid(server_guid),
  255.         offline_password(password),
  256.         last_successful_login_ts(ts)
  257.     {}
  258. };
  259.  
  260. static std::string password_data_list_to_string(const std::list<PasswordData>& pass_data)
  261. {
  262.     std::string s;
  263.     std::list<PasswordData>::const_iterator x;
  264.     for (x=pass_data.begin(); x!= pass_data.end(); ++x) {
  265.         if (!s.empty())
  266.             s += ",";
  267.         s += escape_string(x->server_guid);
  268.         s += "," + escape_string(x->offline_password);
  269.         s += "," + escape_string(print_uint64(x->last_successful_login_ts));
  270.     }
  271.     return s;
  272. }
  273.  
  274. static std::list<PasswordData> string_to_password_data_list(const std::string& s)
  275. {
  276.     std::list<PasswordData> list;
  277.     std::istringstream i(s);
  278.     for (std::string split; std::getline(i, split, ','); ) {
  279.         std::string id = unescape_string(split);
  280.         if (!std::getline(i, split, ',')) break;
  281.         std::string pass = unescape_string(split);
  282.         if (!std::getline(i, split, ',')) break;
  283.         uint64_t ts = scan_uint64(unescape_string(split));
  284.         list.push_back( PasswordData(id, pass, ts) );
  285.     }
  286.     return list;
  287. }
  288.  
  289. // server dir
  290.  
  291. class ServerDirReal: // remote user agent
  292.     public Dir::Notification,
  293.     public NetServerDir,
  294.     public boost::enable_shared_from_this<ServerDirReal>
  295. {
  296. public:
  297.     Settings dir_under_remote_user;
  298.     bool erased;
  299.     int recursion_limit;
  300.     bool i_am_root_server_finder;
  301.     bool i_am_cluster;
  302.     const std::list<std::string>* folders_whitelist;
  303.     const std::list<std::string>* folders_blacklist;
  304.  
  305.     boost::mutex remote_client_mutex;
  306.      boost::shared_ptr<NetClientDir> fragile_remote_client_dir;
  307.      boost::shared_ptr<NetClientServiceListReceiver> fragile_service_client;
  308.  
  309.     ServerDirReal(const Settings& dir_under_remote_user):
  310.         Dir::Notification("ServerDir"),
  311.         dir_under_remote_user(dir_under_remote_user),
  312.         erased(false),
  313.         i_am_root_server_finder(false),
  314.         i_am_cluster(false),
  315.         recursion_limit(-1),
  316.         folders_whitelist(0),
  317.         folders_blacklist(0)
  318.     {
  319.     }
  320.  
  321.     boost::shared_ptr<NetClientDir> client_still_alive()
  322.     {
  323.         boost::mutex::scoped_lock lock(remote_client_mutex);
  324.         return fragile_remote_client_dir;
  325.     }
  326.  
  327.     boost::shared_ptr<NetClientServiceListReceiver> service_client_still_alive()
  328.     {
  329.         boost::mutex::scoped_lock lock(remote_client_mutex);
  330.         return fragile_service_client;
  331.     }
  332.  
  333.     boost::mutex subtrackers_mutex;
  334.      std::map< std::string, boost::shared_ptr<ServerDirReal> > subtrackers;
  335.  
  336.     void constellation_folder_added(
  337.         const Settings& tracked_dir,
  338.         const Settings& new_folder)
  339.     {
  340.         if (new_folder->is_prototype()) return;
  341.  
  342.         new_folder->this_is_used_from_network_folder();
  343.  
  344.         if (folders_whitelist)
  345.             if (std::find(folders_whitelist->begin(), folders_whitelist->end(), new_folder->prototype_name())
  346.                 ==folders_whitelist->end()) return;
  347.         if (folders_blacklist)
  348.             if (std::find(folders_blacklist->begin(), folders_blacklist->end(), new_folder->prototype_name())
  349.                 !=folders_blacklist->end()) return;
  350.  
  351.         const int current_level = new_folder->network_recurse_level();
  352.         if (current_level >= recursion_limit) return;
  353.  
  354.         const uint32_t options = new_folder->options();
  355.         if (!(options & Dir::TRANSMIT_TO_CLIENT)) return;
  356.         if (new_folder->name()=="info_unfiltered") return;
  357.  
  358.         //log("NETSERVER: discovered folder %i %s\n", new_folder->network_recurse_level(), new_folder->path().c_str() );
  359.         boost::shared_ptr<ServerDirReal> new_server_dir(
  360.             new ServerDirReal(new_folder)
  361.             );
  362.         new_server_dir->folders_whitelist = folders_whitelist;
  363.         new_server_dir->folders_blacklist = folders_blacklist;
  364.         new_server_dir->i_am_cluster = i_am_cluster;
  365.         new_server_dir->recursion_limit = recursion_limit;
  366.  
  367.         {
  368.             boost::mutex::scoped_lock sublock(subtrackers_mutex);
  369.             std::map< std::string, boost::shared_ptr<ServerDirReal> >::iterator i = subtrackers.find(new_folder->name());
  370.             assert( i==subtrackers.end() );
  371.             subtrackers[new_folder->name()] = new_server_dir;
  372.         }
  373.  
  374.         if (i_am_root_server_finder) {
  375.             boost::shared_ptr<NetClientServiceListReceiver> sc = service_client_still_alive();
  376.             if (sc && (new_folder->prototype_name()=="RemoteServer" || new_folder->prototype_name()=="LocalServer")) {
  377.                 std::string route;
  378.                 std::string name;
  379.                 std::string cluster_node_guid;
  380.                 {
  381.                     SettingsLock lock(new_folder);
  382.                     route = new_folder->get_value_string("media_route");
  383.                     name = new_folder->get_value_string("name");
  384.                     if (new_folder->prototype_name() == "LocalServer")
  385.                         cluster_node_guid = new_folder->get_value_string("cluster_node_guid");
  386.                 }
  387.  
  388.                 std::string whitelist;
  389.                 if (!(tech1->have_mini() && "Admin" == dir_under_remote_user->user_id())) {
  390.                     SettingsLock lock(new_folder);
  391.                     whitelist = new_folder->get_value_string("whitelist");
  392.                 }
  393.                 sc->whitelist_send(new_folder->name(), whitelist);
  394.  
  395.                 sc->add_server(
  396.                     i_am_cluster ? cluster_node_guid : new_folder->name(),
  397.                     name,
  398.                     route,
  399.                     new_server_dir,
  400.                     current_level + 1
  401.                     );
  402.  
  403.             } else
  404.                 log("NETSERVER: folder_added bug, cannot send path %s\n", new_folder->path().c_str());
  405.         } else {
  406.             boost::shared_ptr<NetClientDir> remote_client = client_still_alive();
  407.             if (remote_client) {
  408.                 const std::string& prototype_name = new_folder->prototype_name();
  409.                 boost::shared_ptr<FakeW> fake = boost::dynamic_pointer_cast<FakeW>(remote_client);
  410.                 if (fake) {
  411.                     boost::shared_ptr<SessionW> session = fake->session_get();
  412.                     int32_t h = our_hash_impl(prototype_name);
  413.                     std::set<int32_t>::iterator hi = session->constellation_prototype_introduced.find(h);
  414.                     if (hi == session->constellation_prototype_introduced.end()) {
  415.                         session->constellation_prototype_introduced.insert(h);
  416.  
  417.                         Settings prototype;
  418.                         {
  419.                             SettingsLock lock(root_under_admin);
  420.                             prototype = root_under_admin->dir_find_prototype(prototype_name);
  421.                         }
  422.  
  423.                         assert(prototype);
  424.                         Json::Value desc = Json::objectValue;
  425.                         desc["fields"] = Json::arrayValue;
  426.                         {
  427.                             SettingsLock lock(prototype);
  428.                             desc["options"] = prototype->options();
  429.                             std::list<std::string> fields = prototype->ls_values();
  430.                             std::list<std::string>::iterator it;
  431.                             for (it = fields.begin(); it != fields.end(); ++it) {
  432.                                 const std::string& field = *it;
  433.                                 Json::Value field_desc = Json::objectValue;
  434.                                 field_desc["name"] = field;
  435.                                 char type = prototype->type_of(field);
  436.                                 field_desc["type"] = std::string(&type, 1);
  437.                                 switch (type) {
  438.                                 case 's':
  439.                                     field_desc["default"] = prototype->get_value_string(field);
  440.                                     break;
  441.                                 case 'i':
  442.                                     field_desc["default"] = prototype->get_value_integer(field);
  443.                                     break;
  444.                                 case 'r':
  445.                                     field_desc["default"] = prototype->get_value_real(field);
  446.                                     break;
  447.                                 default:
  448.                                     log_warning("FOLDER PROTOTYPE BAD: %s(%c)\n", field.c_str(), type);
  449.                                 }
  450.                                 desc["fields"].append(field_desc);
  451.                             }
  452.                         }
  453.                         remote_client->add_prototype(
  454.                             new_folder->prototype_name(),
  455.                             Json::FastWriter().write(desc)
  456.                             );
  457.                     }
  458.                 }
  459.                 remote_client->add_folder(
  460.                     new_folder->name(),
  461.                     new_folder->prototype_name(),
  462.                     new_server_dir,
  463.                     new_folder->rights(),
  464.                     current_level + 1);
  465.             } else
  466.                 log("NETSERVER: cannot send folder %s to client\n", new_folder->path().c_str());
  467.         }
  468.     }
  469.  
  470.     void constellation_folder_removed(
  471.         const Settings& tracked_dir,
  472.         const Settings& removed_folder)
  473.     {
  474.         const std::string& id = removed_folder->name();
  475.         {
  476.             boost::mutex::scoped_lock sublock(subtrackers_mutex);
  477.             std::map< std::string, boost::shared_ptr<ServerDirReal> >::iterator i = subtrackers.find(id);
  478.             if ( i==subtrackers.end() ) return; // never added, because of no TRANSMIT_TO_CLIENT flag
  479.             boost::shared_ptr<NetClientDir> remote_client = client_still_alive();
  480.             if (remote_client) {
  481.                 remote_client->remove_folder(removed_folder->name());
  482.             } else {
  483.                 log("NETSERVER: cannot remove folder %s from client\n", removed_folder->path().c_str());
  484.             }
  485.             boost::shared_ptr<ServerDirReal>& my_subtracker = i->second;
  486.             { // tear down circular client-server links
  487.                 boost::mutex::scoped_lock lock(my_subtracker->remote_client_mutex);
  488.                 my_subtracker->fragile_remote_client_dir.reset();
  489.             }
  490.             subtrackers.erase(i);
  491.         }
  492.     }
  493.  
  494.     void constellation_tracked_dir_erased(const Settings& tracked_dir)
  495.     {
  496.         boost::mutex::scoped_lock lock(remote_client_mutex);
  497.         fragile_remote_client_dir.reset();
  498.         erased = true;
  499.     }
  500.  
  501.     // from network
  502.     void pass_dir_receiver(const boost::shared_ptr<NetClientDir>& new_cd)
  503.     {
  504.         if (!new_cd) {
  505.             log("NETWORK: ERROR: pass_dir_receiver() bug\n");
  506.             return;
  507.         }
  508.  
  509.         boost::mutex::scoped_lock lock(remote_client_mutex);
  510.         if (!erased) {
  511.             fragile_remote_client_dir = new_cd;
  512.         }
  513.     }
  514.  
  515.     // top-level role, called from login
  516.     void pass_server_receiver(const boost::shared_ptr<NetClientServiceListReceiver>& new_sc)
  517.     {
  518.         assert(new_sc);
  519.         boost::mutex::scoped_lock lock(remote_client_mutex);
  520.         if (!erased)
  521.             fragile_service_client = new_sc;
  522.     }
  523.  
  524.     bool is_server(const Settings& s)
  525.     {
  526.         const std::string& protoname = s->prototype_name();
  527.         bool it_is = false;
  528.         it_is |= protoname=="LocalServer";
  529.         it_is |= protoname=="RemoteServer";
  530.         return it_is;
  531.     }
  532.  
  533.     // from network
  534.     void client2server_start_work()
  535.     {
  536.         if (is_server(dir_under_remote_user)) {
  537.             boost::mutex::scoped_lock lock(remote_client_mutex);
  538.             if (!fragile_remote_client_dir) {
  539.                 log_warning("NETWORK: no client in client2server_start_work()\n");
  540.                 return;
  541.             }
  542.             netserver_add_remote_service_list_receiver(
  543.                 dir_under_remote_user->name(),
  544.                 fragile_remote_client_dir,
  545.                 dir_under_remote_user->cd("/", true),
  546.                 !!folders_whitelist
  547.                 );
  548.         }
  549.         SettingsLock lock(dir_under_remote_user);
  550.         dir_under_remote_user->add_notification(shared_from_this(),
  551.             Dir::WANT_ADD_REMOVE|
  552.             Dir::WANT_RIGHTS_CHANGE|
  553.             Dir::FIRE_VALUE_NOTIFICATION_NOW|
  554.             Dir::WANT_NETWORK_SERIALIZATION|
  555.             Dir::WANT_NETWORK_SERVER2CLIENT|
  556.             (i_am_cluster ? Dir::WANT_NETWORK_CLUSTER2CLUSTER : 0)
  557.             );
  558.     }
  559.  
  560.     // from network
  561.     void client2server_stop_work()
  562.     {
  563.         {
  564.             SettingsLock lock(dir_under_remote_user);
  565.             dir_under_remote_user->notification_remove(shared_from_this());
  566.         }
  567.         {
  568.             log_timestamp("NETSERVER: disconnected client\n");
  569.             // TODO: reverse function for netserver_add_remote_service_list_receiver()
  570.         }
  571.         std::map< std::string, boost::shared_ptr<ServerDirReal> > tmp;
  572.         {
  573.             boost::mutex::scoped_lock sublock(subtrackers_mutex);
  574.             tmp.swap(subtrackers); // equivalent to constellation_folder_removed() all
  575.         }
  576.     }
  577.  
  578.     // from network
  579.     void client2server_value_changes(const std::string& s)
  580.     {
  581.         if (i_am_cluster) {
  582.             log_warning("CLUSTER SHOULD NOT DO THAT: %s\n", s.c_str());
  583.             return;
  584.         }
  585.         boost::shared_ptr<NetClientDir> remote_client = client_still_alive();
  586.         std::string tmp = s.substr(s.find("/"));
  587.         std::string dir = tmp.substr(0, tmp.find(" "));
  588.         tmp = tmp.substr(tmp.find("\n") + 1);
  589.         tmp = tmp.substr(tmp.find("\n") + 1);
  590.  
  591.         while (true) {
  592.             std::string key = tmp.substr(0, tmp.find(" "));
  593.             tmp = tmp.substr(tmp.find(" ") + 1);
  594.             tmp = tmp.substr(tmp.find_first_not_of(" "));
  595.             size_t lb_pos = tmp.find("\n");
  596.             std::string value = tmp.substr(0, lb_pos);
  597.             tech1->useraction_log("SETTINGS/SET", remote_client, "~operator",
  598.                 "%s/%s = %s", dir.c_str(), key.c_str(), value.c_str());
  599.             tmp = tmp.substr(lb_pos + 1);
  600.             if (tmp.empty())
  601.                 break;
  602.         }
  603.  
  604.         SettingsLock lock(dir_under_remote_user);
  605.         std::istringstream i2(s);
  606.         for (std::string split; std::getline(i2, split, '\n'); ) {
  607.             if (split.empty()) continue;
  608.             if (split[0]=='#') continue;
  609.             log("FROM CLIENT: '%s'\n", split.c_str());
  610.  
  611.             std::string::size_type pos = split.find(' ');
  612.             if (pos==std::string::npos) {
  613.                 log("NETSERVER: cannot parse value update from client: '%s'\n", split.c_str());
  614.                 continue;
  615.             }
  616.  
  617.             std::string key = split.substr(0, pos);
  618.             std::string::size_type size = split.size();
  619.  
  620.             while (pos<size && split[pos]==' ')
  621.                 ++pos;
  622.  
  623.             try {
  624.                 dir_under_remote_user->network_unserialize_client2server_value(
  625. #ifdef T1_SERVER
  626.                     dir_under_remote_user->hash(key),
  627. #else
  628.                     key,
  629. #endif
  630.                     key,
  631.                     split.c_str() + pos
  632.                     );
  633.             } catch (const std::logic_error& e) {
  634.                 log("NETSERVER: %s\n", e.what());
  635.                 // nothing we can do here but complain to logs, client is untrusted
  636.                 continue;
  637.             }
  638.         }
  639.     }
  640.  
  641.     void constellation_folder_adjust_before_serialization(const Settings& serialized_dir, std::map<std::string, std::string>& values_to_add_or_replace)
  642.     {
  643.         /*if (serialized_dir->prototype_name() == "ChannelInfo") {
  644.             values_to_add_or_replace["restrictions"] = "sample text";
  645.         }*/ // final
  646.  
  647.         if (serialized_dir->prototype_name() == "Channel") {
  648.             values_to_add_or_replace["playback_time"] = "{completely broken}";
  649.         }
  650.     }
  651.  
  652.     void constellation_network_serialization(int rev, const std::string& serialization)
  653.     {
  654.         log_warning("\n-------\n%s\n-------\n", serialization.c_str());
  655.         boost::shared_ptr<NetClientDir> remote_client = client_still_alive();
  656.         if (remote_client)
  657.             remote_client->update_values(rev, serialization);
  658.     }
  659.  
  660.     void constellation_effective_rights_changed(const Settings& tracked_dir)
  661.     {
  662.         //log("ERC!\n");
  663.         boost::shared_ptr<NetClientDir> remote_client = client_still_alive();
  664.         if (remote_client)
  665.             remote_client->update_effective_rights(tracked_dir->rights());
  666.     }
  667. };
  668.  
  669.  
  670. // client dir
  671.  
  672. class ClientDirReal:
  673.     public boost::enable_shared_from_this<ClientDirReal>,
  674.     public Constellation::Dir::Notification,
  675.     public NetClientDir
  676. {
  677. public:
  678.     boost::mutex dirs_mutex;
  679.      Settings i_serve_here; // under admin
  680.      bool subscribed_on_client2server;
  681.      boost::shared_ptr<NetServerDir> my_server_dir;
  682.      Settings filtered_channel_info;
  683.  
  684.     bool i_work_as_root;
  685.     bool i_work_as_tier_server;
  686.  
  687.     boost::weak_ptr<class NetworkNodeTracker> network_node;
  688.  
  689.     ClientDirReal(
  690.         const Settings& i_serve_here,
  691.         const boost::shared_ptr<NetServerDir>& server_dir,
  692.         const boost::shared_ptr<NetworkNodeTracker>& network_node)
  693.         :
  694.         Constellation::Dir::Notification("ClientDir"),
  695.         i_serve_here(i_serve_here),
  696.         my_server_dir(server_dir),
  697.         network_node(network_node),
  698.         i_work_as_root(false),
  699.         i_work_as_tier_server(false)
  700.     {
  701.         subscribed_on_client2server = false;
  702.         // my_server_dir is 0 here only if we serve at root, but we will set later, see keep_reference_on_root_folder()
  703.     }
  704.  
  705.     ~ClientDirReal()
  706.     {
  707.         if (i_work_as_tier_server) return;
  708.  
  709.         Settings my_parent = i_serve_here->parent();
  710.         if (!i_work_as_root) {
  711.             try {
  712.                 SettingsLock lock(my_parent);
  713.                 my_parent->dir_remove(i_serve_here->name());
  714.                 if (filtered_channel_info)
  715.                     my_parent->dir_remove(filtered_channel_info->name());
  716.  
  717.             } catch (const not_found_error&) {
  718.                 // log("ClientDirReal: destruction reordering, normal?\n");
  719.             }
  720.         }
  721.     }
  722.  
  723.     // from network
  724.     void update_values(int rev, const std::string& s)
  725.     {
  726.         if (i_work_as_tier_server)
  727.             return;
  728.         if (i_work_as_root) {
  729.             log("NETCLIENT: ERROR: update_values() on root folder, malicious server?\n");
  730.             return;
  731.         }
  732.  
  733.         Settings serve_here_copy;
  734.         {
  735.             boost::mutex::scoped_lock dirs_lock(dirs_mutex);
  736.             serve_here_copy = i_serve_here;
  737.         }
  738.         if (!serve_here_copy) return; // lost the vote
  739.  
  740.         SettingsLock lock(serve_here_copy);
  741.         serve_here_copy->network_unserialize_server2client_values(1000+rev, s, false, false);
  742.  
  743.         if (filtered_channel_info) {
  744.             SettingsLock lock2(filtered_channel_info);
  745.             implement_disable_mainstream(filtered_channel_info, serve_here_copy);
  746.         }
  747.  
  748.         if (!subscribed_on_client2server) {
  749.             subscribed_on_client2server = true;
  750.             serve_here_copy->add_notification(shared_from_this(), Dir::WANT_NETWORK_SERIALIZATION);
  751.         }
  752.     }
  753.  
  754.     void implement_disable_mainstream(const Settings& channel_info_locked, const Settings& unfiltered_channel_info);
  755.  
  756.     // from network
  757.     void add_folder(
  758.         const std::string& folder_name,
  759.         const std::string& prototype_name,
  760.         const boost::shared_ptr<NetServerDir>& server_dir,
  761.         uint32_t rights,
  762.         int recurse_level)
  763.     {
  764.         if (recurse_level<=0 || recurse_level>7) {
  765.             log_warning("NETCLIENT: bad recurse level %i\n", recurse_level);
  766.             return;
  767.         }
  768.  
  769.         Settings new_dir;
  770.  
  771.         Settings prototype;
  772.         {
  773.             SettingsLock lock(root_under_admin);
  774.             prototype = root_under_admin->dir_find_prototype(prototype_name);
  775.             if (!prototype) {
  776.                 log_warning("CLIENTNET: add_folder() cannot find prototype '%s'\n", prototype_name.c_str());
  777.                 return;
  778.             }
  779.         }
  780.  
  781.         boost::mutex::scoped_lock dirs_lock(dirs_mutex);
  782.  
  783.         boost::shared_ptr<NetworkNodeTracker> node = network_node.lock();
  784.         if (!node) return; // race vs shutdown
  785.         if (!i_serve_here) return; // can be changed in i_work_as_tier_server mode
  786.  
  787.         boost::shared_ptr<ClientDirReal> new_client_dir;
  788.         //log("CLIENT: %s add_folder(%s)\n", i_serve_here->path().c_str(), folder_name.c_str());
  789.         try {
  790.             bool special_info_mode = prototype->name()=="ChannelInfo";
  791.             std::string create_folder_name = folder_name;
  792.  
  793.             if (special_info_mode && folder_name=="info")
  794.                 create_folder_name = "info_unfiltered";
  795.  
  796.             {
  797.                 SettingsLock lock(i_serve_here);
  798.                 new_dir = i_serve_here->dir_create(create_folder_name, prototype);
  799.                 new_client_dir.reset(new ClientDirReal(new_dir, server_dir, node));
  800.  
  801.                 if (special_info_mode)
  802.                     new_client_dir->filtered_channel_info = i_serve_here->dir_create(
  803.                         "info",
  804.                         tech1->common_prototypes()->ChannelInfo);
  805.             }
  806.  
  807.             new_dir->this_is_network_folder(rights, recurse_level);
  808.  
  809.         } catch (const std::logic_error& e) {
  810.             // bad folder_name, etc
  811.             log("CLIENT: add_folder() cannot create folder: %s\n", e.what());
  812.             return;
  813.         }
  814.  
  815.         server_dir->pass_dir_receiver(new_client_dir);
  816.         server_dir->client2server_start_work();
  817.     }
  818.  
  819.     // from network
  820.     void remove_folder(const std::string& folder_name)
  821.     {
  822.     }
  823.  
  824.     // from network
  825.     void initial_add_completed()
  826.     {
  827.         i_serve_here->fire_initial_add_completed_notification();
  828.     }
  829.  
  830.     void constellation_tracked_dir_erased(const Settings& tracked_dir)
  831.     {
  832.         // by parent (disconnect)
  833.     }
  834.  
  835.     // from network
  836.     void update_effective_rights(uint32_t rights)
  837.     {
  838.         if (!i_work_as_root && !i_work_as_tier_server) {
  839.             Settings serve_here_copy;
  840.             {
  841.                 boost::mutex::scoped_lock dirs_lock(dirs_mutex);
  842.                 serve_here_copy = i_serve_here;
  843.             }
  844.             if (!serve_here_copy) return; // lost the vote
  845.  
  846.             //log("S2C %s: 0x%x\n", i_serve_here->path().c_str(), rights);
  847.             serve_here_copy->this_is_network_folder(rights, -1);
  848.  
  849.             if (filtered_channel_info) {
  850.                 SettingsLock lock(serve_here_copy);
  851.                 SettingsLock lock2(filtered_channel_info);
  852.                 implement_disable_mainstream(filtered_channel_info, serve_here_copy);
  853.             }
  854.         }
  855.     }
  856.  
  857.     void constellation_network_serialization(int rev, const std::string& serialization)
  858.     {
  859.         // Value revision from network always >= 1000.
  860.         // If client starts editing values before first server revision arrives, don't send it.
  861.         if (rev < 1000)
  862.             return; // set breakpoint here to see who edits values before first update from server
  863.         my_server_dir->client2server_value_changes(serialization);
  864.     }
  865.  
  866.     void add_service(const boost::shared_ptr<Interface>& service)
  867.     {
  868.         log_warning("NetClientDir: add_service()\n");
  869.     }
  870.  
  871.     void remove_service(const boost::shared_ptr<Interface>& service)
  872.     {
  873.         log_warning("NetClientDir: remove_service()\n");
  874.     }
  875.  
  876.     void remove_service_v2(const std::string& name)
  877.     {
  878.         log_warning("NetClientDir: remove_service_v2()\n");
  879.     }
  880. };
  881.  
  882.  
  883. // Voting: netclient memory db for choosing a way to connect to a server
  884.  
  885. struct VotingRecord {
  886.     int recurse_level; // lower is better
  887.     int relay_count; // lower is better
  888.     Settings network_node;
  889.     boost::weak_ptr<class ServerProvider> server_provider;
  890.     class ServerProvider* server_provider_dangerous_pointer;
  891. };
  892.  
  893. static bool compare_votes(const VotingRecord& lhs, const VotingRecord& rhs)
  894. {
  895.     if (lhs.relay_count == rhs.relay_count)
  896.         return lhs.recurse_level < rhs.recurse_level;
  897.     return lhs.relay_count < rhs.relay_count;
  898. }
  899.  
  900. class VotingServerContext:
  901.     public Constellation::Dir::Notification
  902. {
  903. public:
  904.     boost::mutex server_voting_mutex;
  905.  
  906.     std::string server_guid;
  907.     Settings remote_server;
  908.  
  909.     boost::weak_ptr<class ServerProvider> vote_winner;
  910.     std::list<VotingRecord> votes;
  911.  
  912.     void sort()
  913.     {
  914.         votes.sort(&compare_votes);
  915.     }
  916.  
  917.     VotingServerContext(const std::string& server_guid);
  918.     ~VotingServerContext();
  919.  
  920.     void decide_who_should_proceed();
  921.  
  922.     // nothing tracked, called only using fire_values_notification()
  923.     void constellation_values_changed(const Settings& tracked_dir)
  924.     {
  925.         decide_who_should_proceed();
  926.     }
  927. };
  928.  
  929. static boost::mutex voting_registry_mutex;
  930. static std::map< std::string, boost::weak_ptr<VotingServerContext> > voting_registry;
  931.  
  932.  
  933. // server provider: creates and maintains remote server subtree
  934.  
  935. class ServerProvider:
  936.     public Constellation::Dir::Notification
  937. {
  938. protected:
  939.     Settings node_dir;
  940.  
  941.     boost::mutex voting_ptr_mutex; // voting_cx and remote_welcome is not read-only
  942.      boost::shared_ptr<VotingServerContext> voting_cx; // unknown until first connect
  943.      bool i_am_providing_the_server;
  944.  
  945. public:
  946.     int recurse_level;
  947.  
  948.     ServerProvider(int recurse_level):
  949.         Constellation::Dir::Notification("ServerProvider"),
  950.         recurse_level(recurse_level)
  951.     {
  952.         i_am_providing_the_server = false;
  953.     }
  954.  
  955.     void add_me_to_voting_cx(
  956.         const std::string& server_guid,
  957.         const boost::shared_ptr<ServerProvider>& myself
  958.         )
  959.     {
  960.         // socket thread
  961.         bool just_created = false;
  962.         boost::shared_ptr<VotingServerContext> new_vcx;
  963.         {
  964.             boost::mutex::scoped_lock lock(voting_registry_mutex);
  965.             std::map< std::string, boost::weak_ptr<VotingServerContext> >::iterator x;
  966.             x = voting_registry.find(server_guid);
  967.             if (x!=voting_registry.end())
  968.                 new_vcx = x->second.lock();
  969.  
  970.             if (!new_vcx) {
  971.                 new_vcx.reset(new VotingServerContext(server_guid)); // exception if bad guid
  972.                 voting_registry[server_guid] = new_vcx;
  973.                 just_created = true;
  974.             }
  975.         }
  976.  
  977.         {
  978.             boost::mutex::scoped_lock lock1(voting_ptr_mutex);
  979.             if (voting_cx) {
  980.                 log_warning("NETCLIENT: add_me_to_voting_cx() bug\n");
  981.                 return;
  982.             }
  983.             voting_cx = new_vcx;
  984.  
  985.             boost::mutex::scoped_lock lock2(voting_cx->server_voting_mutex);
  986.             VotingRecord r;
  987.             r.network_node = node_dir;
  988.             r.server_provider = myself;
  989.             r.server_provider_dangerous_pointer = this;
  990.             assert(myself.get()==this);
  991.             r.recurse_level = myself->recurse_level;
  992.             voting_cx->votes.push_back(r);
  993.         }
  994.  
  995.         if (just_created) {
  996.             SettingsLock lock(root_under_admin);
  997.             root_under_admin->add_notification(new_vcx, 0);
  998.         }
  999.  
  1000.         root_under_admin->fire_values_notification(new_vcx);
  1001.     }
  1002.  
  1003.     // called from disconnect (socket thread or destructor)
  1004.     void remove_me_from_voting_cx()
  1005.     {
  1006.         // any thread
  1007.         boost::mutex::scoped_lock lock1(voting_ptr_mutex);
  1008.  
  1009.         boost::shared_ptr<VotingServerContext> my_voting_cx;
  1010.         {
  1011.             if (!voting_cx) return;
  1012.             my_voting_cx.swap(voting_cx);
  1013.  
  1014.             boost::mutex::scoped_lock lock2(my_voting_cx->server_voting_mutex);
  1015.             std::list<VotingRecord>::iterator x;
  1016.             for (x=my_voting_cx->votes.begin(); x!=my_voting_cx->votes.end(); ++x) {
  1017.                 const VotingRecord& r = *x;
  1018.                 if (r.server_provider_dangerous_pointer==this) {
  1019.                 //if (r.network_node==node_dir) {
  1020.                     my_voting_cx->votes.erase(x);
  1021.                     root_under_admin->fire_values_notification(my_voting_cx);
  1022.                     return;
  1023.                 }
  1024.             }
  1025.         }
  1026.  
  1027.         log_critical_error("NETCLIENT: remove_me_from_voting_cx() bug\n");
  1028.     }
  1029.  
  1030.     bool provide_server_start(
  1031.         const std::string& reasonable_name,
  1032.         const std::string& route,
  1033.         int recurse_level)
  1034.     {
  1035.         node_dir->assert_notify_thread();
  1036.  
  1037.         boost::mutex::scoped_lock lock1(voting_ptr_mutex);
  1038.         if (!voting_cx) return false; // suddenly disconnected, well, until next time
  1039.         boost::mutex::scoped_lock lock2(voting_cx->server_voting_mutex);
  1040.         //log_warning("NETCLIENT: provide_server_start(), name='%s', guid=%s\n",
  1041.         //  reasonable_name.c_str(),
  1042.         //  voting_cx->server_guid.c_str());
  1043.         via_this_node_update(voting_cx->server_guid);
  1044.  
  1045.         assert( !voting_cx->remote_server );
  1046.         assert( !i_am_providing_the_server );
  1047.  
  1048.         try {
  1049.             {
  1050.                 SettingsLock lock(root_under_admin);
  1051.                 voting_cx->remote_server = root_under_admin->dir_create(
  1052.                     voting_cx->server_guid,
  1053.                     tech1->common_prototypes()->RemoteServer
  1054.                     ); // exception if bad guid
  1055.                 i_am_providing_the_server = true;
  1056.  
  1057.                 {
  1058.                     SettingsLock lock(voting_cx->remote_server);
  1059.                     voting_cx->remote_server->set_value_string("name", reasonable_name);
  1060.                     voting_cx->remote_server->set_value_string("media_route", route);
  1061.                 }
  1062.             }
  1063.  
  1064.             if (recurse_level == 1)
  1065.             {
  1066.                 SettingsLock lock(node_dir);
  1067.                 const std::string current_name = node_dir->get_value_string("name");
  1068.  
  1069.                 std::string should_be_name = reasonable_name;
  1070.  
  1071.                 if (!current_name.empty() && current_name != reasonable_name) {
  1072.                     should_be_name += " (" + extract_address_from_name(current_name) + ")";
  1073.                 }
  1074.  
  1075.                 if (current_name != should_be_name) node_dir->set_value_string("name", should_be_name);
  1076.             }
  1077.  
  1078.             voting_cx->remote_server->this_is_network_folder(RIGHTS_EVERYTHING, recurse_level);
  1079.  
  1080.             return true;
  1081.  
  1082.         } catch (const std::logic_error& e) {
  1083.             if (voting_cx->server_guid==tech1->server_guid())
  1084.                 return false;
  1085.             log_warning("NETCLIENT: %s\n", e.what());
  1086.             return false;
  1087.         }
  1088.     }
  1089.  
  1090.     void provide_server_no_more()
  1091.     {
  1092.         // any thread
  1093.         boost::mutex::scoped_lock lock1(voting_ptr_mutex);
  1094.         if ( !voting_cx ) return; // already disconnected
  1095.         if ( !i_am_providing_the_server ) return;
  1096.         boost::mutex::scoped_lock lock2(voting_cx->server_voting_mutex);
  1097.  
  1098.         //log("NETCLIENT: %s, provide_server_no_more()\n", name.c_str());
  1099.         i_am_providing_the_server = false;
  1100.         netclient_lost_all_services_for_node(voting_cx->remote_server);
  1101.  
  1102.         {
  1103.             SettingsLock lock(root_under_admin);
  1104.             root_under_admin->dir_remove(voting_cx->remote_server->name());
  1105.             voting_cx->remote_server.reset();
  1106.         }
  1107.     }
  1108.  
  1109.     virtual void you_have_won_the_vote() =0;
  1110.     virtual void you_have_lost_the_vote() =0;
  1111.  
  1112.     void via_this_node_update(const std::string& server_guid)
  1113.     {
  1114.         unsigned int n = (unsigned int) (now() / 1000000ULL);
  1115.         SettingsLock lock(node_dir);
  1116.         csv_list list = csv_explode( node_dir->get_value_string("reachable_via_this_node") );
  1117.         csv_list new_list;
  1118.         bool seen_server_guid = false;
  1119.         for (csv_list::iterator x=list.begin(); x!=list.end(); ++x) {
  1120.             const std::string& s = *x;
  1121.             unsigned long t;
  1122.             char buf[101];
  1123.             int r = sscanf(s.c_str(), "%100s-%lu", buf, &t); // stornix can have longer guid
  1124.             buf[100] = 0;
  1125.             if (r!=2) {
  1126.                 log_warning("NETCLIENT: cannot parse reachable_via_this_node element '%s'\n",
  1127.                     s.c_str()
  1128.                     );
  1129.                 continue;
  1130.             }
  1131.             //log_warning("NETCLIENT: checking '%s' at %lu\n", buf, t);
  1132.             if (buf==server_guid) {
  1133.                 seen_server_guid = true;
  1134.                 t = n;
  1135.             }
  1136.             if (t+100*24*60*60 < n) { // 100 days cleanup
  1137.                 log_timestamp("NETCLIENT: removing server %s from reachable_via_this_node\n", server_guid.c_str());
  1138.                 continue;
  1139.             }
  1140.             new_list.push_back(stdprintf("%s-%lu", buf, t));
  1141.         }
  1142.         if (!seen_server_guid)
  1143.             new_list.push_back(stdprintf("%s-%lu", server_guid.c_str(), (long unsigned int)n));
  1144.  
  1145.         node_dir->set_value_string("reachable_via_this_node", csv_implode(new_list));
  1146.     }
  1147. };
  1148.  
  1149.  
  1150. // network node tracker: settings to connect, login to remote server
  1151.  
  1152. static Settings cloudfolder;
  1153. static Settings cloudstat;
  1154. static Settings health;
  1155. static boost::mutex health_defender;
  1156. static int health_should_be_counter = 0;
  1157. static int health_connected_counter = 0;
  1158.  
  1159. void update_node_icon(const Settings& node, int connected)
  1160. {
  1161.     SettingsLock nlock(node);
  1162.     const int should_be = node->get_value_integer("should_be_connected");
  1163.     bool vtrassir = node->prototype_name() == "NetworkNodeVirtual";
  1164.     if (connected) {
  1165.         node->set_value_string("icon", ":/settings/server.png");
  1166.     } else {
  1167.         if (!should_be) {
  1168.             node->set_value_string("icon", ":/settings/server-disabled.png");
  1169.         } else {
  1170.             node->set_value_string("icon",
  1171.                 vtrassir ? ":/settings/server-error-vtrassir.png" : ":/settings/server-error.png");
  1172.         }
  1173.     }
  1174. }
  1175.  
  1176. void update_global_health(
  1177.     bool update_error,
  1178.     const std::string& node_guid,
  1179.     const std::string& node_last_error) // health_defender locked
  1180. {
  1181.     if (!health) return;
  1182.     SettingsLock lock(health);
  1183.     health->set_value_integer("network_really_connected", health_connected_counter);
  1184.     health->set_value_integer("network_should_be_connected", health_should_be_counter);
  1185.  
  1186.     if (health_connected_counter == health_should_be_counter) {
  1187.         health->set_value_string("network_last_error", "");
  1188.         health->set_value_string("network_error_node", "");
  1189.     } else if(update_error) {
  1190.         health->set_value_string("network_last_error", node_last_error);
  1191.         health->set_value_string("network_error_node", node_guid);
  1192.     }
  1193. }
  1194.  
  1195. static bool autodetect_user(std::string *username, std::string* password)
  1196. {
  1197.     bool predefined_user = false;
  1198.     std::string predefined_username, predefined_password;
  1199.     if (cloudfolder) {
  1200.         SettingsLock lock(cloudfolder);
  1201.         predefined_username = cloudfolder->get_value_string("predefined_user_login");
  1202.         predefined_password = cloudfolder->get_value_string("predefined_user_password");
  1203.         predefined_user = !!cloudfolder->get_value_integer("predefined_user");
  1204.         predefined_user &= !predefined_username.empty();
  1205.     }
  1206.  
  1207.     if (predefined_user) {
  1208.         *username = predefined_username;
  1209.         *password = predefined_password;
  1210.         return true;
  1211.     } else {
  1212.         Settings operator_root = tech1->root_under_operator_logged_in();
  1213.         if (!operator_root) return false;
  1214.  
  1215.         std::string path = stdprintf("users/%s", operator_root->user_id().c_str());
  1216.         Settings root = tech1->local_server_under_admin();
  1217.         Settings user = root->cd(path, false);
  1218.  
  1219.         if (user) {
  1220.             SettingsLock lock(user);
  1221.             int from_cloud = user->get_value_integer("from_cloud");
  1222.             if (from_cloud) {
  1223.                 *username = user->get_value_string("name");
  1224.                 *password = user->get_value_string_with_default("password", "");
  1225.                 return true;
  1226.             }
  1227.         }
  1228.     }
  1229.     return false;
  1230. }
  1231.  
  1232. class NetworkStatNodeTracker:
  1233.     public Constellation::Dir::Notification
  1234. {
  1235. public:
  1236.     Settings stat_dir;
  1237.     boost::weak_ptr<NetworkNodeTracker> node_tracker;
  1238.     std::string last_error;
  1239.  
  1240.     NetworkStatNodeTracker(const Settings& stat_dir_, boost::shared_ptr<NetworkNodeTracker> node_tracker_);
  1241.     void constellation_values_changed(const boost::shared_ptr<Dir> &tracked_dir);
  1242. };
  1243.  
  1244. static bool check_cert(int64_t session_id, const std::string& fingerprint);
  1245.  
  1246. class NetworkNodeTracker:
  1247.     public Constellation::Dir::Notification,
  1248.     public NetClientServiceListReceiver,
  1249.     public boost::enable_shared_from_this<NetworkNodeTracker>
  1250. {
  1251. public:
  1252.     Settings node_dir;
  1253.  
  1254.     boost::mutex stat_tracker_mutex;
  1255.      boost::shared_ptr<NetworkStatNodeTracker> stat_tracker;
  1256.  
  1257.     boost::mutex fingerprint_mutex;
  1258.      std::string fingerprint;
  1259.     bool fingerprint_from_cc;
  1260.  
  1261.     std::string username;
  1262.     std::string password;
  1263.     std::string name;
  1264.     std::string actual_name;
  1265.     std::string cloud_id;
  1266.     int economy_mode;
  1267.     int requested_recurse_level;
  1268.     int port_rpc;
  1269.     int port_video;
  1270.  
  1271.     int use_cloud_connect;
  1272.     int use_connection_via_cloud;
  1273.     int should_be_connected;
  1274.     bool started_session;
  1275.     std::string started_session_ip;
  1276.     int started_session_port;
  1277.     int64_t started_session_id;
  1278.     bool hashed_password_only;
  1279.     bool autocredentials;
  1280.     bool cloud_login;
  1281.     bool try_get_address_from_cc;
  1282.     std::string origin_account;
  1283.  
  1284.     int disable_mainstream;
  1285.     int buffering;
  1286.     int connected_state;
  1287.  
  1288.     bool bad_username;
  1289.  
  1290.     std::string server_path;
  1291.     std::list< boost::weak_ptr<class TierServer> > recursively_created_servers;
  1292.  
  1293.     std::string remoteserver_whitelist;
  1294.  
  1295.     NetworkNodeTracker(const Settings& node_dir_):
  1296.         Constellation::Dir::Notification("NetworkNodeTracker"),
  1297.         node_dir(node_dir_),
  1298.         use_cloud_connect(0),
  1299.         use_connection_via_cloud(0),
  1300.         should_be_connected(0),
  1301.         started_session_id(0),
  1302.         started_session(false),
  1303.         bad_username(false),
  1304.         economy_mode(0),
  1305.         requested_recurse_level(-1),
  1306.         port_rpc(0),
  1307.         port_video(0),
  1308.         connected_state(0),
  1309.         autocredentials(false),
  1310.         cloud_login(false),
  1311.         try_get_address_from_cc(false),
  1312.         root_server_dir_dont_want(false),
  1313.         fingerprint_from_cc(false)
  1314.     {
  1315.         update_node_health(0);
  1316.         hashed_password_only = true;
  1317.     }
  1318.  
  1319.     ~NetworkNodeTracker()
  1320.     {
  1321.         disconnect();
  1322.         if (should_be_connected && node_dir->prototype_name() != "NetworkNodeVirtual") {
  1323.             decrement_should_be_connected_counter();
  1324.             update_node_health(0);
  1325.         }
  1326.     }
  1327.  
  1328.     void disconnect()
  1329.     {
  1330.         if (!started_session) return;
  1331.  
  1332.         started_session = false;
  1333.  
  1334.         if (1 == use_cloud_connect)
  1335.             cloud_disconnect(extract_cloud_id(cloud_id));
  1336.  
  1337.         if (0 != started_session_id) {
  1338.             clientrm->client_session_stop(started_session_id);
  1339.             started_session_id = 0;
  1340.         }
  1341.  
  1342.         boost::shared_ptr<NetworkStatNodeTracker> tmp;
  1343.         {
  1344.             boost::mutex::scoped_lock lock(stat_tracker_mutex);
  1345.             tmp.swap(stat_tracker);
  1346.         }
  1347.  
  1348.         update_node_icon(node_dir, 0);
  1349.     }
  1350.  
  1351.     static std::string extract_cloud_id(const std::string input_string)
  1352.     {
  1353.         std::string result_str = input_string;
  1354.  
  1355.         const size_t spos = input_string.find('/');
  1356.         if (std::string::npos == spos)
  1357.             return result_str;
  1358.  
  1359.         return input_string.substr(spos + 1);
  1360.     }
  1361.  
  1362.     static std::string extract_cloud_authorization_token(const std::string& input_string)
  1363.     {
  1364.         std::string result_str;
  1365.  
  1366.         const size_t spos = input_string.find('/');
  1367.         if (std::string::npos == spos)
  1368.             return result_str;
  1369.  
  1370.         return input_string.substr(0, spos);
  1371.     }
  1372.  
  1373.     void connect_or_not()
  1374.     {
  1375.         node_dir->assert_notify_thread();
  1376.         bool is_virtual_node = (node_dir->prototype_name() == "NetworkNodeVirtual");
  1377.  
  1378.         std::string cl_sid;
  1379.         bool webview = !tech1->have_client() && !tech1->have_server();
  1380.  
  1381.         std::string new_username, new_password;
  1382.         std::string new_name;
  1383.         std::string new_cloud_id;
  1384.         std::string last_ip_address;
  1385.         std::string new_fingerprint;
  1386.         std::string new_origin_account;
  1387.         int new_use_cloud_connect;
  1388.         int new_port_rpc;
  1389.         int new_port_video;
  1390.         int should_be;
  1391.         uint64_t last_cc_timestamp;
  1392.         int address_from_cc_success;
  1393.         int new_economy_mode;
  1394.         int new_recurse_level;
  1395.         int new_relay_count;
  1396.         int new_disable_mainstream;
  1397.         int new_buffering;
  1398.         bool new_autocredentials;
  1399.         Settings node_stat;
  1400.  
  1401.         Json::Value account = tech1->redir_want_client_primary(0, false);
  1402.  
  1403.         bool remove_stats = false;
  1404.         {
  1405.             SettingsLock lock(node_dir);
  1406.             new_use_cloud_connect = node_dir->get_value_integer("use_cloud_connect");
  1407.             new_name = node_dir->get_value_string("name");
  1408.             new_cloud_id = node_dir->get_value_string("cloud_id");
  1409.             last_ip_address = node_dir->get_value_string("ip_address");
  1410.             new_port_rpc = node_dir->get_value_integer("port_rpc");
  1411.             new_port_video = node_dir->get_value_integer("port_video");
  1412.             new_autocredentials = !!node_dir->get_value_integer("autocredentials");
  1413.             if (!new_autocredentials) {
  1414.                 new_username = node_dir->get_value_string("username");
  1415.                 new_password = node_dir->get_value_string("password");
  1416.             }
  1417.             new_economy_mode = node_dir->get_value_integer("economy_mode");
  1418.             new_recurse_level = node_dir->get_value_integer("network_recurse_level");
  1419.             new_relay_count = node_dir->get_value_integer("relay_count");
  1420.             new_disable_mainstream = node_dir->get_value_integer("disable_mainstream");
  1421.             new_buffering = node_dir->get_value_integer("buffering");
  1422.             should_be = node_dir->get_value_integer("should_be_connected");
  1423.             new_fingerprint = node_dir->get_value_string("accepted_fingerprint");
  1424.             last_cc_timestamp = scan_uint64(node_dir->get_value_string("last_cc_timestamp"));
  1425.             address_from_cc_success = node_dir->get_value_integer("address_from_cc_success");
  1426.             hashed_password_only = !!node_dir->get_value_integer("generated");
  1427.             new_origin_account = node_dir->get_value_string("origin_account");
  1428.  
  1429.             cl_sid = account["client_sid"].asString();
  1430.  
  1431.             Settings s = node_dir->dir_find("stats", false);
  1432.  
  1433.             if (1 == should_be) {
  1434.                 if (!s) node_dir->dir_create("stats", NetworkNodeStats);
  1435.             } else if (s) {
  1436.                 remove_stats = true;
  1437.             }
  1438.  
  1439.             node_stat = node_dir->dir_find("stats", false);
  1440.         }
  1441.  
  1442.         std::string cloud_login_user, cloud_login_password;
  1443.         bool new_cloud_login;
  1444.         if (webview && !cl_sid.empty()) {
  1445.             SettingsLock lock(cloudfolder);
  1446.             cloud_login_user = cloudfolder->get_value_string("import_username");
  1447.             cloud_login_password = account["client_sid"].asString();
  1448.             new_cloud_login = true;
  1449.         } else {
  1450.             new_cloud_login = autodetect_user(&cloud_login_user, &cloud_login_password);
  1451.         }
  1452.  
  1453.         if (new_autocredentials) {
  1454.             new_username = cloud_login_user;
  1455.             new_password = cloud_login_password;
  1456.         }
  1457.  
  1458.         started_session_ip = last_ip_address;
  1459.  
  1460.         std::string address = extract_address_from_name(new_name);
  1461.         if (!address.empty()) new_name = address;
  1462.  
  1463.         const bool name_changed = (new_name != name);
  1464.         if (!new_use_cloud_connect && name_changed)
  1465.         {
  1466.             {
  1467.                 SettingsLock lock(node_dir);
  1468.                 node_dir->set_value_string("ip_address", "");
  1469.                 last_ip_address.clear();
  1470.  
  1471.                 try_get_address_from_cc = false;
  1472.                 node_dir->set_value_integer("address_from_cc_success", 0);
  1473.             }
  1474.             started_session_ip.clear();
  1475.         }
  1476.  
  1477.         const bool cloud_id_changed = new_use_cloud_connect &&
  1478.             cloud_id!=new_cloud_id && extract_address_from_name(new_name)!=new_cloud_id;
  1479.         if (cloud_id_changed) {
  1480.             SettingsLock lock(node_dir);
  1481.             node_dir->set_value_string("name", new_cloud_id);
  1482.             new_name = new_cloud_id;
  1483.         }
  1484.  
  1485.         bool something_changed =
  1486.             name_changed ||
  1487.             cloud_id != new_cloud_id ||
  1488.             new_use_cloud_connect != use_cloud_connect ||
  1489.             new_username != username ||
  1490.             new_password != password ||
  1491.             new_port_rpc != port_rpc ||
  1492.             new_port_video != port_video ||
  1493.             new_economy_mode != economy_mode ||
  1494.             new_recurse_level != requested_recurse_level ||
  1495.             new_relay_count != requested_relay_count || // wtf?
  1496.             new_disable_mainstream != disable_mainstream ||
  1497.             new_buffering != buffering ||
  1498.             new_autocredentials != autocredentials ||
  1499.             cloud_login != new_cloud_login;
  1500.  
  1501.         {
  1502.             boost::mutex::scoped_lock slock(fingerprint_mutex);
  1503.             something_changed |= (new_fingerprint != fingerprint);
  1504.             fingerprint = new_fingerprint;
  1505.         }
  1506.  
  1507.         if (something_changed) {
  1508.             bad_username = false;
  1509.             disconnect();
  1510.         }
  1511.  
  1512.         if (new_autocredentials && new_username.empty()) {
  1513.             login_error("local user doesn't use Cloud Login");
  1514.         }
  1515.  
  1516.         name = new_name;
  1517.         cloud_id = new_cloud_id;
  1518.         username = new_username;
  1519.         password = new_password;
  1520.         use_cloud_connect = new_use_cloud_connect;
  1521.         port_rpc = new_port_rpc;
  1522.         port_video = new_port_video;
  1523.         economy_mode = new_economy_mode;
  1524.         requested_recurse_level = new_recurse_level;
  1525.         disable_mainstream = new_disable_mainstream;
  1526.         buffering = new_buffering;
  1527.         autocredentials = new_autocredentials;
  1528.         cloud_login = new_cloud_login;
  1529.         origin_account = new_origin_account;
  1530.  
  1531.         if (!should_be) {
  1532.             bad_username = false; // reset 'bad' state if disabled
  1533.         }
  1534.  
  1535.         if (should_be_connected != should_be) {
  1536.             should_be_connected = should_be;
  1537.             if (!is_virtual_node) {
  1538.                 if (should_be_connected) {
  1539.                     increment_should_be_connected_counter();
  1540.                 } else {
  1541.                     decrement_should_be_connected_counter();
  1542.                     update_node_health(0);
  1543.                 }
  1544.             } else if (!should_be_connected) {
  1545.                     update_node_health(0);
  1546.             }
  1547.         }
  1548.  
  1549.         if (!started_session && should_be && !bad_username) {
  1550.             {
  1551.                 boost::mutex::scoped_lock lock(root_server_dir_mutex);
  1552.                 root_server_dir_dont_want = false;
  1553.             }
  1554.  
  1555.             bool use_cc_workaround = false;
  1556.             std::string last_error;
  1557.             {
  1558.                 SettingsLock lock(node_stat);
  1559.                 last_error = node_stat->get_value_string("last_error");
  1560.                 node_stat->set_value_string("last_error", "");
  1561.                 node_stat->set_value_string("resolve_warning", "");
  1562.                 node_stat->set_value_string("connected_using", "");
  1563.             }
  1564.  
  1565.             uint64_t now_ts = now();
  1566.             uint64_t cc_delay = 5*60*1000000ULL;
  1567.             use_cc_workaround = !last_ip_address.empty() && last_error.find("401")==std::string::npos &&
  1568.                 address_from_cc_success && !cloud_id_changed &&
  1569.                 (last_cc_timestamp > now_ts-cc_delay || last_error.find("434")!=std::string::npos || last_error.find("408")!=std::string::npos);
  1570.  
  1571.             if (use_cloud_connect && !use_cc_workaround) {
  1572.                 assert(0 == started_session_id);
  1573.  
  1574.                 const std::string extracted_cloud_id = extract_cloud_id(cloud_id);
  1575.                 //const std::string cloud_authorization_token = extract_cloud_authorization_token(cloud_id);
  1576.  
  1577.                 try {
  1578.                     //if (cloud_authorization_token.empty())
  1579.                     //  throw std::runtime_error("cloud login and password cannot be empty");
  1580.  
  1581.                     // Better to do this inside CC, have 3 methods to autorize:
  1582.                     //  - sid
  1583.                     //  - tsid
  1584.                     //  - account_name+password_current
  1585.                     //cloud_authorization_token = tech1->redir_want_client_sid();
  1586.  
  1587.                     if (extracted_cloud_id.empty())
  1588.                         throw std::runtime_error("cloud id is empty");
  1589.  
  1590.                     if (origin_account.empty())
  1591.                         throw std::runtime_error("account is empty");
  1592.  
  1593.                     if (tech1->cloud_license_id() == extracted_cloud_id || tech1->server_guid() == extracted_cloud_id)
  1594.                         throw std::runtime_error("connection to self is not allowed");
  1595.  
  1596.                     started_session_id = 0;
  1597.                     try_get_address_from_cc = !address_from_cc_success && !try_get_address_from_cc;
  1598.  
  1599.                     fingerprint_from_cc = false;
  1600.  
  1601.                     boost::shared_ptr<CloudConnectRequest> request(
  1602.                         new CloudConnectRequest);
  1603.                     request->server_id = extracted_cloud_id;
  1604.                     request->account = origin_account;
  1605.                     request->description = RPC_DESCRIPTION;
  1606.                     request->on_success = boost::bind(&cloud_connect_on_success,
  1607.                         boost::weak_ptr<NetworkNodeTracker>(shared_from_this()), _1);
  1608.                     request->on_info = boost::bind(&cloud_connect_on_info,
  1609.                         boost::weak_ptr<NetworkNodeTracker>(shared_from_this()), _1);
  1610.                     client_cloud_connect(request);
  1611.  
  1612.                     try_get_address_from_cc = !try_get_address_from_cc;
  1613.                     started_session = true;
  1614.                     started_session_port = 0;
  1615.                     use_connection_via_cloud = 1;
  1616.  
  1617.                     {
  1618.                         SettingsLock lock(node_dir);
  1619.                         node_dir->set_value_string("last_cc_timestamp", print_uint64(now_ts));
  1620.                     }
  1621.                 } catch (const std::logic_error& e) {
  1622.                     log_warning("NETCLIENT: cloud_connect: %s\n", e.what());
  1623.  
  1624.                     {
  1625.                         SettingsLock lock(node_stat);
  1626.                         node_stat->set_value_string("last_error", e.what());
  1627.                     }
  1628.                     update_node_health(0);
  1629.                     bad_username = true;
  1630.                     return;
  1631.                 }
  1632.             } else {
  1633.                 try {
  1634.                     if (name.empty())
  1635.                         throw std::runtime_error("address is empty");
  1636.  
  1637.                     update_node_health(0); // not connected yet
  1638.  
  1639.                     actual_name = use_cloud_connect ? last_ip_address : name;
  1640.  
  1641.                     Rpc::Callbacks callbacks(
  1642.                         check_cert,
  1643.                         socket_error_callback,
  1644.                         NULL,
  1645.                         update_node_ip_callback
  1646.                         );
  1647.  
  1648.                     started_session_id = clientrm->client_session_start(
  1649.                         actual_name,
  1650.                         port_rpc,
  1651.                         last_ip_address,
  1652.                         callbacks
  1653.                         );
  1654.                     started_session = true;
  1655.                     started_session_port = port_rpc;
  1656.                     use_connection_via_cloud = 0;
  1657.  
  1658.                 } catch (const std::logic_error& e) {
  1659.                     // duplicate address
  1660.                     {
  1661.                         SettingsLock lock(node_stat);
  1662.                         node_stat->set_value_string("last_error", e.what());
  1663.                     }
  1664.                     update_node_health(0);
  1665.                     bad_username = true;
  1666.                     return;
  1667.                 }
  1668.             }
  1669.         }
  1670.  
  1671.         if (started_session && !should_be_connected) {
  1672.             disconnect();
  1673.             update_node_health(0);
  1674.         }
  1675.  
  1676.         boost::shared_ptr<NetworkStatNodeTracker> tmp;
  1677.         if (remove_stats) {
  1678.             {
  1679.                 SettingsLock lock(node_dir);
  1680.                 node_dir->dir_remove("stats");
  1681.             }
  1682.             {
  1683.                 boost::mutex::scoped_lock lock(stat_tracker_mutex);
  1684.                 tmp.swap(stat_tracker);
  1685.             }
  1686.         }
  1687.     }
  1688.  
  1689.     void constellation_values_changed(const Settings& tracked_dir)
  1690.     {
  1691.         connect_or_not();
  1692.     }
  1693.  
  1694.     void constellation_folder_added(const boost::shared_ptr<Dir> &tracked_dir, const boost::shared_ptr<Dir> &new_folder)
  1695.     {
  1696.         if (new_folder->name() == "stats") {
  1697.             boost::shared_ptr<NetworkStatNodeTracker> tmp;
  1698.             tmp.reset(new NetworkStatNodeTracker(new_folder, shared_from_this()));
  1699.             {
  1700.                 SettingsLock lock(new_folder);
  1701.                 new_folder->add_notification(tmp, Dir::FIRE_VALUE_NOTIFICATION_NOW);
  1702.             }
  1703.             {
  1704.                 boost::mutex::scoped_lock lock(stat_tracker_mutex);
  1705.                 tmp.swap(stat_tracker);
  1706.             }
  1707.         }
  1708.     }
  1709.  
  1710.     // called from welcome server message below
  1711.     void connected_successfully(
  1712.         const std::string& server_guid,
  1713.         const boost::shared_ptr<NetServerWelcome>& remote_welcome,
  1714.         uint64_t salt)
  1715.     {
  1716.         // socket thread
  1717.         Settings node_stat = node_dir->cd("stats", false);
  1718.  
  1719.         int v = remote_welcome->interface_version();
  1720.         if(node_stat)
  1721.         {
  1722.             SettingsLock lock(node_stat);
  1723.             node_stat->set_value_string("last_error", "");
  1724.         }
  1725.         update_node_health(1);
  1726.  
  1727.         log("NETCLIENT: connection to %s:%i, user '%s', recurse %i, remote version %i\n",
  1728.             name.c_str(), port_rpc, username.c_str(), requested_recurse_level,
  1729.             v);
  1730.         if (!hashed_password_only && v<=100) {
  1731.             remote_welcome->network_login(
  1732.                 username,
  1733.                 password,
  1734.                 "Trassir-3.0",
  1735.                 shared_from_this(),
  1736.                 !!economy_mode,
  1737.                 requested_recurse_level);
  1738.  
  1739.         } else { // Trassir 3.3
  1740.             if (salt==0) {
  1741.                 log_warning("LOGIN: zero salt, will do nothing\n");
  1742.                 return;
  1743.             }
  1744.  
  1745.             std::vector<uint8_t> pass_hash = expensive_password_hash(salt, password);
  1746.  
  1747.             std::string pwd;
  1748.             if (!autocredentials) {
  1749.                 pwd += "SALTED ";
  1750.                 for (std::vector<uint8_t>::iterator x=pass_hash.begin(); x!=pass_hash.end(); x++)
  1751.                     pwd += stdprintf("%02x", (int) *x);
  1752.                 pwd += "\n";
  1753.             } else {
  1754.                 Json::Value acc = tech1->redir_want_client_primary(0, false);
  1755.                 if (!acc.isMember("account")) throw std::logic_error("no 'account'");
  1756.                 std::vector<uint8_t> sid_hash = expensive_password_hash(salt, acc["account"].asString() );
  1757.                 if (!sid_hash.size())
  1758.                     log_warning("NETCLIENT: cloud client sid empty\n");
  1759.                 pwd += "CLOUDSID ";
  1760.                 for (std::vector<uint8_t>::iterator x=sid_hash.begin(); x!=sid_hash.end(); x++)
  1761.                     pwd += stdprintf("%02x", (int) *x);
  1762.                 pwd += "\n";
  1763.  
  1764.                 std::string offline_password;
  1765.                 {
  1766.                     SettingsLock lock(network_folder);
  1767.                     std::list<PasswordData> lst = string_to_password_data_list(network_folder->get_value_string("offline_passwords"));
  1768.                     std::list<PasswordData>::iterator x;
  1769.                     uint64_t ts_now = now();
  1770.                     for (x=lst.begin(); x!=lst.end();) {
  1771.                         if (ts_now - x->last_successful_login_ts > 28*24*60*60*1000000ULL) {
  1772.                             x = lst.erase(x);
  1773.                             continue;
  1774.                         }
  1775.                         if (cloud_id == x->server_guid)
  1776.                             offline_password = x->offline_password;
  1777.                         ++x;
  1778.                     }
  1779.                 }
  1780.  
  1781.                 pwd += stdprintf("OFFLINE %s\n", offline_password.c_str()); // for offline generated password
  1782.             }
  1783.  
  1784.             log_timestamp("LOGIN: sending username=%s, password='%s'\n", username.c_str(), pwd.c_str());
  1785.             remote_welcome->network_login(
  1786.                 username,
  1787.                 pwd,
  1788.                 "Trassir-3.0",
  1789.                 shared_from_this(),
  1790.                 !!economy_mode,
  1791.                 requested_recurse_level);
  1792.         }
  1793.     }
  1794.  
  1795.     void add_server(
  1796.         const std::string& server_guid,
  1797.         const std::string& server_name,
  1798.         const std::string& server_media_route,
  1799.         const boost::shared_ptr<NetServerDir>& server_dir,
  1800.         int recurse_level);
  1801.  
  1802.     boost::mutex root_server_dir_mutex;
  1803.      boost::shared_ptr<NetServerDir> root_server_dir;
  1804.      bool root_server_dir_dont_want;
  1805.  
  1806.     void keep_reference_on_root_folder(const boost::shared_ptr<NetServerDir>& sd)
  1807.     {
  1808.         boost::mutex::scoped_lock lock(root_server_dir_mutex);
  1809.         if (root_server_dir_dont_want) return;
  1810.         root_server_dir = sd;
  1811.     }
  1812.  
  1813.     // from network (NetClientServiceListReceiver)
  1814.     void login_error(const std::string& message)
  1815.     {
  1816.         log("NETCLIENT: login error: %s\n", message.c_str());
  1817.         bad_username = true;
  1818.         Settings node_stats = node_dir->cd("stats", false);
  1819.         if(node_stats) {
  1820.             SettingsLock lock(node_stats);
  1821.             node_stats->set_value_string("last_error", message);
  1822.         }
  1823.  
  1824.         update_node_health(0);
  1825.     }
  1826.  
  1827.     // user has deleted node, must disconnect, it will not happen automatically since
  1828.     // this object referenced though network as NetClientServiceListReceiver
  1829.     void constellation_tracked_dir_erased(
  1830.         const boost::shared_ptr<Dir>& tracked_dir)
  1831.     {
  1832.         boost::mutex::scoped_lock lock(root_server_dir_mutex);
  1833.         root_server_dir_dont_want = true;
  1834.         root_server_dir.reset();
  1835.     }
  1836.  
  1837.     // from network (NetClientServiceListReceiver)
  1838.     void on_disconnect()
  1839.     {
  1840.         boost::mutex::scoped_lock lock(root_server_dir_mutex);
  1841.         root_server_dir_dont_want = true;
  1842.         root_server_dir.reset();
  1843.     }
  1844.  
  1845.     void update_node_health(int new_connected)
  1846.     {
  1847.         const std::string& node_guid = node_dir->name();
  1848.         std::string username;
  1849.         std::string node_name;
  1850.         Settings node_stats;
  1851.         {
  1852.             SettingsLock nlock(node_dir);
  1853.             node_name = node_dir->get_value_string("name");
  1854.             username = node_dir->get_value_string("username");
  1855.             node_stats = node_dir->dir_find("stats", false);
  1856.         }
  1857.  
  1858.         std::string node_last_error;
  1859.  
  1860.         boost::mutex::scoped_lock lock(health_defender);
  1861.  
  1862.         if (node_stats)
  1863.         {
  1864.             SettingsLock slock(node_stats);
  1865.             node_last_error = node_stats->get_value_string("last_error");
  1866.             connected_state = node_stats->get_value_integer("connected");
  1867.             node_stats->set_value_integer("connected", new_connected);
  1868.         }
  1869.  
  1870.         if( node_dir->prototype_name() != "NetworkNodeVirtual" ) {
  1871.             if (connected_state==0 && new_connected==1) {
  1872.                 ++health_connected_counter;
  1873. #ifdef T1_SERVER
  1874.                 boost::shared_ptr<ServerObject> so = tech1->serverobject();
  1875.                 if (so)
  1876.                     tech1->fire_event(so, &event_connected_to, node_name, username, "");
  1877. #endif
  1878.             }
  1879.             if (connected_state==1 && new_connected==0) {
  1880.                 --health_connected_counter;
  1881. #ifdef T1_SERVER
  1882.                 boost::shared_ptr<ServerObject> so = tech1->serverobject();
  1883.                 if (so)
  1884.                     tech1->fire_event(so, &event_disconnected_from, node_name, "", "");
  1885. #endif
  1886.             }
  1887.  
  1888.             connected_state = new_connected;
  1889.  
  1890.             update_global_health(!new_connected, node_guid, node_last_error);
  1891.         }
  1892.         update_node_icon(node_dir, new_connected);
  1893.     }
  1894.  
  1895.     void update_offline_password(const std::string& new_password)
  1896.     {
  1897.         uint64_t now_ts = now();
  1898.         SettingsLock lock(network_folder);
  1899.         std::list<PasswordData> offline_passwords = string_to_password_data_list(
  1900.             network_folder->get_value_string("offline_passwords") );
  1901.         std::list<PasswordData>::iterator x;
  1902.         bool add_new = true;
  1903.         for (x=offline_passwords.begin(); x!=offline_passwords.end(); ++x) {
  1904.             if (x->server_guid == cloud_id) {
  1905.                 x->offline_password = new_password;
  1906.                 x->last_successful_login_ts = now_ts;
  1907.                 add_new = false;
  1908.                 break;
  1909.             }
  1910.         }
  1911.         if (add_new)
  1912.             offline_passwords.push_back( PasswordData(cloud_id, new_password, now_ts) );
  1913.  
  1914.         network_folder->set_value_string("offline_passwords",
  1915.             password_data_list_to_string(offline_passwords));
  1916.     }
  1917.  
  1918.     void whitelist_send(const std::string& server_guid, const std::string& whitelist)
  1919.     {
  1920.         remoteserver_whitelist = whitelist;
  1921.         log_timestamp("NETCLIENT: for RemoteServer '%s' got whitelist: '%s'\n", server_guid.c_str(), whitelist.c_str());
  1922.     }
  1923.  
  1924. private:
  1925.     void increment_should_be_connected_counter()
  1926.     {
  1927.         boost::mutex::scoped_lock lock(health_defender);
  1928.         ++health_should_be_counter;
  1929.         update_global_health(false, "", "");
  1930.     }
  1931.  
  1932.     void decrement_should_be_connected_counter()
  1933.     {
  1934.         boost::mutex::scoped_lock lock(health_defender);
  1935.         --health_should_be_counter;
  1936.         assert(health_should_be_counter >= 0);
  1937.         update_global_health(0, "", "");
  1938.     }
  1939.  
  1940.     static
  1941.     void cloud_connect_on_success(const boost::weak_ptr<NetworkNodeTracker>& weak,
  1942.         const boost::shared_ptr<CloudConnectSocket>& cc_socket)
  1943.     {
  1944.         boost::shared_ptr<NetworkNodeTracker> tracker = weak.lock();
  1945.         if (!tracker) {
  1946.             log_warning("NETSERVER: cloud_connect_on_success, node tracker not found!\n");
  1947.             cc_socket->close_callback();
  1948.             return;
  1949.         }
  1950.  
  1951.         Rpc::Callbacks callbacks;
  1952.         callbacks.error_callback = socket_error_callback;
  1953.         callbacks.update_node_address_callback = update_node_address_callback;
  1954.         if (tracker->fingerprint_from_cc)
  1955.             callbacks.check_cert_fingerprint = check_cert;
  1956.         tracker->started_session_id = rpc_inject_socket(cc_socket, callbacks);
  1957.     }
  1958.  
  1959.     static
  1960.     void cloud_connect_on_info(const boost::weak_ptr<NetworkNodeTracker>& weak,
  1961.         const std::string& json_info)
  1962.     {
  1963.         boost::shared_ptr<NetworkNodeTracker> tracker = weak.lock();
  1964.         if (!tracker) {
  1965.             log_warning("NETSERVER: cloud_connect_on_info, node tracker not found!\n");
  1966.             return;
  1967.         }
  1968.  
  1969.         std::string ssl_fingerprint;
  1970.         try {
  1971.             Json::Value v = json_parse_or_die(json_info, true);
  1972.             ssl_fingerprint = json_value_require(v, "ssl_fingerprint", Json::stringValue).asString();
  1973.         } catch (const std::exception& /*e*/) {
  1974.             log_timestamp("NETSERVER: fingerprint is missing for %s\n",
  1975.                     extract_cloud_id(tracker->cloud_id).c_str()
  1976.                     );
  1977.             return;
  1978.         }
  1979.  
  1980.         if (!ssl_fingerprint.empty()) {
  1981.             {
  1982.                 boost::mutex::scoped_lock lock(tracker->fingerprint_mutex);
  1983.                 tracker->fingerprint = ssl_fingerprint;
  1984.             }
  1985.             {
  1986.                 SettingsLock lock(tracker->node_dir);
  1987.                 tracker->node_dir->set_value_string("accepted_fingerprint", ssl_fingerprint);
  1988.             }
  1989.             tracker->fingerprint_from_cc = true;
  1990.         }
  1991.     }
  1992.  
  1993. };
  1994.  
  1995. static const char* AMERGE_SESSION_NODE = "vtrassir_amerge";
  1996.  
  1997. class AmergeRpcSession
  1998.     : public NetClientServiceListReceiver
  1999.     , public NetClientDir
  2000.     , public boost::enable_shared_from_this<AmergeRpcSession>
  2001. {
  2002. public:
  2003.     int64_t rpc_session_id;
  2004.  
  2005.     boost::mutex dirs_mutex;
  2006.      boost::shared_ptr<NetServerDir> root_server_dir;
  2007.      Settings remote_server_dir;
  2008.  
  2009.     AmergeRpcSession()
  2010.         : rpc_session_id(0)
  2011.     {}
  2012.  
  2013.     ~AmergeRpcSession()
  2014.     {
  2015.         disconnect();
  2016.     }
  2017.  
  2018.     void connect()
  2019.     {
  2020.         boost::shared_ptr<CloudConnectRequest> request(
  2021.             new CloudConnectRequest);
  2022.         request->server_id = "vtrassir";
  2023.         request->description = RPC_DESCRIPTION;
  2024.         request->on_success = boost::bind(&cloud_connect_on_success,
  2025.             boost::weak_ptr<AmergeRpcSession>(shared_from_this()), _1);
  2026.         client_cloud_connect(request);
  2027.     }
  2028.  
  2029.     void disconnect()
  2030.     {
  2031.         cloud_disconnect("vtrassir");
  2032.         if (rpc_session_id != 0 && clientrm)
  2033.             clientrm->client_session_stop(rpc_session_id);
  2034.         rpc_session_id = 0;
  2035.     }
  2036.  
  2037.     void connected_successfully(
  2038.         const boost::shared_ptr<NetServerWelcome>& remote_welcome)
  2039.     {
  2040.         remote_welcome->network_login(
  2041.             "AmergeServiceUser",
  2042.             "",
  2043.             "Trassir-3.0",
  2044.             shared_from_this(),
  2045.             false,
  2046.             1);
  2047.     }
  2048.  
  2049.     void login_error(const std::string& message)
  2050.     {
  2051.         log("NETCLIENT: amerge login error: %s\n", message.c_str());
  2052.         //TODO: reconnect ???
  2053.     }
  2054.  
  2055.     void keep_reference_on_root_folder(const boost::shared_ptr<NetServerDir>& sd)
  2056.     {
  2057.         boost::mutex::scoped_lock lock(dirs_mutex);
  2058.         root_server_dir = sd;
  2059.     }
  2060.  
  2061.     void add_server(
  2062.         const std::string& server_guid,
  2063.         const std::string& server_name,
  2064.         const std::string& server_media_route,
  2065.         const boost::shared_ptr<NetServerDir>& root_server_dir,
  2066.         int recurse_level)
  2067.     {
  2068.         Settings new_remote_server_dir;
  2069.         {
  2070.             SettingsLock lock(root_under_admin);
  2071.             new_remote_server_dir = root_under_admin->dir_create(
  2072.                 server_guid + "_amerge",
  2073.                 tech1->common_prototypes()->HiddenServer
  2074.                 ); // exception if bad guid
  2075.         }
  2076.         {
  2077.             SettingsLock lock(new_remote_server_dir);
  2078.             new_remote_server_dir->set_value_string("media_route", "/asio:ip=vtrassir:port=0");
  2079.         }
  2080.         {
  2081.             boost::mutex::scoped_lock lock(dirs_mutex);
  2082.             remote_server_dir = new_remote_server_dir;
  2083.         }
  2084.  
  2085.         root_server_dir->pass_dir_receiver(shared_from_this());
  2086.         root_server_dir->client2server_start_work();
  2087.     }
  2088.  
  2089.     void update_offline_password(const std::string& new_password) {}
  2090.     void whitelist_send(const std::string&,const std::string&) {}
  2091.  
  2092.     void update_values(int rev, const std::string& s)
  2093.     {
  2094.         Settings server_dir;
  2095.         {
  2096.             boost::mutex::scoped_lock lock(dirs_mutex);
  2097.             server_dir = remote_server_dir;
  2098.         }
  2099.         if (server_dir) {
  2100.             SettingsLock lock(server_dir);
  2101.             server_dir->network_unserialize_server2client_values(1000+rev, s, false, false);
  2102.         }
  2103.     }
  2104.  
  2105.     void update_effective_rights(uint32_t) {}
  2106.  
  2107.     void add_folder(
  2108.         const std::string& folder_name,
  2109.         const std::string& prototype,
  2110.         const boost::shared_ptr<NetServerDir>& server_dir,
  2111.         uint32_t rights,
  2112.         int recurse_level)
  2113.     {
  2114.     }
  2115.  
  2116.     void remove_folder(const std::string& folder_name) {}
  2117.     void initial_add_completed() {}
  2118.  
  2119.     void add_service(const boost::shared_ptr<Interface>& service)
  2120.     {
  2121.         if (!service) {
  2122.             log("AMERGE_SESSION: add_service() ERROR (1)\n");
  2123.             return;
  2124.         }
  2125.  
  2126.         Settings server_dir;
  2127.         {
  2128.             boost::mutex::scoped_lock lock(dirs_mutex);
  2129.             server_dir = remote_server_dir;
  2130.         }
  2131.         if (server_dir) {
  2132.             const std::string& key = stdprintf("%s@%s", service->interface_name(), server_dir->name().c_str());
  2133.             netclient_found_remote_service(key, server_dir, service);
  2134.         }
  2135.     }
  2136.  
  2137.     void remove_service(const boost::shared_ptr<Interface>& service)
  2138.     {
  2139.         if (!service) {
  2140.             log_warning("AMERGE_SESSION: remove_service ERROR (1)\n");
  2141.             return;
  2142.         }
  2143.         remove_service_v2(service->interface_name());
  2144.     }
  2145.  
  2146.     void remove_service_v2(const std::string& sname)
  2147.     {
  2148.         Settings server_dir;
  2149.         {
  2150.             boost::mutex::scoped_lock lock(dirs_mutex);
  2151.             server_dir = remote_server_dir;
  2152.         }
  2153.         if (server_dir) {
  2154.             std::string key = sname + "@" + server_dir->name();
  2155.             netclient_lost_remote_service(key);
  2156.         }
  2157.     }
  2158.  
  2159.     void on_disconnect()
  2160.     {
  2161.         Settings old_remote_server_dir;
  2162.         boost::shared_ptr<NetServerDir> old_root_server_dir;
  2163.         {
  2164.             boost::mutex::scoped_lock lock(dirs_mutex);
  2165.             remote_server_dir.swap(old_remote_server_dir);
  2166.             root_server_dir.swap(old_root_server_dir);
  2167.         }
  2168.         if (old_remote_server_dir) {
  2169.             netclient_lost_all_services_for_node(old_remote_server_dir);
  2170.             {
  2171.                 SettingsLock lock(root_under_admin);
  2172.                 root_under_admin->dir_remove(old_remote_server_dir->name());
  2173.             }
  2174.         }
  2175.  
  2176.         if (old_root_server_dir)
  2177.             old_root_server_dir->client2server_stop_work();
  2178.     }
  2179.  
  2180. private:
  2181.  
  2182.     static
  2183.     void cloud_connect_on_success(const boost::weak_ptr<AmergeRpcSession>& weak,
  2184.         const boost::shared_ptr<CloudConnectSocket>& cc_socket)
  2185.     {
  2186.         boost::shared_ptr<AmergeRpcSession> session = weak.lock();
  2187.         if (!session) {
  2188.             log_warning("NETSERVER: cloud_connect_on_success, amerge session not found!\n");
  2189.             cc_socket->close_callback();
  2190.             return;
  2191.         }
  2192.  
  2193.         Rpc::Callbacks callbacks;
  2194.         callbacks.error_callback = boost::bind(socket_error_callback,
  2195.             boost::weak_ptr<AmergeRpcSession>(session));
  2196.         session->rpc_session_id = rpc_inject_socket(cc_socket, callbacks);
  2197.     }
  2198.  
  2199.     static
  2200.     void socket_error_callback(const boost::weak_ptr<AmergeRpcSession>& weak)
  2201.     {
  2202.         boost::shared_ptr<AmergeRpcSession> session = weak.lock();
  2203.         if (!session)
  2204.             return;
  2205.         session->disconnect();
  2206.         session->connect();
  2207.     }
  2208. };
  2209.  
  2210. void amerge_connection_enable_disable(bool enable)
  2211. {
  2212.     boost::shared_ptr<AmergeRpcSession> new_session;
  2213.     if (enable) {
  2214.         boost::shared_ptr<AmergeRpcSession> session;
  2215.         {
  2216.             boost::mutex::scoped_lock lock(amerge_session_mutex);
  2217.             session = amerge_session;
  2218.         }
  2219.         if (session)
  2220.             return;
  2221.         new_session.reset(new AmergeRpcSession);
  2222.         new_session->connect();
  2223.     }
  2224.     {
  2225.         boost::mutex::scoped_lock lock(amerge_session_mutex);
  2226.         amerge_session.swap(new_session);
  2227.     }
  2228. }
  2229.  
  2230. NetworkStatNodeTracker::NetworkStatNodeTracker(const Settings& stat_dir_, boost::shared_ptr<NetworkNodeTracker> node_tracker_):
  2231.     Constellation::Dir::Notification("NetworkStatNodeTracker"),
  2232.     stat_dir(stat_dir_),
  2233.     node_tracker(node_tracker_)
  2234. {}
  2235.  
  2236. void NetworkStatNodeTracker::constellation_values_changed(const boost::shared_ptr<Dir> &tracked_dir)
  2237. {
  2238.     std::string new_last_error;
  2239.     {
  2240.         SettingsLock lock(tracked_dir);
  2241.         last_error = tracked_dir->get_value_string("last_error");
  2242.     }
  2243.     boost::shared_ptr<NetworkNodeTracker> tracker = node_tracker.lock();
  2244.     if (tracker && last_error!=new_last_error && !last_error.empty())
  2245.         tracker->constellation_values_changed(tracked_dir->parent());
  2246.     last_error = new_last_error;
  2247. }
  2248.  
  2249. void ClientDirReal::implement_disable_mainstream(
  2250.     const Settings& channel_info_locked,
  2251.     const Settings& unfiltered_channel_info)
  2252. {
  2253.     boost::shared_ptr<NetworkNodeTracker> node = network_node.lock();
  2254.     if (!node) return;
  2255.  
  2256.     int disable_mainstream = node->disable_mainstream;
  2257.     int buffering = node->buffering;
  2258.  
  2259.     std::string vms = unfiltered_channel_info->get_value_string_with_default("address_video_main", "");
  2260.     std::string vss = unfiltered_channel_info->get_value_string_with_default("address_video_ss", "");
  2261.  
  2262.     // Constellation::RIGHTS_SOUND
  2263.     std::string ams = unfiltered_channel_info->get_value_string_with_default("address_audio_main", "");
  2264.     std::string ass = unfiltered_channel_info->get_value_string_with_default("address_audio_ss", "");
  2265.  
  2266.     if (disable_mainstream && !vss.empty()) {
  2267.         channel_info_locked->set_value_string("address_video_main", "");
  2268.         channel_info_locked->set_value_string("address_video_ss",   vss);
  2269.         channel_info_locked->set_value_string("address_audio_main", "");
  2270.         channel_info_locked->set_value_string("address_audio_ss",   ass);
  2271.     } else {
  2272.         channel_info_locked->set_value_string("address_video_main", vms);
  2273.         channel_info_locked->set_value_string("address_video_ss",   vss);
  2274.         channel_info_locked->set_value_string("address_audio_main", ams);
  2275.         channel_info_locked->set_value_string("address_audio_ss",   ass);
  2276.         channel_info_locked->set_value_string("address_audio_ss",   ass);
  2277.     }
  2278.  
  2279.     channel_info_locked->set_value_integer("addrflags",
  2280.         unfiltered_channel_info->get_value_integer_with_default("addrflags", 0));
  2281.     channel_info_locked->set_value_integer("economy_mode",
  2282.         unfiltered_channel_info->get_value_integer_with_default("economy_mode", 0));
  2283.     channel_info_locked->set_value_string("grabber_path",
  2284.         unfiltered_channel_info->get_value_string_with_default("grabber_path", ""));
  2285.     channel_info_locked->set_value_string("address_figures_detector",
  2286.         unfiltered_channel_info->get_value_string_with_default("address_figures_detector", ""));
  2287.     channel_info_locked->set_value_string("address_figures_subtitles",
  2288.         unfiltered_channel_info->get_value_string_with_default("address_figures_subtitles", ""));
  2289.     channel_info_locked->set_value_integer("grabber_channel_n",
  2290.         unfiltered_channel_info->get_value_integer_with_default("grabber_channel_n", 0));
  2291. }
  2292.  
  2293.  
  2294. // tier server
  2295.  
  2296. class TierServer:
  2297.     public ClientDirReal,
  2298.     public ServerProvider
  2299. {
  2300. public:
  2301.     boost::mutex vote_api_mutex;
  2302.     std::string guid;
  2303.     std::string name;
  2304.     std::string media_route;
  2305.     boost::shared_ptr<NetServerDir> server_dir;
  2306.     int recurse_level;
  2307.     std::string through;
  2308.  
  2309.     std::string remoteserver_whitelist;
  2310.  
  2311.     TierServer(
  2312.         const std::string& guid,
  2313.         const std::string& name,
  2314.         const boost::shared_ptr<NetServerDir>& server_dir,
  2315.         const boost::shared_ptr<NetworkNodeTracker>& network_node,
  2316.         const std::string& media_route,
  2317.         const std::string& remoteserver_whitelist,
  2318.         int recurse_level)
  2319.         :
  2320.         ClientDirReal( Settings(), server_dir, network_node ),
  2321.         ServerProvider(recurse_level),
  2322.         guid(guid),
  2323.         name(name),
  2324.         media_route(media_route),
  2325.         server_dir(server_dir),
  2326.         remoteserver_whitelist(remoteserver_whitelist),
  2327.         recurse_level(recurse_level)
  2328.     {
  2329.         i_work_as_tier_server = true;
  2330.         node_dir = network_node->node_dir;
  2331.         //i_work_as_root = true;
  2332.     }
  2333.  
  2334.     ~TierServer()
  2335.     {
  2336.         boost::mutex::scoped_lock lock(vote_api_mutex);
  2337.         provide_server_no_more();
  2338.         remove_me_from_voting_cx();
  2339.     }
  2340.  
  2341.     // called once, after constructor
  2342.     void connected_successfully()
  2343.     {
  2344.         boost::mutex::scoped_lock lock(vote_api_mutex);
  2345.         add_me_to_voting_cx(guid, boost::dynamic_pointer_cast<ServerProvider>(shared_from_this()));
  2346.     }
  2347.  
  2348.     void update_connected_through(const std::string& s)
  2349.     {
  2350.         if(!s.empty())
  2351.         {
  2352.             through = s;
  2353.  
  2354.             if(i_serve_here)
  2355.             {
  2356.                 SettingsLock slock(i_serve_here);
  2357.                 i_serve_here->set_value_string("connected_through", s);
  2358.                 i_serve_here->set_value_string("whitelist", remoteserver_whitelist);
  2359.             }
  2360.         }
  2361.     }
  2362.  
  2363.     // virtual ServerProvider
  2364.     void you_have_won_the_vote()
  2365.     {
  2366.         boost::mutex::scoped_lock lock(vote_api_mutex);
  2367.         bool success = provide_server_start(name, media_route, recurse_level);
  2368.  
  2369.         if (!success) {
  2370.             remove_me_from_voting_cx();
  2371.             return;
  2372.         }
  2373.  
  2374.         boost::mutex::scoped_lock dirs_lock(dirs_mutex);
  2375.         i_serve_here = voting_cx->remote_server;
  2376.  
  2377.         update_connected_through(through);
  2378.  
  2379.         server_dir->client2server_start_work();
  2380.         log("tier: client2server_start_work()\n");
  2381.     }
  2382.  
  2383.     // virtual ServerProvider
  2384.     void you_have_lost_the_vote()
  2385.     {
  2386.         boost::mutex::scoped_lock lock(vote_api_mutex);
  2387.         provide_server_no_more();
  2388.  
  2389.         boost::mutex::scoped_lock dirs_lock(dirs_mutex);
  2390.         i_serve_here.reset();
  2391.         server_dir->client2server_stop_work();
  2392.         log("tier: client2server_stop_work()\n");
  2393.     }
  2394.  
  2395.     // from network (NetClientDir)
  2396.     void add_service(const boost::shared_ptr<Interface>& service)
  2397.     {
  2398.         if (!service) {
  2399.             log("NETCLIENT: add_service() ERROR (1)\n");
  2400.             return;
  2401.         }
  2402.         boost::mutex::scoped_lock dirs_lock(dirs_mutex);
  2403.         if (!i_serve_here) {
  2404.             log("NETCLIENT: remove_service() ERROR (2)\n");
  2405.             return;
  2406.         }
  2407.  
  2408.         const std::string& key = stdprintf("%s@%s", service->interface_name(), guid.c_str());
  2409.         netclient_found_remote_service(key, i_serve_here, service);
  2410.     }
  2411.  
  2412.     // from network (NetClientDir)
  2413.     void remove_service(const boost::shared_ptr<Interface>& service)
  2414.     {
  2415.         if (!service) {
  2416.             log_warning("NETCLIENT: remove_service ERROR (1)\n");
  2417.             return;
  2418.         }
  2419.         remove_service_v2(service->interface_name());
  2420.     }
  2421.  
  2422.     void remove_service_v2(const std::string& sname)
  2423.     {
  2424.         std::string key = sname + "@" + guid;
  2425.         netclient_lost_remote_service(key);
  2426.     }
  2427. };
  2428.  
  2429. void NetworkNodeTracker::add_server(
  2430.     const std::string& server_guid,
  2431.     const std::string& server_name,
  2432.     const std::string& server_media_route,
  2433.     const boost::shared_ptr<NetServerDir>& server_dir,
  2434.     int recurse_level)
  2435. {
  2436.     if (recurse_level<1 || recurse_level>=8) { // 1, 2, 3 ... 7 allowed
  2437.         log("NETCLIENT: add_server() bad recurse level %i\n", recurse_level);
  2438.         return;
  2439.     }
  2440.  
  2441.     const std::string route_to_tier =
  2442.         server_media_route
  2443.         + ((use_cloud_connect && use_connection_via_cloud)
  2444.         ? stdprintf("/asio:ip=%s:port=0", extract_cloud_id(cloud_id).c_str())
  2445.         : stdprintf("/asio:ip=%s:port=%i", extract_address_from_name(actual_name).c_str(), port_video));
  2446.  
  2447.     try {
  2448.         boost::shared_ptr<TierServer> tier_server(new TierServer(
  2449.             server_guid,
  2450.             server_name,
  2451.             server_dir,
  2452.             shared_from_this(),
  2453.             route_to_tier,
  2454.             remoteserver_whitelist,
  2455.             recurse_level
  2456.             ));
  2457.  
  2458.         if(recurse_level == 1) {
  2459.             const std::string& node_path = node_dir->path();
  2460.             server_path = stdprintf("/%s", server_guid.c_str());
  2461.  
  2462.             {
  2463.                 boost::mutex::scoped_lock dirs_lock(tier_server->dirs_mutex);
  2464.                 tier_server->update_connected_through(node_path);
  2465.             }
  2466.  
  2467.             for(std::list< boost::weak_ptr< TierServer > >::iterator iter = recursively_created_servers.begin();
  2468.                 recursively_created_servers.end() != iter; ++iter)
  2469.             {
  2470.                 boost::shared_ptr<TierServer> cur = (*iter).lock();
  2471.                 if(cur)
  2472.                 {
  2473.                     boost::mutex::scoped_lock dirs_lock(cur->dirs_mutex);
  2474.                     cur->update_connected_through(server_path);
  2475.                 }
  2476.             }
  2477.  
  2478.             recursively_created_servers.clear();
  2479.  
  2480.         } else {
  2481.             if (server_path.empty()) {
  2482.                 recursively_created_servers.push_back(tier_server);
  2483.             } else {
  2484.                 boost::mutex::scoped_lock dirs_lock(tier_server->dirs_mutex);
  2485.                 tier_server->update_connected_through(server_path);
  2486.             }
  2487.         }
  2488.  
  2489.         server_dir->pass_dir_receiver(tier_server);
  2490.         tier_server->connected_successfully();
  2491.     } catch (const std::logic_error& e) {
  2492.         // bad server name, etc
  2493.         log("CLIENT: add_server(): %s\n", e.what());
  2494.         return;
  2495.     }
  2496. }
  2497.  
  2498.  
  2499. // network folder tracker
  2500.  
  2501. extern void notify_about_cc_setup_changes(Tech1*);
  2502.  
  2503. class NetworkDirTracker:
  2504.     public Constellation::Dir::Notification
  2505. {
  2506. public:
  2507.     boost::mutex ntrackers_mutex;
  2508.      std::map< std::string, boost::shared_ptr<NetworkNodeTracker> > ntrackers;
  2509.  
  2510.     NetworkDirTracker():
  2511.         Constellation::Dir::Notification("NetworkDirTracker")
  2512.     {
  2513.     }
  2514.  
  2515.     void constellation_folder_added(
  2516.         const Settings& tracked_dir,
  2517.         const Settings& new_folder)
  2518.     {
  2519.         assert(tracked_dir==network_folder);
  2520.         if (new_folder->name()=="network_node_add") return;
  2521.  
  2522.         boost::shared_ptr<NetworkNodeTracker> nt( new NetworkNodeTracker(new_folder) );
  2523.         {
  2524.             boost::mutex::scoped_lock tlock(ntrackers_mutex);
  2525.             ntrackers[new_folder->name()] = nt;
  2526.         }
  2527.         {
  2528.             SettingsLock lock(new_folder);
  2529.             new_folder->add_notification(nt, Constellation::Dir::FIRE_VALUE_NOTIFICATION_NOW|Constellation::Dir::WANT_ADD_REMOVE);
  2530.         }
  2531.     }
  2532.  
  2533.     void constellation_folder_removed(
  2534.         const Settings& tracked_dir,
  2535.         const Settings& removed_folder)
  2536.     {
  2537.         assert(tracked_dir==network_folder);
  2538.         {
  2539.             boost::mutex::scoped_lock tlock(ntrackers_mutex);
  2540.             std::map< std::string, boost::shared_ptr<NetworkNodeTracker> >::iterator i = ntrackers.find(removed_folder->name());
  2541.             assert( i!=ntrackers.end() );
  2542.             ntrackers.erase(i);
  2543.         }
  2544.     }
  2545.  
  2546.     void constellation_values_changed(
  2547.         const boost::shared_ptr<Dir>&)
  2548.     {
  2549.         notify_about_cc_setup_changes(tech1);
  2550.     }
  2551.  
  2552.     boost::shared_ptr<NetworkNodeTracker> find_node_tracker_locked(
  2553.         const std::string& node_guid,
  2554.         const boost::mutex::scoped_lock& ntrackers_mutex_locked
  2555.         )
  2556.     {
  2557.         std::map< std::string, boost::shared_ptr<NetworkNodeTracker> >::iterator i = ntrackers.find(node_guid);
  2558.         return i!=ntrackers.end() ? i->second : boost::shared_ptr<NetworkNodeTracker>();
  2559.     }
  2560.  
  2561.     boost::shared_ptr<NetworkNodeTracker> find_node_tracker(const std::string& node_guid)
  2562.     {
  2563.         boost::mutex::scoped_lock tlock(ntrackers_mutex);
  2564.         return find_node_tracker_locked(node_guid, tlock);
  2565.     }
  2566.  
  2567.     boost::shared_ptr<NetworkNodeTracker> find_node_tracker_by_session_id(int64_t session_id)
  2568.     {
  2569.         boost::mutex::scoped_lock lock(ntrackers_mutex);
  2570.         std::map< std::string, boost::shared_ptr<NetworkNodeTracker> >::iterator x;
  2571.         for (x=ntrackers.begin(); x!=ntrackers.end(); ++x) {
  2572.             const boost::shared_ptr<NetworkNodeTracker>& t = x->second;
  2573.             if (t->started_session_id==session_id) {
  2574.                 return t;
  2575.             }
  2576.         }
  2577.         return boost::shared_ptr<NetworkNodeTracker>();
  2578.     }
  2579. };
  2580.  
  2581. static
  2582. std::list<std::string> get_network_nodes()
  2583. {
  2584.     SettingsLock l(network_folder);
  2585.     return network_folder->ls_dirs();
  2586. }
  2587.  
  2588. // add tracker
  2589.  
  2590. class NetworkNodeAddTracker:
  2591.     public Constellation::Dir::Notification
  2592. {
  2593.     struct NodeAddHelper
  2594.     {
  2595.         std::string id, name, cloud_id, password, username, origin_account;
  2596.         int port_rpc, port_video, use_cloud_connect, autocredentials, generated, economy;
  2597.  
  2598.         void fill_from_node_add(const SettingsLock&)
  2599.         {
  2600.             id = node_add_dot_dot_dot->get_value_string("new_node_id");
  2601.             name = node_add_dot_dot_dot->get_value_string("new_node_name");
  2602.             cloud_id = node_add_dot_dot_dot->get_value_string("new_node_cloud_id");
  2603.             origin_account = node_add_dot_dot_dot->get_value_string("new_origin_account");
  2604.             username = node_add_dot_dot_dot->get_value_string("new_node_username");
  2605.             password = node_add_dot_dot_dot->get_value_string("new_node_password");
  2606.             use_cloud_connect = node_add_dot_dot_dot->get_value_integer("new_node_use_cloud_connect");
  2607.             port_rpc = node_add_dot_dot_dot->get_value_integer("new_node_port_rpc");
  2608.             port_video = node_add_dot_dot_dot->get_value_integer("new_node_port_video");
  2609.             autocredentials = node_add_dot_dot_dot->get_value_integer("new_node_autocredentials");
  2610.             generated = node_add_dot_dot_dot->get_value_integer("new_node_generated");
  2611.             economy = node_add_dot_dot_dot->get_value_integer("new_node_economy");
  2612.         }
  2613.  
  2614.         std::map<std::string, bool> make_t1cloud_folders(const std::list<std::string>& exist_dirs)
  2615.         {
  2616.             std::map<std::string, bool> out;
  2617.             const Json::Value& accounts = tech1->redir_want_client_accounts(0, false);
  2618.             for (size_t index = 0; index < accounts.size(); ++index) {
  2619.                 const Json::Value& acc = accounts.get(index, Json::Value());
  2620.                 if (acc["account"].isString() == false)
  2621.                     continue;
  2622.                 const std::string& acc_id = acc["account"].asString();
  2623.                 if (acc_id.empty())
  2624.                     continue;
  2625.                 const std::string& foldername = get_cc_t1cloud_foldername(acc_id);
  2626.                 const std::string& cloudid = get_cc_cloudid_for_t1cloud(acc_id);
  2627.  
  2628.                 if (std::find(exist_dirs.begin(), exist_dirs.end(), foldername) != exist_dirs.end())
  2629.                     out[foldername] = false;
  2630.                 else if (make_connection_folder(foldername, foldername, cloudid, acc_id))
  2631.                     out[foldername] = true;
  2632.             }
  2633.             return out;
  2634.         }
  2635.  
  2636.         bool make_connection_folder(const std::string& id, const std::string& foldername, const std::string& cloud_id, const std::string& origin_account)
  2637.         {
  2638.             log("NETWORK: add node %s\n", foldername.c_str());
  2639.  
  2640.             try {
  2641.                 Settings new_dir;
  2642.                 {
  2643.                     SettingsLock lock(network_folder);
  2644.                     new_dir = network_folder->dir_create(id,
  2645.                         is_cc_t1cloud_folder(foldername) ? NetworkNodeVirtual : NetworkNode);
  2646.                 }
  2647.  
  2648.                 SettingsLock lock2(new_dir);
  2649.                 new_dir->set_value_string("name", foldername);
  2650.                 new_dir->set_value_string("cloud_id", cloud_id);
  2651.                 new_dir->set_value_string("origin_account", origin_account);
  2652.                 new_dir->set_value_string("username", username);
  2653.                 new_dir->set_value_string("password", password);
  2654.                 new_dir->set_value_integer("use_cloud_connect", use_cloud_connect);
  2655.                 new_dir->set_value_integer("port_rpc", port_rpc);
  2656.                 new_dir->set_value_integer("port_video", port_video);
  2657.                 new_dir->set_value_integer("generated", generated);
  2658.                 new_dir->set_value_integer("autocredentials", autocredentials);
  2659.                 new_dir->set_value_integer("economy_mode", economy);
  2660.  
  2661.                 return true;
  2662.             } catch (const already_exists_error&) {
  2663.                 log_warning("NETWORK: network node guid duplicate, sorry will do nothing\n");
  2664.                 return false;
  2665.             }
  2666.         }
  2667.  
  2668.         static
  2669.         void reset_node_add(const SettingsLock&)
  2670.         {
  2671.             node_add_dot_dot_dot->set_value_string("new_node_name", "");
  2672.             node_add_dot_dot_dot->set_value_string("new_node_cloud_id", "");
  2673.             node_add_dot_dot_dot->set_value_string("new_origin_account", "");
  2674.             node_add_dot_dot_dot->set_value_string("new_node_username", "");
  2675.             node_add_dot_dot_dot->set_value_string("new_node_password", "");
  2676.             node_add_dot_dot_dot->unset_value("new_node_use_cloud_connect");
  2677.             node_add_dot_dot_dot->unset_value("new_node_port_rpc");
  2678.             node_add_dot_dot_dot->unset_value("new_node_port_video");
  2679.             node_add_dot_dot_dot->unset_value("new_node_autocredentials");
  2680.             node_add_dot_dot_dot->unset_value("new_node_generated");
  2681.             node_add_dot_dot_dot->unset_value("new_node_economy");
  2682.         }
  2683.     };
  2684.  
  2685. public:
  2686.     NetworkNodeAddTracker():
  2687.         Constellation::Dir::Notification("NetworkNodeAddTracker")
  2688.     {
  2689.     }
  2690.  
  2691.     void renew_next_node_id(SettingsLock& locked_node_add_dot_dot_dot)
  2692.     {
  2693.         node_add_dot_dot_dot->set_value_string("new_node_id", tech1->random_guid());
  2694.     }
  2695.  
  2696.     void create_handler()
  2697.     {
  2698.         NodeAddHelper helper;
  2699.         {
  2700.             SettingsLock lock(node_add_dot_dot_dot);
  2701.             int now = node_add_dot_dot_dot->get_value_integer("create_now");
  2702.             if (!now) return;
  2703.             node_add_dot_dot_dot->set_value_integer("create_now", 0);
  2704.  
  2705.             helper.fill_from_node_add(lock);
  2706.             NodeAddHelper::reset_node_add(lock);
  2707.             renew_next_node_id(lock);
  2708.         }
  2709.         if ("vtrassir" == helper.cloud_id) { // it's a kind of magic
  2710.             std::string account_found;
  2711.             const Json::Value& accounts = tech1->redir_want_client_accounts(0, false);
  2712.             for (size_t index = 0; index < accounts.size(); ++index) {
  2713.                 const Json::Value& acc = accounts.get(index, Json::Value());
  2714.                 if (!acc["account"].isString())
  2715.                     continue;
  2716.                 if (!acc["is_primary"].isBool() || !acc["is_primary"].asBool())
  2717.                     continue;
  2718.                 const std::string& acc_id = acc["account"].asString();
  2719.                 if (acc_id.empty())
  2720.                     break;
  2721.  
  2722.                 helper.cloud_id = get_cc_cloudid_for_t1cloud(acc_id);
  2723.                 helper.origin_account = acc_id;
  2724.                 break;
  2725.             }
  2726.             if (helper.origin_account.empty()) {
  2727.                 log_warning("NETCLIENT: origin_account is empty. are you logged in using cloud-login?\n");
  2728.                 return;
  2729.             }
  2730.         }
  2731.  
  2732.         helper.make_connection_folder(helper.id, helper.name, helper.cloud_id, helper.origin_account);
  2733.     }
  2734.  
  2735.     void update_vtrassirs(bool vtrassir_enable)
  2736.     {
  2737.         const std::list<std::string>& dirs = get_network_nodes();
  2738.         std::map<std::string, bool> t1folders;
  2739.         if (vtrassir_enable) {
  2740.             NodeAddHelper helper;
  2741.             helper.autocredentials = 1;
  2742.             helper.use_cloud_connect = 1;
  2743.             t1folders = helper.make_t1cloud_folders(dirs);
  2744.         }
  2745.  
  2746.         std::list<std::string>::const_iterator iter;
  2747.         for (iter = dirs.begin(); iter != dirs.end(); ++iter)
  2748.             if (is_cc_t1cloud_folder(*iter) && t1folders.find(*iter) == t1folders.end())
  2749.                 delete_node(*iter);
  2750.     }
  2751.  
  2752.     void delete_handler()
  2753.     {
  2754.         std::string delete_id;
  2755.         {
  2756.             SettingsLock lock(node_add_dot_dot_dot);
  2757.             delete_id = node_add_dot_dot_dot->get_value_string("delete_node_id");
  2758.             if (delete_id.empty()) return;
  2759.             node_add_dot_dot_dot->set_value_string("delete_node_id", "");
  2760.         }
  2761.  
  2762.         if (delete_id == "cloudtrassir")
  2763.             delete_vtrassir_nodes();
  2764.         else
  2765.             delete_node(delete_id);
  2766.     }
  2767.  
  2768.     void delete_vtrassir_nodes()
  2769.     {
  2770.         const std::list<std::string>& dirs = get_network_nodes();
  2771.         std::list<std::string>::const_iterator it;
  2772.         for (it = dirs.begin(); it != dirs.end(); ++it)
  2773.             if (is_cc_t1cloud_folder(*it))
  2774.                 delete_node(*it);
  2775.     }
  2776.  
  2777.     void delete_node(const std::string& delete_id)
  2778.     {
  2779.         try {
  2780.             SettingsLock lock(network_folder);
  2781.             network_folder->dir_remove(delete_id);
  2782.  
  2783.         } catch (const not_found_error& e) {
  2784.             log("NETSERVER: cannot erase network node: %s\n", e.what());
  2785.         }
  2786.     }
  2787.  
  2788.     void constellation_values_changed(
  2789.         const Settings& tracked_dir)
  2790.     {
  2791.         assert(node_add_dot_dot_dot==tracked_dir);
  2792.         create_handler();
  2793.         delete_handler();
  2794.     }
  2795. };
  2796.  
  2797. namespace {
  2798. class CloudTracker;
  2799. class CloudStatTracker;
  2800. static boost::shared_ptr<CloudTracker> cloud_tracker;
  2801. static boost::shared_ptr<CloudStatTracker> cloud_stat_tracker;
  2802.  
  2803. class CloudTracker : public Constellation::Dir::Notification
  2804. {
  2805.     bool vtrassir_enable;
  2806.  
  2807.     void constellation_values_changed(const Settings&)
  2808.     {
  2809.         if (network_node_add_tracker == NULL)
  2810.             return;
  2811.         const bool enable = is_vtrassir_enable();
  2812.         if (enable != vtrassir_enable) {
  2813.             vtrassir_enable = enable;
  2814.             network_node_add_tracker->update_vtrassirs(enable);
  2815.         }
  2816.     }
  2817.  
  2818. public:
  2819.     CloudTracker():
  2820.         Constellation::Dir::Notification("netserver:CloudTracker"),
  2821.         vtrassir_enable(false)
  2822.     {}
  2823.  
  2824.     bool is_vtrassir_enable()
  2825.     {
  2826.         SettingsLock l(cloudfolder);
  2827.         return cloudfolder->get_value_integer("import_channels_enabled") != 0;
  2828.     }
  2829. };
  2830.  
  2831. class CloudStatTracker: public Constellation::Dir::Notification
  2832. {
  2833.     std::string client_accounts;
  2834.  
  2835.     void constellation_values_changed(const Settings& tracked_dir)
  2836.     {
  2837.         if (network_node_add_tracker == NULL || cloud_tracker == NULL)
  2838.             return;
  2839.         std::string accounts;
  2840.         {
  2841.             SettingsLock lock(tracked_dir);
  2842.             accounts = tracked_dir->get_value_string("import_accounts");
  2843.         }
  2844.         if (accounts != client_accounts) {
  2845.             client_accounts = accounts;
  2846.             network_node_add_tracker->update_vtrassirs(cloud_tracker->is_vtrassir_enable());
  2847.         }
  2848.     }
  2849. public:
  2850.     CloudStatTracker():
  2851.         Constellation::Dir::Notification("netserver:CloudStatTracker")
  2852.     {}
  2853. };
  2854.  
  2855. }
  2856.  
  2857. #ifdef T1_SERVER
  2858.  
  2859. static
  2860. void login_error_and_ban(const boost::shared_ptr<NetClientServiceListReceiver>& service_client,
  2861.     const std::string& error_string)
  2862. {
  2863.     FakeObjectInfo info = Rpc::fake_object_info(service_client.get());
  2864.     RpcConnection::asio_temporary_ban(info.ip);
  2865.     service_client->login_error(error_string);
  2866. }
  2867.  
  2868. typedef std::multimap< std::string, boost::weak_ptr<NetClientServiceListReceiver> > StringClientMap;
  2869. static boost::mutex clients_mmap_mutex;
  2870.  static StringClientMap clients_mmap;
  2871. void netserver_kick_user(const std::string& user_guid, const std::string& reason) {
  2872.     StringClientMap my_clients;
  2873.     {
  2874.         boost::mutex::scoped_lock lock(clients_mmap_mutex);
  2875.         my_clients = clients_mmap;
  2876.     }
  2877.  
  2878.     std::pair<StringClientMap::iterator, StringClientMap::iterator> bounds;
  2879.     bounds = my_clients.equal_range(user_guid);
  2880.  
  2881.     StringClientMap::iterator it;
  2882.     for (it = bounds.first; it != bounds.second; ++it) {
  2883.         boost::shared_ptr<NetClientServiceListReceiver> service_client = it->second.lock();
  2884.         if (!service_client) continue;
  2885.  
  2886.         service_client->login_error(reason);
  2887.         spontaneous_disconnect(service_client.get());
  2888.         log_warning("NETSERVER: User '%s' kicked\n", user_guid.c_str());
  2889.     }
  2890. }
  2891.  
  2892. bool user_logged_in(const std::string& user_guid)
  2893. {
  2894.     Settings root = tech1->root_under_operator_logged_in();
  2895.     if (root && user_guid==root->user_id())
  2896.         return true;
  2897.     StringClientMap my_clients;
  2898.     {
  2899.         boost::mutex::scoped_lock lock(clients_mmap_mutex);
  2900.         my_clients = clients_mmap;
  2901.     }
  2902.     return my_clients.count(user_guid)>0;
  2903. }
  2904.  
  2905. // handshake
  2906.  
  2907. class Tech1Welcome: public NetServerWelcome {
  2908. public:
  2909.     boost::mutex client_list_mutex;
  2910.      std::list< boost::weak_ptr<NetClientServiceListReceiver> > client_list;
  2911.  
  2912.     void network_login(
  2913.         const std::string& username,
  2914.         const std::string& password,
  2915.         const std::string& clientversion,
  2916.         const boost::shared_ptr<NetClientServiceListReceiver>& service_client,
  2917.         bool economy_mode,
  2918.         int network_recurse_level
  2919.         )
  2920.     {
  2921.         int actual_connection_count;
  2922.         {
  2923.             boost::mutex::scoped_lock lock(client_list_mutex);
  2924.             std::list<boost::weak_ptr<NetClientServiceListReceiver> >::iterator x;
  2925.             for (x=client_list.begin(); x!=client_list.end(); ) {
  2926.                 boost::shared_ptr<NetClientServiceListReceiver> rcvr = x->lock();
  2927.                 if (!rcvr) x = client_list.erase(x);
  2928.                 else x++;
  2929.             }
  2930.             actual_connection_count = client_list.size();
  2931.         }
  2932.  
  2933.         if (!service_client) {
  2934.             log("NETSERVER: login from remote failed (1)\n");
  2935.             return;
  2936.         }
  2937.  
  2938.         FakeObjectInfo info = Rpc::fake_object_info(service_client.get());
  2939.  
  2940.         boost::shared_ptr<ServerObject> so = tech1->serverobject();
  2941.         bool supported = false;
  2942.         supported |= clientversion.find("Trassir-3.0") != std::string::npos;
  2943.         supported |= clientversion.find("Trassir-4.0") != std::string::npos;
  2944.         supported |= clientversion.find("Stornix-4.0") != std::string::npos;
  2945.         if (!supported) {
  2946.             login_error_and_ban(service_client,
  2947.                 stdprintf("your software version %s not compatible with %s",
  2948.                     clientversion.c_str(),
  2949.                     PRODUCT_NAME));
  2950.             tech1->useraction_log("LOGIN/WRONG-VERSION", service_client, "~operator", "%s %s",
  2951.                 username.c_str(), clientversion.c_str());
  2952.             log("NETSERVER: login from %s with incompatible version '%s'\n",
  2953.                 info.ip.c_str(), clientversion.c_str());
  2954.             return;
  2955.         }
  2956.  
  2957.         if (username=="~Cluster~" && !tech1->cluster_node_guid().empty()) {
  2958.             if (!cluster_login(password, service_client, info.server_salt)) {
  2959.                 log_warning("NETSERVER: cluster2cluster password incorrect\n");
  2960.  
  2961.                 login_error_and_ban(service_client, "401: authorization failed");
  2962.                 tech1->useraction_log("LOGIN/WRONG-CREDENTIALS", service_client, "", "%s %s",
  2963.                     username.c_str(), clientversion.c_str());
  2964.                 if (so) tech1->fire_event(so, &event_login_failed, username.c_str(), info.ip.c_str(), "");
  2965.             }
  2966.  
  2967.             return;
  2968.         }
  2969.  
  2970.         std::string user_id = tech1->authorize(
  2971.             username, password,
  2972.             info.ip, info.server_salt,
  2973.             0);
  2974.  
  2975.         if (user_id.empty()) {
  2976.             login_error_and_ban(service_client,"401: authorization failed");
  2977.             if(password.find("CLOUDSID") != std::string::npos)
  2978.                 service_client->update_offline_password(""); //erase disposable pass for CC connection
  2979.             log("NETSERVER: login %s from %s failed\n", username.c_str(), info.ip.c_str());
  2980.             tech1->useraction_log("LOGIN/WRONG-CREDENTIALS", service_client, "~operator", "%s %s",
  2981.                 username.c_str(), clientversion.c_str());
  2982.             if (so)
  2983.                 tech1->fire_event(so, &event_login_failed, username.c_str(), info.ip.c_str(), "");
  2984.  
  2985.             return;
  2986.         }
  2987.  
  2988.         {
  2989.             boost::mutex::scoped_lock lock(clients_mmap_mutex);
  2990.             clients_mmap.insert(std::pair< std::string, boost::weak_ptr<NetClientServiceListReceiver> >(user_id, service_client));
  2991.  
  2992.             StringClientMap::iterator it;
  2993.             StringClientMap::iterator to_erase;
  2994.             it = clients_mmap.begin();
  2995.             while(it != clients_mmap.end()) {
  2996.                 if (it->second.expired()) {
  2997.                     to_erase = it;
  2998.                     ++it;
  2999.                     clients_mmap.erase(to_erase);
  3000.                 } else {
  3001.                     ++it;
  3002.                 }
  3003.             }
  3004.         }
  3005.  
  3006.         Settings root_under_name;
  3007.         try {
  3008.             boost::shared_ptr<Constellation::Root> root = tech1->constellation_root();
  3009.             root_under_name = root->root_directory(user_id);
  3010.  
  3011.         } catch (const std::logic_error& e) {
  3012.             login_error_and_ban(service_client, e.what());
  3013.             log_warning("NETSERVER: login from remote failed: %s\n", e.what());
  3014.             return;
  3015.         }
  3016.  
  3017.         Settings network = tech1->local_server_under_admin()->cd("network", false);
  3018.         int limit;
  3019.         {
  3020.             SettingsLock lock(network);
  3021.             limit = network->get_value_integer("limit_client_count");
  3022.         }
  3023.         if(actual_connection_count >= limit) {
  3024.             login_error_and_ban(service_client, "client count limit reached (set by administrator)");
  3025.             log_warning("NETSERVER: client count limit reached (set by administrator)\n");
  3026.             spontaneous_disconnect(service_client.get());
  3027.             return;
  3028.         }
  3029.  
  3030.         if (so)
  3031.             tech1->fire_event(so, &event_login_successful, username.c_str(), info.ip.c_str(), "");
  3032.  
  3033.         tech1->useraction_log("LOGIN/SUCCESS", service_client, user_id, "%s %s",
  3034.             username.c_str(), clientversion.c_str());
  3035.         log_timestamp("NETSERVER: connected client %s from %s\n", username.c_str(), info.ip.c_str());
  3036.  
  3037.         {
  3038.             boost::mutex::scoped_lock lock(client_list_mutex);
  3039.             client_list.push_back(service_client);
  3040.         }
  3041.         boost::shared_ptr<ServerDirReal> root_server_dir(
  3042.             new ServerDirReal(root_under_name));
  3043.         root_server_dir->i_am_root_server_finder = true;
  3044.         if ("AmergeServiceUser" == username) {
  3045.             root_server_dir->folders_whitelist = &whitelist_amerge;
  3046.         } else if (tech1->have_mini()) {
  3047.             if ("Admin" != username)
  3048.                 root_server_dir->folders_whitelist = &whitelist_cloud;
  3049.         } else if (economy_mode) {
  3050.             root_server_dir->folders_whitelist = &whitelist_economy;
  3051.         } else if (!tech1->cluster_node_guid().empty()) {
  3052.             root_server_dir->folders_blacklist = &blacklist_cluster2client;
  3053.         }
  3054.  
  3055.         root_server_dir->recursion_limit = network_recurse_level;
  3056.         root_server_dir->pass_server_receiver(service_client);
  3057.         root_server_dir->client2server_start_work();
  3058.         service_client->keep_reference_on_root_folder(root_server_dir);
  3059.  
  3060.         // offline passwords
  3061.  
  3062.         std::string new_password = tech1->random_guid();
  3063.         Settings users = tech1->local_server_under_admin()->cd("users", false);
  3064.         Settings user = users->cd(user_id, false);
  3065.         if (user) {
  3066.             SettingsLock lock(user);
  3067.             if (!user->get_value_integer("from_cloud")) return; // offline password only for cloud login
  3068.  
  3069.             std::string random_passwords = user->get_value_string_with_default("random_passwords", "");
  3070.             csv_list random_passwords_list = csv_explode(random_passwords);
  3071.             service_client->update_offline_password(new_password);
  3072.             uint64_t now_ts = now();
  3073.             random_passwords_list.push_back(print_uint64(now_ts));
  3074.             random_passwords_list.push_back(new_password);
  3075.  
  3076.             user->set_value_string("random_passwords", csv_implode(random_passwords_list));
  3077.         }
  3078.     }
  3079.  
  3080.     bool cluster_login(
  3081.         const std::string& password,
  3082.         const boost::shared_ptr<NetClientServiceListReceiver>& service_client,
  3083.         uint64_t salt)
  3084.     {
  3085.         std::string ssl_pkey;
  3086.         Settings swo = tech1->local_server_under_admin()->cd("system_wide_options", true);
  3087.         {
  3088.             SettingsLock lock(swo);
  3089.             ssl_pkey = swo->get_value_string("ssl_pkey");
  3090.         }
  3091.  
  3092.         static std::string meerswine;
  3093.         if (meerswine.empty()) {
  3094.             FILE* f = fopen("meerswine", "rb");
  3095.             if (f) {
  3096.                 fclose(f);
  3097.                 meerswine = read_file("meerswine");
  3098.             } else {
  3099.                 meerswine = tech1->random_guid() + tech1->random_guid();
  3100.             }
  3101.         }
  3102.  
  3103.         std::string::size_type s_pos = password.find("SALTED ");
  3104.         std::string pass = password.substr((s_pos != std::string::npos) ? 7 : 0);
  3105.  
  3106.         if (
  3107.             !expensive_password_hash_check(meerswine, salt, hex_string_to_bytes_vector(pass)) &&
  3108.             !expensive_password_hash_check(ssl_pkey, salt, hex_string_to_bytes_vector(pass))
  3109.         ) return false;
  3110.  
  3111.         Settings root = tech1->constellation_root()->root_directory("admin");
  3112.         boost::shared_ptr<ServerDirReal> root_server_dir(new ServerDirReal(root));
  3113.         root_server_dir->i_am_root_server_finder = true;
  3114.         root_server_dir->i_am_cluster = true;
  3115.         root_server_dir->folders_blacklist = &blacklist_cluster2cluster;
  3116.         root_server_dir->recursion_limit = 1;
  3117.         root_server_dir->pass_server_receiver(service_client);
  3118.         root_server_dir->client2server_start_work();
  3119.         service_client->keep_reference_on_root_folder(root_server_dir);
  3120.  
  3121.         return true;
  3122.     }
  3123. };
  3124. #endif
  3125.  
  3126. extern bool amerge_session_connected_successfully(
  3127.     int64_t rpc_session_id,
  3128.     const std::string& server_guid,
  3129.     const boost::shared_ptr<NetServerWelcome>& remote_welcome,
  3130.     uint64_t salt);
  3131.  
  3132.  
  3133. class RpcClient: public Client {
  3134. public:
  3135.     void welcome_message_from_server(const boost::shared_ptr<Interface>& sr, const std::string& server_guid)
  3136.     {
  3137.         if (server_guid.empty()) {
  3138.             log("NETCLIENT: connection rejected (0)\n");
  3139.             return;
  3140.         }
  3141.  
  3142.         boost::shared_ptr<NetServerWelcome> remote_welcome = boost::dynamic_pointer_cast<NetServerWelcome>(sr);
  3143.         if (!remote_welcome) {
  3144.             log("NETCLIENT: connection rejected (1)\n");
  3145.             return;
  3146.         }
  3147.  
  3148.         Rpc::FakeObjectInfo info = fake_object_info(sr.get());
  3149.         if (!info.valid) {
  3150.             log("NETCLIENT: connection rejected (2)\n");
  3151.             return;
  3152.         }
  3153.  
  3154.         boost::shared_ptr<NetworkNodeTracker> associated_node_tracker =
  3155.             network_tracker->find_node_tracker_by_session_id(info.session_id);
  3156.  
  3157.         if (!associated_node_tracker) {
  3158.             boost::shared_ptr<AmergeRpcSession> session;
  3159.             {
  3160.                 boost::mutex::scoped_lock lock(amerge_session_mutex);
  3161.                 session = amerge_session;
  3162.             }
  3163.             if (session)
  3164.                 session->connected_successfully(remote_welcome);
  3165.             else
  3166.                 log("NETCLIENT: connection rejected (3)\n");
  3167.             return;
  3168.         }
  3169.  
  3170.         //log("RpcClient: remote server guid %s\n", server_guid.c_str());
  3171.  
  3172.         if (going_down) return; // little race vs network_tracker.reset(), on shutdown
  3173.  
  3174.         try {
  3175.             associated_node_tracker->connected_successfully(server_guid, remote_welcome, info.server_salt);
  3176.         } catch (const std::logic_error& e) { // access denied, not found (bad server_guid)
  3177.             log("NETCLIENT: %s\n", e.what());
  3178.             return;
  3179.         }
  3180.     }
  3181. };
  3182.  
  3183. void update_node_ip_callback(int64_t session_id, const std::string& ip_address)
  3184. {
  3185.     if (going_down) return;
  3186.  
  3187.     Settings associated_node;
  3188.     {
  3189.         boost::shared_ptr<NetworkNodeTracker> associated_node_tracker =
  3190.             network_tracker->find_node_tracker_by_session_id(session_id);
  3191.         if (associated_node_tracker) {
  3192.             associated_node = associated_node_tracker->node_dir;
  3193.             associated_node_tracker->update_node_health(0);
  3194.         }
  3195.     }
  3196.  
  3197.     if (!associated_node) {
  3198.         // already have message in logs, plus
  3199.         log("NETCLIENT: cannot find network node to update ip address\n");
  3200.         return;
  3201.     }
  3202.  
  3203.     SettingsLock lock(associated_node);
  3204.     associated_node->set_value_string("ip_address", ip_address);
  3205. }
  3206.  
  3207. void update_node_address_callback(int64_t session_id, const std::string& ip_address, int port_rpc, int port_video)
  3208. {
  3209.     if (going_down) return;
  3210.  
  3211.     Settings associated_node;
  3212.     {
  3213.         boost::shared_ptr<NetworkNodeTracker> associated_node_tracker =
  3214.             network_tracker->find_node_tracker_by_session_id(session_id);
  3215.         if (associated_node_tracker) {
  3216.             associated_node = associated_node_tracker->node_dir;
  3217.             associated_node_tracker->update_node_health(0);
  3218.             associated_node_tracker->try_get_address_from_cc = false;
  3219.         }
  3220.     }
  3221.  
  3222.     if (!associated_node) {
  3223.         // already have message in logs, plus
  3224.         log("NETCLIENT: cannot find network node to update ip address\n");
  3225.         return;
  3226.     }
  3227.     std::string now_ts = print_uint64(now());
  3228.  
  3229.     SettingsLock lock(associated_node);
  3230.     associated_node->set_value_string("ip_address", ip_address);
  3231.     associated_node->set_value_integer("port_rpc", port_rpc);
  3232.     associated_node->set_value_integer("port_video", port_video);
  3233.     associated_node->set_value_integer("address_from_cc_success", 1);
  3234. }
  3235.  
  3236. void socket_error_callback(int64_t session_id, const std::string& error_message)
  3237. {
  3238.     if (going_down) return;
  3239.  
  3240.     Settings associated_node;
  3241.     {
  3242.         boost::shared_ptr<NetworkNodeTracker> associated_node_tracker = network_tracker->find_node_tracker_by_session_id(session_id);
  3243.         if (associated_node_tracker) {
  3244.             associated_node = associated_node_tracker->node_dir;
  3245.             associated_node_tracker->disconnect();
  3246.             associated_node_tracker->update_node_health(0);
  3247.         }
  3248.     }
  3249.  
  3250.     if (!associated_node) {
  3251.         // already have message in logs, plus
  3252.         log("NETCLIENT: cannot find network node to store error: %s\n",
  3253.             error_message.c_str());
  3254.         return;
  3255.     }
  3256.  
  3257.     Settings node_stat = associated_node->cd("stats", false);
  3258.     if (node_stat) {
  3259.         SettingsLock lock(node_stat);
  3260.         const std::string& already_have_error = node_stat->get_value_string("last_error");
  3261.         if (already_have_error.empty()) { // first error is better
  3262.             node_stat->set_value_string("last_error", error_message);
  3263.         }
  3264.     }
  3265.     SettingsLock lock(associated_node);
  3266.     associated_node->set_value_integer("address_from_cc_success", 0);
  3267. }
  3268.  
  3269. #ifdef T1_SERVER
  3270. class RpcServer: public Server {
  3271. public:
  3272.     boost::shared_ptr<Tech1Welcome> i_store_welcome;
  3273.  
  3274.     RpcServer()
  3275.     {
  3276.         i_store_welcome.reset(new Tech1Welcome);
  3277.     }
  3278.  
  3279.     void send_welcome_message_to_client(const boost::shared_ptr<Client>& cl)
  3280.     {
  3281.         cl->welcome_message_from_server(i_store_welcome, tech1->server_guid());
  3282.     }
  3283. };
  3284. #endif
  3285.  
  3286.  
  3287. // voting here
  3288.  
  3289. VotingServerContext::VotingServerContext(const std::string& server_guid):
  3290.     server_guid(server_guid),
  3291.     Constellation::Dir::Notification("VotingServerContext")
  3292. {
  3293. }
  3294.  
  3295. VotingServerContext::~VotingServerContext()
  3296. {
  3297.     assert(!remote_server);
  3298. }
  3299.  
  3300. void VotingServerContext::decide_who_should_proceed()
  3301. {
  3302.     boost::shared_ptr<ServerProvider> old_winner;
  3303.     boost::shared_ptr<ServerProvider> new_winner;
  3304.  
  3305.     {
  3306.         boost::mutex::scoped_lock lock(server_voting_mutex);
  3307.         old_winner = vote_winner.lock();
  3308.         vote_winner.reset();
  3309.  
  3310.         sort();
  3311.  
  3312.         if (!votes.empty() && !going_down)
  3313.             new_winner = votes.front().server_provider.lock();
  3314.             // if lock failed, we will be back here, vote again
  3315.         vote_winner = new_winner;
  3316.     }
  3317.  
  3318.     if (old_winner!=new_winner) {
  3319.         if (old_winner)
  3320.             old_winner->you_have_lost_the_vote();
  3321.  
  3322.         if (new_winner)
  3323.             new_winner->you_have_won_the_vote();
  3324.     }
  3325. }
  3326.  
  3327. bool check_cert(int64_t session_id, const std::string& fingerprint)
  3328. {
  3329.     Settings serv_node;
  3330.     {
  3331.         boost::shared_ptr<NetworkNodeTracker> nn_tracker =
  3332.             network_tracker->find_node_tracker_by_session_id(session_id);
  3333.         if (nn_tracker)
  3334.             serv_node = nn_tracker->node_dir;
  3335.     }
  3336.  
  3337.     if (!serv_node) {
  3338.         log_warning("NETCLIENT: cannot find network node to check certificate\n");
  3339.         return false;
  3340.     }
  3341.  
  3342.     Settings serv_stats = serv_node->cd("stats", false);
  3343.     if (!serv_stats) {
  3344.         log_critical_error("NETCLIENT: cannot find network node stat dir\n");
  3345.         return false;
  3346.     }
  3347.  
  3348.     std::string allowed_fingerprint;
  3349.     {
  3350.         SettingsLock slock(serv_node);
  3351.         allowed_fingerprint = serv_node->get_value_string("accepted_fingerprint");
  3352.     }
  3353.  
  3354.     {
  3355.         SettingsLock sslock(serv_stats);
  3356.         serv_stats->set_value_string("fingerprint", fingerprint);
  3357.     }
  3358.  
  3359.     return (fingerprint == allowed_fingerprint);
  3360. }
  3361.  
  3362.  
  3363. class LocalOperatorTracker:
  3364.     public Dir::Notification
  3365. {
  3366.     std::string local_operator;
  3367.     std::string cloud_client_sid;
  3368.  
  3369. public:
  3370.     LocalOperatorTracker()
  3371.         :Constellation::Dir::Notification("LocalOperatorTracker")
  3372.     {
  3373.     }
  3374.  
  3375.     void constellation_values_changed(const Settings& tracked_dir)
  3376.     {
  3377.         std::string new_local_operator, new_cloud_client_sid;
  3378.         {
  3379.             Json::Value acc = tech1->redir_want_client_primary(0, false);
  3380.             SettingsLock lock(health);
  3381.             new_local_operator = health->get_value_string("local_operator");
  3382.             new_cloud_client_sid = acc["client_sid"].asString();
  3383.         }
  3384.  
  3385.         bool cloud_enabled = false;
  3386.         bool predefined_user = false;
  3387.         if (cloudfolder) {
  3388.             SettingsLock lock(cloudfolder);
  3389.             std::string predefined_username = cloudfolder->get_value_string("predefined_user_login");
  3390.             predefined_user = !!cloudfolder->get_value_integer("predefined_user");
  3391.             predefined_user &= !predefined_username.empty();
  3392.             cloud_enabled = !!cloudfolder->get_value_integer("cloud_enabled");
  3393.         }
  3394.  
  3395.         if (local_operator!=new_local_operator && !predefined_user) {
  3396.             std::string path;
  3397.             Settings user;
  3398.  
  3399.             if (!new_local_operator.empty()) {
  3400.                 path = stdprintf("users/%s", new_local_operator.c_str());
  3401.                 user = tech1->local_server_under_admin()->cd(path, false);
  3402.             }
  3403.  
  3404.             bool from_cloud = false;
  3405.             if (user) {
  3406.                 SettingsLock lock(user);
  3407.                 from_cloud = !!user->get_value_integer("from_cloud");
  3408.             } else {
  3409.                 cloud_client_logout();
  3410.             }
  3411.  
  3412.             if (from_cloud) cloud_client_start_thread(user);
  3413.         }
  3414.  
  3415.         if (local_operator != new_local_operator ||
  3416.             cloud_client_sid != new_cloud_client_sid)
  3417.         {
  3418.             std::list<std::string> network_nodes = get_network_nodes();
  3419.  
  3420.             std::list<std::string>::iterator x;
  3421.             for (x=network_nodes.begin(); x!= network_nodes.end(); x++) {
  3422.                 Settings node = network_folder->cd(*x, false);
  3423.                 if (node->prototype_name()!="NetworkNode" && node->prototype_name()!="NetworkNodeVirtual")
  3424.                     continue;
  3425.                 if (!node) continue;
  3426.                 int autocredentials, should_be_connected, use_cloud_connect;
  3427.                 {
  3428.                     SettingsLock lock(node);
  3429.                     autocredentials = node->get_value_integer("autocredentials");
  3430.                     should_be_connected = node->get_value_integer("should_be_connected");
  3431.                     use_cloud_connect = node->get_value_integer("use_cloud_connect");
  3432.                 }
  3433.                 if (!should_be_connected || (!autocredentials && !use_cloud_connect)) continue;
  3434.                 boost::shared_ptr<NetworkNodeTracker> tracker = network_tracker->find_node_tracker(*x);
  3435.                 if (tracker)
  3436.                     node->fire_values_notification(tracker);
  3437.             }
  3438.         }
  3439.  
  3440.         cloud_client_sid = new_cloud_client_sid;
  3441.         local_operator = new_local_operator;
  3442.     }
  3443. };
  3444.  
  3445. static const int iface_tracking_timeout_sec = 1;
  3446. static bool terminate_iface_tracking = false;
  3447. static boost::shared_ptr<boost::thread> iface_traker_thread;
  3448.  
  3449. static boost::mutex subscribers_mutex;
  3450.  static std::list< boost::weak_ptr<NetworkAddressesChangeCallback> > network_addresses_subscribtions;
  3451.  
  3452. void network_subscribe_on_addresses_change(
  3453.     const boost::weak_ptr<NetworkAddressesChangeCallback>& callback_weak
  3454.     )
  3455. {
  3456.     network_addresses_subscribtions.push_back(callback_weak);
  3457. }
  3458.  
  3459. #ifdef T1_SERVER
  3460. static
  3461. void send_current_addresses_to_subscribers()
  3462. {
  3463.     try {
  3464.         std::list< boost::weak_ptr<NetworkAddressesChangeCallback> > subscribtions;
  3465.         {
  3466.             boost::mutex::scoped_lock slock(subscribers_mutex);
  3467.             network_addresses_subscribtions.remove_if(boost::mem_fn(&boost::weak_ptr<NetworkAddressesChangeCallback>::expired));
  3468.             subscribtions = network_addresses_subscribtions;
  3469.         }
  3470.  
  3471.         std::list< boost::weak_ptr<NetworkAddressesChangeCallback> >::iterator i;
  3472.         for (i = subscribtions.begin(); subscribtions.end() != i; ++i) {
  3473.             const boost::shared_ptr<NetworkAddressesChangeCallback>& cur = i->lock();
  3474.             if (!cur) continue;
  3475.  
  3476.             cur->network_addresses_changed();
  3477.         }
  3478.  
  3479.     } catch (const std::exception& e) {
  3480.         log_warning("NETWORK_INTERFACES update: %s\n", e.what());
  3481.     }
  3482. }
  3483. #endif
  3484.  
  3485. #ifdef WIN32
  3486. #include <winsock2.h>
  3487. #include <iphlpapi.h>
  3488. #include <stdio.h>
  3489. #include <windows.h>
  3490.  
  3491. #ifdef T1_SERVER
  3492. static
  3493. void windows_iface_track_thread_func()
  3494. {
  3495.     set_thread_name("net/server/win-track-ip-changes");
  3496.  
  3497.     while (!terminate_iface_tracking) {
  3498.         OVERLAPPED overlap = {0};
  3499.         overlap.hEvent = WSACreateEvent();
  3500.         HANDLE hand = NULL;
  3501.         const DWORD rc = NotifyAddrChange(&hand, &overlap);
  3502.         if (ERROR_IO_PENDING != rc) {
  3503.             log_warning("NETWORK: fail to subscribe for address change; error code %d\n", rc);
  3504.             sleep_relative(1000);
  3505.             continue;
  3506.         }
  3507.  
  3508.         while (!terminate_iface_tracking) {
  3509.             const DWORD rz = WaitForSingleObject(overlap.hEvent, iface_tracking_timeout_sec * 1000);
  3510.             if (rz == WAIT_OBJECT_0) {
  3511.                 log_timestamp("NETWORK: IP configuration changed\n");
  3512.                 send_current_addresses_to_subscribers();
  3513.                 break; // restart outer loop to get more IP change notifications
  3514.             } else if (rz != WAIT_TIMEOUT) {
  3515.                 log_warning("NETWORK: fail to wait for address change; retcode %d, last error code %d\n", rz, GetLastError());
  3516.                 break; // restart outer loop
  3517.             }
  3518.         }
  3519.  
  3520.         CancelIPChangeNotify(&overlap); // optional but reccomended in WINAPI
  3521.         CloseHandle(overlap.hEvent);
  3522.     }
  3523. }
  3524. #endif // T1_SERVER
  3525. #endif  // WIN32
  3526.  
  3527. #ifdef __linux__
  3528. #include <stdio.h>
  3529. #include <string.h>
  3530. #include <netinet/in.h>
  3531. #include <linux/netlink.h>
  3532. #include <linux/rtnetlink.h>
  3533. #include <net/if.h>
  3534.  
  3535.  
  3536. #ifdef T1_SERVER
  3537. static
  3538. void linux_iface_track_thread_func()
  3539. {
  3540.     set_thread_name("ifaddr_tracker");
  3541.     fd_set readfds;
  3542.     int socketfd, len;
  3543.     char buffer[4096];
  3544.     struct sockaddr_nl addr;
  3545.     struct nlmsghdr *nlh;
  3546.     struct timeval tv;
  3547.  
  3548.     if ((socketfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
  3549.         log_warning("couldn't open NETLINK_ROUTE socket");
  3550.         return;
  3551.     }
  3552.  
  3553.     const int default_flags = fcntl(socketfd, F_GETFL, 0);
  3554.     fcntl(socketfd, F_SETFL, default_flags | O_NONBLOCK);
  3555.  
  3556.     memset(&addr, 0, sizeof(addr));
  3557.     addr.nl_family = AF_NETLINK;
  3558.     addr.nl_groups = RTMGRP_IPV4_IFADDR;
  3559.  
  3560.     if (bind(socketfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
  3561.         log_warning("couldn't bind");
  3562.         return;
  3563.     }
  3564.  
  3565.     nlh = (struct nlmsghdr *)buffer;
  3566.     while (!terminate_iface_tracking) {
  3567.         tv.tv_sec = iface_tracking_timeout_sec;
  3568.         tv.tv_usec = 0;
  3569.  
  3570.         FD_ZERO(&readfds);
  3571.         FD_SET(socketfd, &readfds);
  3572.  
  3573.         const int rc = select(0, &readfds, NULL, NULL, &tv);
  3574.  
  3575.         if (rc < 0) {
  3576.             log_warning("IFACE_TRACKER: select error\n");
  3577.             return;
  3578.         }
  3579.  
  3580.         if (!FD_ISSET(socketfd, &readfds)) {
  3581.             continue;
  3582.         }
  3583.  
  3584.         if ((len = recv(socketfd, nlh, 4096, 0)) > 0) {
  3585.             while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) {
  3586.                 if (RTM_NEWADDR == nlh->nlmsg_type || RTM_DELADDR == nlh->nlmsg_type)
  3587.                     send_current_addresses_to_subscribers();
  3588.  
  3589.                 nlh = NLMSG_NEXT(nlh, len);
  3590.             }
  3591.         }
  3592.     }
  3593. }
  3594. #endif
  3595. #endif  // __linux__
  3596.  
  3597. #ifdef T1_SERVER
  3598. static
  3599. void start_track_interfaces_change()
  3600. {
  3601.     if (iface_traker_thread)
  3602.         return;
  3603.  
  3604.     terminate_iface_tracking = false;
  3605.  
  3606. #ifdef __linux__
  3607.     iface_traker_thread.reset(new boost::thread(&linux_iface_track_thread_func));
  3608. #endif  // __linux__
  3609. #ifdef WIN32
  3610.     iface_traker_thread.reset(new boost::thread(&windows_iface_track_thread_func));
  3611. #endif  // WIN32
  3612. }
  3613.  
  3614. static
  3615. void stop_track_interfaces_change()
  3616. {
  3617.     if (!iface_traker_thread)
  3618.         return;
  3619.  
  3620.     terminate_iface_tracking = true;
  3621.     iface_traker_thread->join();
  3622.     iface_traker_thread.reset();
  3623. }
  3624. #endif
  3625.  
  3626. // init/done
  3627.  
  3628. void network_init(Tech1* t1)
  3629. {
  3630.     static bool init_once = true;
  3631.  
  3632.     if (init_once) {
  3633.         rpc_json_init();
  3634.         register_all_agent_factories_tech1network();
  3635.         register_all_fake_factories_tech1network();
  3636.         t1->registry = Rpc::registry;
  3637.         init_once = false;
  3638.     }
  3639.  
  3640.     going_down = false;
  3641.  
  3642.     tech1 = t1;
  3643.     root_under_admin = tech1->constellation_root()->root_directory("admin");
  3644.     create_network_prototypes(root_under_admin);
  3645.  
  3646.     RpcConnection::asio_startup();
  3647.  
  3648.     cloud_connect_init(t1);
  3649. }
  3650.  
  3651. void net_set_server_name()
  3652. {
  3653.     Settings local_server = tech1->local_server_under_admin();
  3654.     std::string alternative_name;
  3655.     std::string name_prefix;
  3656.     {
  3657.         Settings swo = local_server->cd("system_wide_options", false);
  3658.         assert(swo);
  3659.         SettingsLock lock(swo);
  3660.         alternative_name = swo->get_value_string("alternative_name");
  3661.         const std::string opmode = swo->get_value_string("operation_mode");
  3662.         if (opmode == "freeversion")
  3663.             name_prefix = "Trassir-FREE-";
  3664.     }
  3665.     {
  3666.         SettingsLock lock(local_server);
  3667.         if (local_server->prototype_name()=="LocalServer") {
  3668.             local_server->set_value_string("name", name_prefix
  3669.                 + (alternative_name.empty() ? dssl_gethostname() : alternative_name));
  3670.         }
  3671.     }
  3672. }
  3673.  
  3674. #ifdef T1_SERVER
  3675. void net_server_after_load()
  3676. {
  3677.     try {
  3678.         Settings swo = tech1->local_server_under_admin()->cd("system_wide_options", true);
  3679.  
  3680.         tech1->server.reset(new RpcServer);
  3681.         serverrm = endpoint_create();
  3682.         serverrm->evolve_into_server(tech1->server);
  3683.  
  3684.         std::string cert_str, pkey_str;
  3685.         {
  3686.             SettingsLock lock1(swo);
  3687.             cert_str = swo->get_value_string("ssl_cert");
  3688.             pkey_str = swo->get_value_string("ssl_pkey");
  3689.         }
  3690.  
  3691.         boost::shared_ptr<Endpoint> tmp = endpoint_create();
  3692.         tmp->evolve_into_server(tech1->server);
  3693.         {
  3694.             boost::mutex::scoped_lock sclock(rm_mutex);
  3695.             serverrm = tmp;
  3696.         }
  3697.  
  3698.         if(cert_str.empty() || pkey_str.empty()) {
  3699.             throw std::runtime_error("cannot read server certificate");
  3700.         }
  3701.  
  3702.         RpcConnection::asio_create_server(
  3703.             cert_str, pkey_str,
  3704.             tech1->system_wide_options()->ifaces_rpc,
  3705.             tech1->system_wide_options()->port_rpc,
  3706.             boost::dynamic_pointer_cast<RpcConnection::Server>(serverrm)
  3707.             );
  3708.  
  3709.         start_track_interfaces_change();
  3710.     } catch (const std::exception& e) {
  3711.         log_critical_error("NETSERVER: create server failed: %s\n", e.what());
  3712.         exit(1);
  3713.     }
  3714. }
  3715. #endif
  3716.  
  3717. extern void store_clientrm(const boost::shared_ptr<Rpc::Endpoint>&);
  3718.  
  3719. static
  3720. void lookup_initial_configuration(Settings& network_folder)
  3721. {
  3722.     FILE* f;
  3723.     try {
  3724.         f = open_or_die(webdog_custom_path_str, "rt");
  3725.         log_timestamp("CLOUD: reading '%s'\n", webdog_custom_path_str);
  3726.     } catch (const std::exception&) {
  3727.         return;
  3728.     }
  3729.     Settings local_server = tech1->local_server_under_admin();
  3730.     Settings swo = local_server->cd("system_wide_options", false);
  3731.     SettingsLock slock(network_folder);
  3732.     SettingsLock lock(swo);
  3733.     static boost::regex key_val("\\s*(\\w+)\\s*=\\s*([^\n]*)\n?");
  3734.     static boost::regex skip("(\\s*\n)|(\\s*#.*\n)");
  3735.     char buf[32768];
  3736.     size_t line = 0;
  3737.     while (fgets(buf, 32768, f)) {
  3738.         ++line;
  3739.         boost::cmatch what;
  3740.         if (boost::regex_match(buf, what, skip)) {
  3741.             continue;
  3742.         }
  3743.         if (!boost::regex_match(buf, what, key_val)) {
  3744.             log_warning("NETWORK: bad file \"%s\", can not parse line %d : %s\n", webdog_custom_path_str, line, buf);
  3745.             continue;
  3746.         }
  3747.         std::string val = what[2].str();
  3748.         int v = atoi(val.c_str());
  3749.         if (what[1].str()=="cloud_host" || what[1].str()=="cloud_address" ) {
  3750.             swo->set_value_string("cloud_address", val);
  3751.         } else if (what[1].str()=="automatic_update_url") {
  3752.             swo->set_value_string("automatic_update_url", val);
  3753.         } else if (what[1].str()=="cloud_connect_enable") {
  3754.             network_folder->set_value_integer("cloud_connect_enable", v);
  3755.         } else {
  3756.             log("NETWORK: parse file \"%s\" ignore line %d : %s\n", webdog_custom_path_str, line, buf);
  3757.         }
  3758.     }
  3759.     fclose(f);
  3760. }
  3761.  
  3762. void webdog_custom_erase()
  3763. {
  3764.     static bool skip = false;
  3765.     if (skip) return;
  3766.     skip = !boost::filesystem::exists(webdog_custom_path_str);
  3767.     if (skip) return;
  3768.  
  3769.     boost::system::error_code ec;
  3770.     boost::filesystem::remove(webdog_custom_path_str, ec);
  3771.     if (ec)
  3772.         log_warning("NETWORK: cannot erase '%s': %s\n", webdog_custom_path_str, ec.message().c_str());
  3773.     else
  3774.         log_timestamp("NETWORK: file '%s' erased\n", webdog_custom_path_str);
  3775. }
  3776.  
  3777. void net_client_after_load()
  3778. {
  3779.     client.reset(new RpcClient);
  3780.  
  3781.     boost::shared_ptr<Endpoint> tmp = endpoint_create();
  3782.     tmp->evolve_into_client(client);
  3783.     {
  3784.         boost::mutex::scoped_lock sclock(rm_mutex);
  3785.         clientrm = tmp;
  3786.     }
  3787.     store_clientrm(tmp);
  3788.  
  3789.     Settings local_server = tech1->local_server_under_admin();
  3790.  
  3791.     {
  3792.         SettingsLock lock(local_server);
  3793.         network_folder = local_server->dir_find("network", false);
  3794.         if (!network_folder) {
  3795.             network_folder = local_server->dir_create("network", NetworkFolder);
  3796.         }
  3797.     }
  3798.     lookup_initial_configuration(network_folder);
  3799.  
  3800.     local_operator_tracker.reset(new LocalOperatorTracker);
  3801.     cloudfolder = local_server->cd("cloud", false);
  3802.     cloudstat = cloudfolder->cd("stat", false);
  3803.     health = local_server->cd("health", false);
  3804.     if (!health) {
  3805.         log_critical_error("NETCLIENT: cannot find server health.\n");
  3806.     } else {
  3807.         SettingsLock lock(health);
  3808.         health->add_notification(local_operator_tracker, Dir::FIRE_VALUE_NOTIFICATION_NOW);
  3809.     }
  3810.  
  3811.     network_tracker.reset(new NetworkDirTracker);
  3812.  
  3813.     {
  3814.         SettingsLock lock(network_folder);
  3815.         network_folder->add_notification(network_tracker, Dir::WANT_ADD_REMOVE | Dir::FIRE_VALUE_NOTIFICATION_NOW);
  3816.         node_add_dot_dot_dot = network_folder->dir_create(
  3817.             "network_node_add",
  3818.             NetworkNodeAdd
  3819.             );
  3820.     }
  3821.  
  3822.     cloud_tracker.reset(new CloudTracker);
  3823.     {
  3824.         SettingsLock lock(cloudfolder);
  3825.         cloudfolder->add_notification(cloud_tracker, Constellation::Dir::FIRE_VALUE_NOTIFICATION_NOW);
  3826.     }
  3827.     cloud_stat_tracker.reset(new CloudStatTracker);
  3828.     {
  3829.         SettingsLock lock(cloudstat);
  3830.         cloudstat->add_notification(cloud_stat_tracker, Constellation::Dir::FIRE_VALUE_NOTIFICATION_NOW);
  3831.     }
  3832.     network_node_add_tracker.reset(new NetworkNodeAddTracker);
  3833.     {
  3834.         SettingsLock lock(node_add_dot_dot_dot);
  3835.         network_node_add_tracker->renew_next_node_id(lock);
  3836.         node_add_dot_dot_dot->add_notification(network_node_add_tracker, 0);
  3837.     }
  3838.  
  3839.     cloud_connect_after_load();
  3840. }
  3841.  
  3842. void network_done()
  3843. {
  3844.     cloud_connect_done();
  3845.  
  3846.     going_down = true;
  3847.     network_tracker.reset(); // used in client code, don't destroy until no other threads can access it
  3848.     NetworkNode.reset();
  3849.     NetworkNodeStats.reset();
  3850.     NetworkFolder.reset();
  3851.     NetworkNodeAdd.reset();
  3852.     NetworkNodeVirtual.reset();
  3853.  
  3854.     node_add_dot_dot_dot.reset();
  3855.     network_node_add_tracker.reset();
  3856.     cloud_stat_tracker.reset();
  3857.     cloud_tracker.reset();
  3858.     cloudstat.reset();
  3859.  
  3860.     boost::shared_ptr<AmergeRpcSession> empty_session;
  3861.     {
  3862.         boost::mutex::scoped_lock lock(amerge_session_mutex);
  3863.         amerge_session.swap(empty_session);
  3864.     }
  3865.     empty_session.reset();
  3866.  
  3867. #ifdef T1_SERVER
  3868.     if (serverrm) {
  3869.         stop_track_interfaces_change();
  3870.  
  3871.         try {
  3872.         RpcConnection::asio_destroy_server(
  3873.             boost::dynamic_pointer_cast<RpcConnection::Server>(serverrm));
  3874.         } catch (const std::exception& e) {
  3875.             log_warning("NETWORK: cannot destroy server: %s\n", e.what());
  3876.         }
  3877.     }
  3878. #endif
  3879.  
  3880.     {
  3881.         boost::mutex::scoped_lock lock(subscribers_mutex);
  3882.         network_addresses_subscribtions.clear();
  3883.     }
  3884.  
  3885.     RpcConnection::asio_cleanup();
  3886.  
  3887. #ifdef T1_SERVER
  3888.     if (serverrm) {
  3889.         serverrm->assert_empty();
  3890.         serverrm.reset();
  3891.         tech1->server->i_store_welcome.reset();
  3892.         tech1->server.reset();
  3893.     }
  3894. #endif
  3895.  
  3896.     boost::shared_ptr<Endpoint> tmp;
  3897.     {
  3898.         boost::mutex::scoped_lock sclock(rm_mutex);
  3899.         tmp.swap(clientrm);
  3900.     }
  3901.  
  3902.     if (tmp)
  3903.         tmp->assert_empty();
  3904.     tmp.reset();
  3905.     client.reset();
  3906.  
  3907.     tech1 = 0;
  3908.     root_under_admin.reset();
  3909.     network_folder.reset();
  3910.     health.reset();
  3911.     cloudfolder.reset();
  3912.  
  3913.     local_operator_tracker.reset();
  3914.  
  3915.     voting_registry.clear(); // weak_ptr-s should be freed too before DLL unload
  3916. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement