Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <rpc-endpoint.h>
- #include <rpc-connection.h>
- #include <t1.h>
- #include "../version.h"
- #include <t1-network.h>
- #include <t1enums.h>
- #include <objects-service.h>
- #include "serverobject.h"
- #include "certificates.h"
- #include "../generated/tech1network-rpc-main.h"
- #include <boost/thread.hpp>
- #include <boost/enable_shared_from_this.hpp>
- #include <boost/filesystem/convenience.hpp>
- #include <boost/regex.hpp>
- #include <fileutils.h>
- #include <stringutils.h>
- #include <timeutils.h>
- #include <socketutils.h>
- #include <crypto-utils.h>
- #include <jsonutils.h>
- #include <map>
- const char* webdog_custom_path_str = "webdog-custom.txt";
- using namespace Constellation;
- static Tech1* tech1;
- extern EventType event_connected_to;
- extern EventType event_disconnected_from;
- // prototypes
- static Settings root_under_admin;
- static Settings network_folder;
- Settings NetworkNode; // used in webview.cpp
- static Settings NetworkFolder;
- static Settings NetworkNodeStats;
- static Settings NetworkNodeVirtual;
- static Settings NetworkNodeAdd;
- static Settings node_add_dot_dot_dot;
- static bool going_down = false;
- static const std::list<std::string> whitelist_economy(csv_explode(
- "LocalServer,RemoteServer,ChannelsFolder,Channel,ChannelInfo,TemplatesFolder,Template,Map,MapLevel,SystemWideOptions,Health"));
- static const std::list<std::string> whitelist_cloud(csv_explode(
- "LocalServer,ChannelsFolder,Channel,ChannelInfo,ChannelFlags,ChannelStats,IpCamerasFolder,Grabber,GrabberCaps,ZoneCaps,GrabberFeedback"));
- static const std::list<std::string> whitelist_amerge(
- csv_explode("LocalServer"));
- // stornix
- static const std::list<std::string> blacklist_cluster2client(
- csv_explode("StornixVolumeStat,StornixDisksStat,NetworkFolder"));
- static const std::list<std::string> blacklist_cluster2cluster(
- csv_explode("Health,Cloud,Audit,NetworkFolder,TimeSetup"));
- class NetworkDirTracker;
- static boost::shared_ptr<NetworkDirTracker> network_tracker;
- class NetworkNodeAddTracker;
- static boost::shared_ptr<NetworkNodeAddTracker> network_node_add_tracker;
- static boost::mutex amerge_session_mutex;
- static boost::shared_ptr<class AmergeRpcSession> amerge_session;
- static boost::mutex rm_mutex;
- static boost::shared_ptr<Endpoint> clientrm;
- static boost::shared_ptr<Endpoint> serverrm;
- class RpcClient;
- class RpcServer;
- static boost::shared_ptr<RpcClient> client;
- class LocalOperatorTracker;
- static boost::shared_ptr<LocalOperatorTracker> local_operator_tracker;
- static void update_node_ip_callback(int64_t session_id, const std::string& ip_address);
- static void update_node_address_callback(int64_t session_id, const std::string& ip_address, int port_rpc, int port_video);
- static void socket_error_callback(int64_t session_id, const std::string& error_message);
- extern void netclient_found_remote_service( // will hold reference on service
- const std::string& key,
- const Settings& network_node,
- const boost::shared_ptr<Interface>& service
- );
- extern void netclient_lost_remote_service(
- const std::string& key
- );
- extern void netclient_lost_all_services_for_node(
- const Settings& network_node
- );
- extern void netserver_add_remote_service_list_receiver(
- const std::string& required_server_guid,
- const boost::shared_ptr<NetClientDir>& client,
- const Settings& root_under_client_user,
- bool economy_mode
- );
- extern int64_t rpc_inject_socket(const boost::shared_ptr<CloudConnectSocket>&, Rpc::Callbacks session_callbacks);
- // cloud-connect
- extern void cloud_connect_init(Tech1* t1);
- extern void cloud_connect_after_load();
- extern void cloud_connect_done();
- extern void client_cloud_connect(const boost::shared_ptr<CloudConnectRequest>& request);
- extern void cloud_disconnect(const std::string& server_id);
- bool is_cc_t1cloud_folder(const std::string& name)
- {
- return name.substr(0, 12) == "cloudtrassir";
- }
- std::string get_cc_t1cloud_foldername(const std::string& accountid)
- {
- return "cloudtrassir" + accountid;
- }
- bool is_cc_to_t1cloud(const std::string& name)
- {
- return name.substr(0, 8) == "vtrassir";
- }
- std::string get_cc_cloudid_for_t1cloud(const std::string& accountid)
- {
- return "vtrassir" + accountid;
- }
- static
- std::string extract_address_from_name(const std::string& name)
- {
- std::string ip = name.substr(name.find_last_of("(") + 1);
- if (!ip.empty()) {
- ip = ip.substr(0, ip.find_last_of(")"));
- }
- return ip;
- }
- extern void cloud_client_start_thread(const Settings& user);
- extern void cloud_client_logout();
- static
- void create_network_prototypes(const Settings& root)
- {
- {
- SettingsLock lock(root);
- NetworkNode = root->dir_create("NetworkNode", Settings());
- NetworkNodeStats = root->dir_create("NetworkNodeStats", Settings());
- NetworkNodeAdd = root->dir_create("NetworkNodeAdd", Settings());
- NetworkFolder = root->dir_create("NetworkFolder", Settings());
- NetworkNodeVirtual = root->dir_create("NetworkNodeVirtual", NetworkNode);
- }
- for (int i=0; i<2; ++i) {
- Settings nn = i==0 ? NetworkNode : NetworkNodeVirtual;
- SettingsLock lock(nn);
- nn->create_value_string("origin_account", RIGHTS_VIEW, RIGHTS_ROOT, "");
- nn->create_value_string("name", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
- nn->create_value_string("ip_address", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
- nn->create_value_string("ip_addresses", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
- nn->create_value_string("accepted_fingerprint", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
- nn->create_value_integer("port_rpc", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, 3080);
- nn->create_value_integer("port_video", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, 3081);
- nn->create_value_string("username", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
- nn->create_value_string("password", RIGHTS_PASSWORD, RIGHTS_SETUP, "");
- nn->create_value_integer("should_be_connected", RIGHTS_VIEW, RIGHTS_SETUP, 1);
- nn->create_value_integer("economy_mode", RIGHTS_VIEW, RIGHTS_SETUP, 0);
- nn->create_value_integer("network_recurse_level", RIGHTS_VIEW, RIGHTS_SETUP, 1);
- nn->create_value_integer("relay_count", RIGHTS_VIEW, RIGHTS_ROOT, 0);
- nn->create_value_integer("buffering", RIGHTS_VIEW, RIGHTS_SETUP, 0);
- nn->create_value_integer("disable_mainstream", RIGHTS_VIEW, RIGHTS_SETUP, 0);
- nn->create_value_string("icon", RIGHTS_VIEW, RIGHTS_ROOT, ":/settings/server.gif");
- nn->create_value_string("reachable_via_this_node", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_ROOT, "");
- nn->create_value_string("last_cc_timestamp", RIGHTS_VIEW, RIGHTS_SETUP, "0");
- nn->create_value_integer("address_from_cc_success", RIGHTS_VIEW, RIGHTS_SETUP, 0);
- nn->create_value_integer("use_cloud_connect", RIGHTS_VIEW, RIGHTS_SETUP, 0);
- nn->create_value_string("cloud_id", RIGHTS_VIEW|RIGHTS_SENSITIVE, RIGHTS_SETUP, "");
- nn->create_value_integer("autocredentials", RIGHTS_VIEW, RIGHTS_SETUP, 0);
- nn->create_value_integer("generated", RIGHTS_VIEW, RIGHTS_SETUP, 0);
- nn->evolve_into_prototype(
- Dir::SAVE_TO_DISK|
- Dir::TRANSMIT_TO_CLIENT|
- (i==0 ? Dir::SHOW_IN_TREE : 0)|
- Dir::CDEF_IGNORE|
- Dir::ACL_VIEW|Dir::ACL_SETUP
- );
- }
- {
- SettingsLock lock(NetworkNodeStats);
- NetworkNodeStats->create_value_string("fingerprint", RIGHTS_VIEW, RIGHTS_ROOT, "");
- NetworkNodeStats->create_value_integer("connected", RIGHTS_VIEW, RIGHTS_ROOT, 0);
- NetworkNodeStats->create_value_string("last_error", RIGHTS_VIEW, RIGHTS_ROOT, "");
- NetworkNodeStats->create_value_string("resolve_warning", RIGHTS_VIEW, RIGHTS_ROOT, "");
- NetworkNodeStats->create_value_string("connected_using", RIGHTS_VIEW, RIGHTS_ROOT, "");
- NetworkNodeStats->evolve_into_prototype(
- Dir::TRANSMIT_TO_CLIENT|
- Dir::CDEF_IGNORE
- );
- }
- {
- SettingsLock lock(NetworkNodeAdd);
- NetworkNodeAdd->create_value_string("new_node_id", RIGHTS_SETUP, RIGHTS_SETUP, "");
- NetworkNodeAdd->create_value_string("new_origin_account", RIGHTS_SETUP, RIGHTS_SETUP, "");
- NetworkNodeAdd->create_value_string("new_node_name", RIGHTS_SETUP, RIGHTS_SETUP, "");
- NetworkNodeAdd->create_value_integer("new_node_port_rpc", RIGHTS_SETUP, RIGHTS_SETUP, 3080);
- NetworkNodeAdd->create_value_integer("new_node_port_video", RIGHTS_SETUP, RIGHTS_SETUP, 3081);
- NetworkNodeAdd->create_value_string("new_node_username", RIGHTS_ROOT, RIGHTS_SETUP, "");
- NetworkNodeAdd->create_value_string("new_node_password", RIGHTS_PASSWORD, RIGHTS_SETUP, "");
- NetworkNodeAdd->create_value_integer("create_now", RIGHTS_ROOT, RIGHTS_SETUP, 0);
- NetworkNodeAdd->create_value_string("delete_node_id", RIGHTS_ROOT, RIGHTS_SETUP, "");
- NetworkNodeAdd->create_value_integer("new_node_use_cloud_connect", RIGHTS_ROOT, RIGHTS_SETUP, 0);
- NetworkNodeAdd->create_value_string("new_node_cloud_id", RIGHTS_ROOT, RIGHTS_SETUP, "");
- NetworkNodeAdd->create_value_integer("new_node_generated", RIGHTS_VIEW, RIGHTS_SETUP, 0);
- NetworkNodeAdd->create_value_integer("new_node_autocredentials", RIGHTS_VIEW, RIGHTS_SETUP, 0);
- NetworkNodeAdd->create_value_integer("new_node_economy", RIGHTS_VIEW, RIGHTS_SETUP, 0);
- NetworkNodeAdd->evolve_into_prototype(
- Dir::TRANSMIT_TO_CLIENT|
- Dir::SHOW_IN_TREE
- );
- }
- {
- SettingsLock lock(NetworkFolder);
- NetworkFolder->create_value_string("icon", 0, RIGHTS_ROOT, ":/settings/setup-network.png");
- NetworkFolder->create_value_integer("cloud_connect_enable", RIGHTS_VIEW, RIGHTS_SETUP, 0);
- NetworkFolder->create_value_string("upnp_gate", RIGHTS_VIEW, RIGHTS_SETUP, "discovering");
- NetworkFolder->create_value_integer("limit_client_count", RIGHTS_VIEW, RIGHTS_SETUP, 100);
- NetworkFolder->create_value_string("offline_passwords", RIGHTS_PASSWORD, RIGHTS_ROOT, "");
- NetworkFolder->evolve_into_prototype(
- Dir::SAVE_TO_DISK|
- Dir::TRANSMIT_TO_CLIENT|
- Dir::SHOW_IN_TREE|
- Dir::FORCE_SUBOBJECTS_FIND|
- Dir::ACL_VIEW|Dir::ACL_SETUP
- );
- }
- }
- struct PasswordData
- {
- std::string server_guid;
- std::string offline_password;
- uint64_t last_successful_login_ts;
- PasswordData(const std::string& server_guid, const std::string& password, uint64_t ts):
- server_guid(server_guid),
- offline_password(password),
- last_successful_login_ts(ts)
- {}
- };
- static std::string password_data_list_to_string(const std::list<PasswordData>& pass_data)
- {
- std::string s;
- std::list<PasswordData>::const_iterator x;
- for (x=pass_data.begin(); x!= pass_data.end(); ++x) {
- if (!s.empty())
- s += ",";
- s += escape_string(x->server_guid);
- s += "," + escape_string(x->offline_password);
- s += "," + escape_string(print_uint64(x->last_successful_login_ts));
- }
- return s;
- }
- static std::list<PasswordData> string_to_password_data_list(const std::string& s)
- {
- std::list<PasswordData> list;
- std::istringstream i(s);
- for (std::string split; std::getline(i, split, ','); ) {
- std::string id = unescape_string(split);
- if (!std::getline(i, split, ',')) break;
- std::string pass = unescape_string(split);
- if (!std::getline(i, split, ',')) break;
- uint64_t ts = scan_uint64(unescape_string(split));
- list.push_back( PasswordData(id, pass, ts) );
- }
- return list;
- }
- // server dir
- class ServerDirReal: // remote user agent
- public Dir::Notification,
- public NetServerDir,
- public boost::enable_shared_from_this<ServerDirReal>
- {
- public:
- Settings dir_under_remote_user;
- bool erased;
- int recursion_limit;
- bool i_am_root_server_finder;
- bool i_am_cluster;
- const std::list<std::string>* folders_whitelist;
- const std::list<std::string>* folders_blacklist;
- boost::mutex remote_client_mutex;
- boost::shared_ptr<NetClientDir> fragile_remote_client_dir;
- boost::shared_ptr<NetClientServiceListReceiver> fragile_service_client;
- ServerDirReal(const Settings& dir_under_remote_user):
- Dir::Notification("ServerDir"),
- dir_under_remote_user(dir_under_remote_user),
- erased(false),
- i_am_root_server_finder(false),
- i_am_cluster(false),
- recursion_limit(-1),
- folders_whitelist(0),
- folders_blacklist(0)
- {
- }
- boost::shared_ptr<NetClientDir> client_still_alive()
- {
- boost::mutex::scoped_lock lock(remote_client_mutex);
- return fragile_remote_client_dir;
- }
- boost::shared_ptr<NetClientServiceListReceiver> service_client_still_alive()
- {
- boost::mutex::scoped_lock lock(remote_client_mutex);
- return fragile_service_client;
- }
- boost::mutex subtrackers_mutex;
- std::map< std::string, boost::shared_ptr<ServerDirReal> > subtrackers;
- void constellation_folder_added(
- const Settings& tracked_dir,
- const Settings& new_folder)
- {
- if (new_folder->is_prototype()) return;
- new_folder->this_is_used_from_network_folder();
- if (folders_whitelist)
- if (std::find(folders_whitelist->begin(), folders_whitelist->end(), new_folder->prototype_name())
- ==folders_whitelist->end()) return;
- if (folders_blacklist)
- if (std::find(folders_blacklist->begin(), folders_blacklist->end(), new_folder->prototype_name())
- !=folders_blacklist->end()) return;
- const int current_level = new_folder->network_recurse_level();
- if (current_level >= recursion_limit) return;
- const uint32_t options = new_folder->options();
- if (!(options & Dir::TRANSMIT_TO_CLIENT)) return;
- if (new_folder->name()=="info_unfiltered") return;
- //log("NETSERVER: discovered folder %i %s\n", new_folder->network_recurse_level(), new_folder->path().c_str() );
- boost::shared_ptr<ServerDirReal> new_server_dir(
- new ServerDirReal(new_folder)
- );
- new_server_dir->folders_whitelist = folders_whitelist;
- new_server_dir->folders_blacklist = folders_blacklist;
- new_server_dir->i_am_cluster = i_am_cluster;
- new_server_dir->recursion_limit = recursion_limit;
- {
- boost::mutex::scoped_lock sublock(subtrackers_mutex);
- std::map< std::string, boost::shared_ptr<ServerDirReal> >::iterator i = subtrackers.find(new_folder->name());
- assert( i==subtrackers.end() );
- subtrackers[new_folder->name()] = new_server_dir;
- }
- if (i_am_root_server_finder) {
- boost::shared_ptr<NetClientServiceListReceiver> sc = service_client_still_alive();
- if (sc && (new_folder->prototype_name()=="RemoteServer" || new_folder->prototype_name()=="LocalServer")) {
- std::string route;
- std::string name;
- std::string cluster_node_guid;
- {
- SettingsLock lock(new_folder);
- route = new_folder->get_value_string("media_route");
- name = new_folder->get_value_string("name");
- if (new_folder->prototype_name() == "LocalServer")
- cluster_node_guid = new_folder->get_value_string("cluster_node_guid");
- }
- std::string whitelist;
- if (!(tech1->have_mini() && "Admin" == dir_under_remote_user->user_id())) {
- SettingsLock lock(new_folder);
- whitelist = new_folder->get_value_string("whitelist");
- }
- sc->whitelist_send(new_folder->name(), whitelist);
- sc->add_server(
- i_am_cluster ? cluster_node_guid : new_folder->name(),
- name,
- route,
- new_server_dir,
- current_level + 1
- );
- } else
- log("NETSERVER: folder_added bug, cannot send path %s\n", new_folder->path().c_str());
- } else {
- boost::shared_ptr<NetClientDir> remote_client = client_still_alive();
- if (remote_client) {
- const std::string& prototype_name = new_folder->prototype_name();
- boost::shared_ptr<FakeW> fake = boost::dynamic_pointer_cast<FakeW>(remote_client);
- if (fake) {
- boost::shared_ptr<SessionW> session = fake->session_get();
- int32_t h = our_hash_impl(prototype_name);
- std::set<int32_t>::iterator hi = session->constellation_prototype_introduced.find(h);
- if (hi == session->constellation_prototype_introduced.end()) {
- session->constellation_prototype_introduced.insert(h);
- Settings prototype;
- {
- SettingsLock lock(root_under_admin);
- prototype = root_under_admin->dir_find_prototype(prototype_name);
- }
- assert(prototype);
- Json::Value desc = Json::objectValue;
- desc["fields"] = Json::arrayValue;
- {
- SettingsLock lock(prototype);
- desc["options"] = prototype->options();
- std::list<std::string> fields = prototype->ls_values();
- std::list<std::string>::iterator it;
- for (it = fields.begin(); it != fields.end(); ++it) {
- const std::string& field = *it;
- Json::Value field_desc = Json::objectValue;
- field_desc["name"] = field;
- char type = prototype->type_of(field);
- field_desc["type"] = std::string(&type, 1);
- switch (type) {
- case 's':
- field_desc["default"] = prototype->get_value_string(field);
- break;
- case 'i':
- field_desc["default"] = prototype->get_value_integer(field);
- break;
- case 'r':
- field_desc["default"] = prototype->get_value_real(field);
- break;
- default:
- log_warning("FOLDER PROTOTYPE BAD: %s(%c)\n", field.c_str(), type);
- }
- desc["fields"].append(field_desc);
- }
- }
- remote_client->add_prototype(
- new_folder->prototype_name(),
- Json::FastWriter().write(desc)
- );
- }
- }
- remote_client->add_folder(
- new_folder->name(),
- new_folder->prototype_name(),
- new_server_dir,
- new_folder->rights(),
- current_level + 1);
- } else
- log("NETSERVER: cannot send folder %s to client\n", new_folder->path().c_str());
- }
- }
- void constellation_folder_removed(
- const Settings& tracked_dir,
- const Settings& removed_folder)
- {
- const std::string& id = removed_folder->name();
- {
- boost::mutex::scoped_lock sublock(subtrackers_mutex);
- std::map< std::string, boost::shared_ptr<ServerDirReal> >::iterator i = subtrackers.find(id);
- if ( i==subtrackers.end() ) return; // never added, because of no TRANSMIT_TO_CLIENT flag
- boost::shared_ptr<NetClientDir> remote_client = client_still_alive();
- if (remote_client) {
- remote_client->remove_folder(removed_folder->name());
- } else {
- log("NETSERVER: cannot remove folder %s from client\n", removed_folder->path().c_str());
- }
- boost::shared_ptr<ServerDirReal>& my_subtracker = i->second;
- { // tear down circular client-server links
- boost::mutex::scoped_lock lock(my_subtracker->remote_client_mutex);
- my_subtracker->fragile_remote_client_dir.reset();
- }
- subtrackers.erase(i);
- }
- }
- void constellation_tracked_dir_erased(const Settings& tracked_dir)
- {
- boost::mutex::scoped_lock lock(remote_client_mutex);
- fragile_remote_client_dir.reset();
- erased = true;
- }
- // from network
- void pass_dir_receiver(const boost::shared_ptr<NetClientDir>& new_cd)
- {
- if (!new_cd) {
- log("NETWORK: ERROR: pass_dir_receiver() bug\n");
- return;
- }
- boost::mutex::scoped_lock lock(remote_client_mutex);
- if (!erased) {
- fragile_remote_client_dir = new_cd;
- }
- }
- // top-level role, called from login
- void pass_server_receiver(const boost::shared_ptr<NetClientServiceListReceiver>& new_sc)
- {
- assert(new_sc);
- boost::mutex::scoped_lock lock(remote_client_mutex);
- if (!erased)
- fragile_service_client = new_sc;
- }
- bool is_server(const Settings& s)
- {
- const std::string& protoname = s->prototype_name();
- bool it_is = false;
- it_is |= protoname=="LocalServer";
- it_is |= protoname=="RemoteServer";
- return it_is;
- }
- // from network
- void client2server_start_work()
- {
- if (is_server(dir_under_remote_user)) {
- boost::mutex::scoped_lock lock(remote_client_mutex);
- if (!fragile_remote_client_dir) {
- log_warning("NETWORK: no client in client2server_start_work()\n");
- return;
- }
- netserver_add_remote_service_list_receiver(
- dir_under_remote_user->name(),
- fragile_remote_client_dir,
- dir_under_remote_user->cd("/", true),
- !!folders_whitelist
- );
- }
- SettingsLock lock(dir_under_remote_user);
- dir_under_remote_user->add_notification(shared_from_this(),
- Dir::WANT_ADD_REMOVE|
- Dir::WANT_RIGHTS_CHANGE|
- Dir::FIRE_VALUE_NOTIFICATION_NOW|
- Dir::WANT_NETWORK_SERIALIZATION|
- Dir::WANT_NETWORK_SERVER2CLIENT|
- (i_am_cluster ? Dir::WANT_NETWORK_CLUSTER2CLUSTER : 0)
- );
- }
- // from network
- void client2server_stop_work()
- {
- {
- SettingsLock lock(dir_under_remote_user);
- dir_under_remote_user->notification_remove(shared_from_this());
- }
- {
- log_timestamp("NETSERVER: disconnected client\n");
- // TODO: reverse function for netserver_add_remote_service_list_receiver()
- }
- std::map< std::string, boost::shared_ptr<ServerDirReal> > tmp;
- {
- boost::mutex::scoped_lock sublock(subtrackers_mutex);
- tmp.swap(subtrackers); // equivalent to constellation_folder_removed() all
- }
- }
- // from network
- void client2server_value_changes(const std::string& s)
- {
- if (i_am_cluster) {
- log_warning("CLUSTER SHOULD NOT DO THAT: %s\n", s.c_str());
- return;
- }
- boost::shared_ptr<NetClientDir> remote_client = client_still_alive();
- std::string tmp = s.substr(s.find("/"));
- std::string dir = tmp.substr(0, tmp.find(" "));
- tmp = tmp.substr(tmp.find("\n") + 1);
- tmp = tmp.substr(tmp.find("\n") + 1);
- while (true) {
- std::string key = tmp.substr(0, tmp.find(" "));
- tmp = tmp.substr(tmp.find(" ") + 1);
- tmp = tmp.substr(tmp.find_first_not_of(" "));
- size_t lb_pos = tmp.find("\n");
- std::string value = tmp.substr(0, lb_pos);
- tech1->useraction_log("SETTINGS/SET", remote_client, "~operator",
- "%s/%s = %s", dir.c_str(), key.c_str(), value.c_str());
- tmp = tmp.substr(lb_pos + 1);
- if (tmp.empty())
- break;
- }
- SettingsLock lock(dir_under_remote_user);
- std::istringstream i2(s);
- for (std::string split; std::getline(i2, split, '\n'); ) {
- if (split.empty()) continue;
- if (split[0]=='#') continue;
- log("FROM CLIENT: '%s'\n", split.c_str());
- std::string::size_type pos = split.find(' ');
- if (pos==std::string::npos) {
- log("NETSERVER: cannot parse value update from client: '%s'\n", split.c_str());
- continue;
- }
- std::string key = split.substr(0, pos);
- std::string::size_type size = split.size();
- while (pos<size && split[pos]==' ')
- ++pos;
- try {
- dir_under_remote_user->network_unserialize_client2server_value(
- #ifdef T1_SERVER
- dir_under_remote_user->hash(key),
- #else
- key,
- #endif
- key,
- split.c_str() + pos
- );
- } catch (const std::logic_error& e) {
- log("NETSERVER: %s\n", e.what());
- // nothing we can do here but complain to logs, client is untrusted
- continue;
- }
- }
- }
- void constellation_folder_adjust_before_serialization(const Settings& serialized_dir, std::map<std::string, std::string>& values_to_add_or_replace)
- {
- /*if (serialized_dir->prototype_name() == "ChannelInfo") {
- values_to_add_or_replace["restrictions"] = "sample text";
- }*/ // final
- if (serialized_dir->prototype_name() == "Channel") {
- values_to_add_or_replace["playback_time"] = "{completely broken}";
- }
- }
- void constellation_network_serialization(int rev, const std::string& serialization)
- {
- log_warning("\n-------\n%s\n-------\n", serialization.c_str());
- boost::shared_ptr<NetClientDir> remote_client = client_still_alive();
- if (remote_client)
- remote_client->update_values(rev, serialization);
- }
- void constellation_effective_rights_changed(const Settings& tracked_dir)
- {
- //log("ERC!\n");
- boost::shared_ptr<NetClientDir> remote_client = client_still_alive();
- if (remote_client)
- remote_client->update_effective_rights(tracked_dir->rights());
- }
- };
- // client dir
- class ClientDirReal:
- public boost::enable_shared_from_this<ClientDirReal>,
- public Constellation::Dir::Notification,
- public NetClientDir
- {
- public:
- boost::mutex dirs_mutex;
- Settings i_serve_here; // under admin
- bool subscribed_on_client2server;
- boost::shared_ptr<NetServerDir> my_server_dir;
- Settings filtered_channel_info;
- bool i_work_as_root;
- bool i_work_as_tier_server;
- boost::weak_ptr<class NetworkNodeTracker> network_node;
- ClientDirReal(
- const Settings& i_serve_here,
- const boost::shared_ptr<NetServerDir>& server_dir,
- const boost::shared_ptr<NetworkNodeTracker>& network_node)
- :
- Constellation::Dir::Notification("ClientDir"),
- i_serve_here(i_serve_here),
- my_server_dir(server_dir),
- network_node(network_node),
- i_work_as_root(false),
- i_work_as_tier_server(false)
- {
- subscribed_on_client2server = false;
- // my_server_dir is 0 here only if we serve at root, but we will set later, see keep_reference_on_root_folder()
- }
- ~ClientDirReal()
- {
- if (i_work_as_tier_server) return;
- Settings my_parent = i_serve_here->parent();
- if (!i_work_as_root) {
- try {
- SettingsLock lock(my_parent);
- my_parent->dir_remove(i_serve_here->name());
- if (filtered_channel_info)
- my_parent->dir_remove(filtered_channel_info->name());
- } catch (const not_found_error&) {
- // log("ClientDirReal: destruction reordering, normal?\n");
- }
- }
- }
- // from network
- void update_values(int rev, const std::string& s)
- {
- if (i_work_as_tier_server)
- return;
- if (i_work_as_root) {
- log("NETCLIENT: ERROR: update_values() on root folder, malicious server?\n");
- return;
- }
- Settings serve_here_copy;
- {
- boost::mutex::scoped_lock dirs_lock(dirs_mutex);
- serve_here_copy = i_serve_here;
- }
- if (!serve_here_copy) return; // lost the vote
- SettingsLock lock(serve_here_copy);
- serve_here_copy->network_unserialize_server2client_values(1000+rev, s, false, false);
- if (filtered_channel_info) {
- SettingsLock lock2(filtered_channel_info);
- implement_disable_mainstream(filtered_channel_info, serve_here_copy);
- }
- if (!subscribed_on_client2server) {
- subscribed_on_client2server = true;
- serve_here_copy->add_notification(shared_from_this(), Dir::WANT_NETWORK_SERIALIZATION);
- }
- }
- void implement_disable_mainstream(const Settings& channel_info_locked, const Settings& unfiltered_channel_info);
- // from network
- void add_folder(
- const std::string& folder_name,
- const std::string& prototype_name,
- const boost::shared_ptr<NetServerDir>& server_dir,
- uint32_t rights,
- int recurse_level)
- {
- if (recurse_level<=0 || recurse_level>7) {
- log_warning("NETCLIENT: bad recurse level %i\n", recurse_level);
- return;
- }
- Settings new_dir;
- Settings prototype;
- {
- SettingsLock lock(root_under_admin);
- prototype = root_under_admin->dir_find_prototype(prototype_name);
- if (!prototype) {
- log_warning("CLIENTNET: add_folder() cannot find prototype '%s'\n", prototype_name.c_str());
- return;
- }
- }
- boost::mutex::scoped_lock dirs_lock(dirs_mutex);
- boost::shared_ptr<NetworkNodeTracker> node = network_node.lock();
- if (!node) return; // race vs shutdown
- if (!i_serve_here) return; // can be changed in i_work_as_tier_server mode
- boost::shared_ptr<ClientDirReal> new_client_dir;
- //log("CLIENT: %s add_folder(%s)\n", i_serve_here->path().c_str(), folder_name.c_str());
- try {
- bool special_info_mode = prototype->name()=="ChannelInfo";
- std::string create_folder_name = folder_name;
- if (special_info_mode && folder_name=="info")
- create_folder_name = "info_unfiltered";
- {
- SettingsLock lock(i_serve_here);
- new_dir = i_serve_here->dir_create(create_folder_name, prototype);
- new_client_dir.reset(new ClientDirReal(new_dir, server_dir, node));
- if (special_info_mode)
- new_client_dir->filtered_channel_info = i_serve_here->dir_create(
- "info",
- tech1->common_prototypes()->ChannelInfo);
- }
- new_dir->this_is_network_folder(rights, recurse_level);
- } catch (const std::logic_error& e) {
- // bad folder_name, etc
- log("CLIENT: add_folder() cannot create folder: %s\n", e.what());
- return;
- }
- server_dir->pass_dir_receiver(new_client_dir);
- server_dir->client2server_start_work();
- }
- // from network
- void remove_folder(const std::string& folder_name)
- {
- }
- // from network
- void initial_add_completed()
- {
- i_serve_here->fire_initial_add_completed_notification();
- }
- void constellation_tracked_dir_erased(const Settings& tracked_dir)
- {
- // by parent (disconnect)
- }
- // from network
- void update_effective_rights(uint32_t rights)
- {
- if (!i_work_as_root && !i_work_as_tier_server) {
- Settings serve_here_copy;
- {
- boost::mutex::scoped_lock dirs_lock(dirs_mutex);
- serve_here_copy = i_serve_here;
- }
- if (!serve_here_copy) return; // lost the vote
- //log("S2C %s: 0x%x\n", i_serve_here->path().c_str(), rights);
- serve_here_copy->this_is_network_folder(rights, -1);
- if (filtered_channel_info) {
- SettingsLock lock(serve_here_copy);
- SettingsLock lock2(filtered_channel_info);
- implement_disable_mainstream(filtered_channel_info, serve_here_copy);
- }
- }
- }
- void constellation_network_serialization(int rev, const std::string& serialization)
- {
- // Value revision from network always >= 1000.
- // If client starts editing values before first server revision arrives, don't send it.
- if (rev < 1000)
- return; // set breakpoint here to see who edits values before first update from server
- my_server_dir->client2server_value_changes(serialization);
- }
- void add_service(const boost::shared_ptr<Interface>& service)
- {
- log_warning("NetClientDir: add_service()\n");
- }
- void remove_service(const boost::shared_ptr<Interface>& service)
- {
- log_warning("NetClientDir: remove_service()\n");
- }
- void remove_service_v2(const std::string& name)
- {
- log_warning("NetClientDir: remove_service_v2()\n");
- }
- };
- // Voting: netclient memory db for choosing a way to connect to a server
- struct VotingRecord {
- int recurse_level; // lower is better
- int relay_count; // lower is better
- Settings network_node;
- boost::weak_ptr<class ServerProvider> server_provider;
- class ServerProvider* server_provider_dangerous_pointer;
- };
- static bool compare_votes(const VotingRecord& lhs, const VotingRecord& rhs)
- {
- if (lhs.relay_count == rhs.relay_count)
- return lhs.recurse_level < rhs.recurse_level;
- return lhs.relay_count < rhs.relay_count;
- }
- class VotingServerContext:
- public Constellation::Dir::Notification
- {
- public:
- boost::mutex server_voting_mutex;
- std::string server_guid;
- Settings remote_server;
- boost::weak_ptr<class ServerProvider> vote_winner;
- std::list<VotingRecord> votes;
- void sort()
- {
- votes.sort(&compare_votes);
- }
- VotingServerContext(const std::string& server_guid);
- ~VotingServerContext();
- void decide_who_should_proceed();
- // nothing tracked, called only using fire_values_notification()
- void constellation_values_changed(const Settings& tracked_dir)
- {
- decide_who_should_proceed();
- }
- };
- static boost::mutex voting_registry_mutex;
- static std::map< std::string, boost::weak_ptr<VotingServerContext> > voting_registry;
- // server provider: creates and maintains remote server subtree
- class ServerProvider:
- public Constellation::Dir::Notification
- {
- protected:
- Settings node_dir;
- boost::mutex voting_ptr_mutex; // voting_cx and remote_welcome is not read-only
- boost::shared_ptr<VotingServerContext> voting_cx; // unknown until first connect
- bool i_am_providing_the_server;
- public:
- int recurse_level;
- ServerProvider(int recurse_level):
- Constellation::Dir::Notification("ServerProvider"),
- recurse_level(recurse_level)
- {
- i_am_providing_the_server = false;
- }
- void add_me_to_voting_cx(
- const std::string& server_guid,
- const boost::shared_ptr<ServerProvider>& myself
- )
- {
- // socket thread
- bool just_created = false;
- boost::shared_ptr<VotingServerContext> new_vcx;
- {
- boost::mutex::scoped_lock lock(voting_registry_mutex);
- std::map< std::string, boost::weak_ptr<VotingServerContext> >::iterator x;
- x = voting_registry.find(server_guid);
- if (x!=voting_registry.end())
- new_vcx = x->second.lock();
- if (!new_vcx) {
- new_vcx.reset(new VotingServerContext(server_guid)); // exception if bad guid
- voting_registry[server_guid] = new_vcx;
- just_created = true;
- }
- }
- {
- boost::mutex::scoped_lock lock1(voting_ptr_mutex);
- if (voting_cx) {
- log_warning("NETCLIENT: add_me_to_voting_cx() bug\n");
- return;
- }
- voting_cx = new_vcx;
- boost::mutex::scoped_lock lock2(voting_cx->server_voting_mutex);
- VotingRecord r;
- r.network_node = node_dir;
- r.server_provider = myself;
- r.server_provider_dangerous_pointer = this;
- assert(myself.get()==this);
- r.recurse_level = myself->recurse_level;
- voting_cx->votes.push_back(r);
- }
- if (just_created) {
- SettingsLock lock(root_under_admin);
- root_under_admin->add_notification(new_vcx, 0);
- }
- root_under_admin->fire_values_notification(new_vcx);
- }
- // called from disconnect (socket thread or destructor)
- void remove_me_from_voting_cx()
- {
- // any thread
- boost::mutex::scoped_lock lock1(voting_ptr_mutex);
- boost::shared_ptr<VotingServerContext> my_voting_cx;
- {
- if (!voting_cx) return;
- my_voting_cx.swap(voting_cx);
- boost::mutex::scoped_lock lock2(my_voting_cx->server_voting_mutex);
- std::list<VotingRecord>::iterator x;
- for (x=my_voting_cx->votes.begin(); x!=my_voting_cx->votes.end(); ++x) {
- const VotingRecord& r = *x;
- if (r.server_provider_dangerous_pointer==this) {
- //if (r.network_node==node_dir) {
- my_voting_cx->votes.erase(x);
- root_under_admin->fire_values_notification(my_voting_cx);
- return;
- }
- }
- }
- log_critical_error("NETCLIENT: remove_me_from_voting_cx() bug\n");
- }
- bool provide_server_start(
- const std::string& reasonable_name,
- const std::string& route,
- int recurse_level)
- {
- node_dir->assert_notify_thread();
- boost::mutex::scoped_lock lock1(voting_ptr_mutex);
- if (!voting_cx) return false; // suddenly disconnected, well, until next time
- boost::mutex::scoped_lock lock2(voting_cx->server_voting_mutex);
- //log_warning("NETCLIENT: provide_server_start(), name='%s', guid=%s\n",
- // reasonable_name.c_str(),
- // voting_cx->server_guid.c_str());
- via_this_node_update(voting_cx->server_guid);
- assert( !voting_cx->remote_server );
- assert( !i_am_providing_the_server );
- try {
- {
- SettingsLock lock(root_under_admin);
- voting_cx->remote_server = root_under_admin->dir_create(
- voting_cx->server_guid,
- tech1->common_prototypes()->RemoteServer
- ); // exception if bad guid
- i_am_providing_the_server = true;
- {
- SettingsLock lock(voting_cx->remote_server);
- voting_cx->remote_server->set_value_string("name", reasonable_name);
- voting_cx->remote_server->set_value_string("media_route", route);
- }
- }
- if (recurse_level == 1)
- {
- SettingsLock lock(node_dir);
- const std::string current_name = node_dir->get_value_string("name");
- std::string should_be_name = reasonable_name;
- if (!current_name.empty() && current_name != reasonable_name) {
- should_be_name += " (" + extract_address_from_name(current_name) + ")";
- }
- if (current_name != should_be_name) node_dir->set_value_string("name", should_be_name);
- }
- voting_cx->remote_server->this_is_network_folder(RIGHTS_EVERYTHING, recurse_level);
- return true;
- } catch (const std::logic_error& e) {
- if (voting_cx->server_guid==tech1->server_guid())
- return false;
- log_warning("NETCLIENT: %s\n", e.what());
- return false;
- }
- }
- void provide_server_no_more()
- {
- // any thread
- boost::mutex::scoped_lock lock1(voting_ptr_mutex);
- if ( !voting_cx ) return; // already disconnected
- if ( !i_am_providing_the_server ) return;
- boost::mutex::scoped_lock lock2(voting_cx->server_voting_mutex);
- //log("NETCLIENT: %s, provide_server_no_more()\n", name.c_str());
- i_am_providing_the_server = false;
- netclient_lost_all_services_for_node(voting_cx->remote_server);
- {
- SettingsLock lock(root_under_admin);
- root_under_admin->dir_remove(voting_cx->remote_server->name());
- voting_cx->remote_server.reset();
- }
- }
- virtual void you_have_won_the_vote() =0;
- virtual void you_have_lost_the_vote() =0;
- void via_this_node_update(const std::string& server_guid)
- {
- unsigned int n = (unsigned int) (now() / 1000000ULL);
- SettingsLock lock(node_dir);
- csv_list list = csv_explode( node_dir->get_value_string("reachable_via_this_node") );
- csv_list new_list;
- bool seen_server_guid = false;
- for (csv_list::iterator x=list.begin(); x!=list.end(); ++x) {
- const std::string& s = *x;
- unsigned long t;
- char buf[101];
- int r = sscanf(s.c_str(), "%100s-%lu", buf, &t); // stornix can have longer guid
- buf[100] = 0;
- if (r!=2) {
- log_warning("NETCLIENT: cannot parse reachable_via_this_node element '%s'\n",
- s.c_str()
- );
- continue;
- }
- //log_warning("NETCLIENT: checking '%s' at %lu\n", buf, t);
- if (buf==server_guid) {
- seen_server_guid = true;
- t = n;
- }
- if (t+100*24*60*60 < n) { // 100 days cleanup
- log_timestamp("NETCLIENT: removing server %s from reachable_via_this_node\n", server_guid.c_str());
- continue;
- }
- new_list.push_back(stdprintf("%s-%lu", buf, t));
- }
- if (!seen_server_guid)
- new_list.push_back(stdprintf("%s-%lu", server_guid.c_str(), (long unsigned int)n));
- node_dir->set_value_string("reachable_via_this_node", csv_implode(new_list));
- }
- };
- // network node tracker: settings to connect, login to remote server
- static Settings cloudfolder;
- static Settings cloudstat;
- static Settings health;
- static boost::mutex health_defender;
- static int health_should_be_counter = 0;
- static int health_connected_counter = 0;
- void update_node_icon(const Settings& node, int connected)
- {
- SettingsLock nlock(node);
- const int should_be = node->get_value_integer("should_be_connected");
- bool vtrassir = node->prototype_name() == "NetworkNodeVirtual";
- if (connected) {
- node->set_value_string("icon", ":/settings/server.png");
- } else {
- if (!should_be) {
- node->set_value_string("icon", ":/settings/server-disabled.png");
- } else {
- node->set_value_string("icon",
- vtrassir ? ":/settings/server-error-vtrassir.png" : ":/settings/server-error.png");
- }
- }
- }
- void update_global_health(
- bool update_error,
- const std::string& node_guid,
- const std::string& node_last_error) // health_defender locked
- {
- if (!health) return;
- SettingsLock lock(health);
- health->set_value_integer("network_really_connected", health_connected_counter);
- health->set_value_integer("network_should_be_connected", health_should_be_counter);
- if (health_connected_counter == health_should_be_counter) {
- health->set_value_string("network_last_error", "");
- health->set_value_string("network_error_node", "");
- } else if(update_error) {
- health->set_value_string("network_last_error", node_last_error);
- health->set_value_string("network_error_node", node_guid);
- }
- }
- static bool autodetect_user(std::string *username, std::string* password)
- {
- bool predefined_user = false;
- std::string predefined_username, predefined_password;
- if (cloudfolder) {
- SettingsLock lock(cloudfolder);
- predefined_username = cloudfolder->get_value_string("predefined_user_login");
- predefined_password = cloudfolder->get_value_string("predefined_user_password");
- predefined_user = !!cloudfolder->get_value_integer("predefined_user");
- predefined_user &= !predefined_username.empty();
- }
- if (predefined_user) {
- *username = predefined_username;
- *password = predefined_password;
- return true;
- } else {
- Settings operator_root = tech1->root_under_operator_logged_in();
- if (!operator_root) return false;
- std::string path = stdprintf("users/%s", operator_root->user_id().c_str());
- Settings root = tech1->local_server_under_admin();
- Settings user = root->cd(path, false);
- if (user) {
- SettingsLock lock(user);
- int from_cloud = user->get_value_integer("from_cloud");
- if (from_cloud) {
- *username = user->get_value_string("name");
- *password = user->get_value_string_with_default("password", "");
- return true;
- }
- }
- }
- return false;
- }
- class NetworkStatNodeTracker:
- public Constellation::Dir::Notification
- {
- public:
- Settings stat_dir;
- boost::weak_ptr<NetworkNodeTracker> node_tracker;
- std::string last_error;
- NetworkStatNodeTracker(const Settings& stat_dir_, boost::shared_ptr<NetworkNodeTracker> node_tracker_);
- void constellation_values_changed(const boost::shared_ptr<Dir> &tracked_dir);
- };
- static bool check_cert(int64_t session_id, const std::string& fingerprint);
- class NetworkNodeTracker:
- public Constellation::Dir::Notification,
- public NetClientServiceListReceiver,
- public boost::enable_shared_from_this<NetworkNodeTracker>
- {
- public:
- Settings node_dir;
- boost::mutex stat_tracker_mutex;
- boost::shared_ptr<NetworkStatNodeTracker> stat_tracker;
- boost::mutex fingerprint_mutex;
- std::string fingerprint;
- bool fingerprint_from_cc;
- std::string username;
- std::string password;
- std::string name;
- std::string actual_name;
- std::string cloud_id;
- int economy_mode;
- int requested_recurse_level;
- int port_rpc;
- int port_video;
- int use_cloud_connect;
- int use_connection_via_cloud;
- int should_be_connected;
- bool started_session;
- std::string started_session_ip;
- int started_session_port;
- int64_t started_session_id;
- bool hashed_password_only;
- bool autocredentials;
- bool cloud_login;
- bool try_get_address_from_cc;
- std::string origin_account;
- int disable_mainstream;
- int buffering;
- int connected_state;
- bool bad_username;
- std::string server_path;
- std::list< boost::weak_ptr<class TierServer> > recursively_created_servers;
- std::string remoteserver_whitelist;
- NetworkNodeTracker(const Settings& node_dir_):
- Constellation::Dir::Notification("NetworkNodeTracker"),
- node_dir(node_dir_),
- use_cloud_connect(0),
- use_connection_via_cloud(0),
- should_be_connected(0),
- started_session_id(0),
- started_session(false),
- bad_username(false),
- economy_mode(0),
- requested_recurse_level(-1),
- port_rpc(0),
- port_video(0),
- connected_state(0),
- autocredentials(false),
- cloud_login(false),
- try_get_address_from_cc(false),
- root_server_dir_dont_want(false),
- fingerprint_from_cc(false)
- {
- update_node_health(0);
- hashed_password_only = true;
- }
- ~NetworkNodeTracker()
- {
- disconnect();
- if (should_be_connected && node_dir->prototype_name() != "NetworkNodeVirtual") {
- decrement_should_be_connected_counter();
- update_node_health(0);
- }
- }
- void disconnect()
- {
- if (!started_session) return;
- started_session = false;
- if (1 == use_cloud_connect)
- cloud_disconnect(extract_cloud_id(cloud_id));
- if (0 != started_session_id) {
- clientrm->client_session_stop(started_session_id);
- started_session_id = 0;
- }
- boost::shared_ptr<NetworkStatNodeTracker> tmp;
- {
- boost::mutex::scoped_lock lock(stat_tracker_mutex);
- tmp.swap(stat_tracker);
- }
- update_node_icon(node_dir, 0);
- }
- static std::string extract_cloud_id(const std::string input_string)
- {
- std::string result_str = input_string;
- const size_t spos = input_string.find('/');
- if (std::string::npos == spos)
- return result_str;
- return input_string.substr(spos + 1);
- }
- static std::string extract_cloud_authorization_token(const std::string& input_string)
- {
- std::string result_str;
- const size_t spos = input_string.find('/');
- if (std::string::npos == spos)
- return result_str;
- return input_string.substr(0, spos);
- }
- void connect_or_not()
- {
- node_dir->assert_notify_thread();
- bool is_virtual_node = (node_dir->prototype_name() == "NetworkNodeVirtual");
- std::string cl_sid;
- bool webview = !tech1->have_client() && !tech1->have_server();
- std::string new_username, new_password;
- std::string new_name;
- std::string new_cloud_id;
- std::string last_ip_address;
- std::string new_fingerprint;
- std::string new_origin_account;
- int new_use_cloud_connect;
- int new_port_rpc;
- int new_port_video;
- int should_be;
- uint64_t last_cc_timestamp;
- int address_from_cc_success;
- int new_economy_mode;
- int new_recurse_level;
- int new_relay_count;
- int new_disable_mainstream;
- int new_buffering;
- bool new_autocredentials;
- Settings node_stat;
- Json::Value account = tech1->redir_want_client_primary(0, false);
- bool remove_stats = false;
- {
- SettingsLock lock(node_dir);
- new_use_cloud_connect = node_dir->get_value_integer("use_cloud_connect");
- new_name = node_dir->get_value_string("name");
- new_cloud_id = node_dir->get_value_string("cloud_id");
- last_ip_address = node_dir->get_value_string("ip_address");
- new_port_rpc = node_dir->get_value_integer("port_rpc");
- new_port_video = node_dir->get_value_integer("port_video");
- new_autocredentials = !!node_dir->get_value_integer("autocredentials");
- if (!new_autocredentials) {
- new_username = node_dir->get_value_string("username");
- new_password = node_dir->get_value_string("password");
- }
- new_economy_mode = node_dir->get_value_integer("economy_mode");
- new_recurse_level = node_dir->get_value_integer("network_recurse_level");
- new_relay_count = node_dir->get_value_integer("relay_count");
- new_disable_mainstream = node_dir->get_value_integer("disable_mainstream");
- new_buffering = node_dir->get_value_integer("buffering");
- should_be = node_dir->get_value_integer("should_be_connected");
- new_fingerprint = node_dir->get_value_string("accepted_fingerprint");
- last_cc_timestamp = scan_uint64(node_dir->get_value_string("last_cc_timestamp"));
- address_from_cc_success = node_dir->get_value_integer("address_from_cc_success");
- hashed_password_only = !!node_dir->get_value_integer("generated");
- new_origin_account = node_dir->get_value_string("origin_account");
- cl_sid = account["client_sid"].asString();
- Settings s = node_dir->dir_find("stats", false);
- if (1 == should_be) {
- if (!s) node_dir->dir_create("stats", NetworkNodeStats);
- } else if (s) {
- remove_stats = true;
- }
- node_stat = node_dir->dir_find("stats", false);
- }
- std::string cloud_login_user, cloud_login_password;
- bool new_cloud_login;
- if (webview && !cl_sid.empty()) {
- SettingsLock lock(cloudfolder);
- cloud_login_user = cloudfolder->get_value_string("import_username");
- cloud_login_password = account["client_sid"].asString();
- new_cloud_login = true;
- } else {
- new_cloud_login = autodetect_user(&cloud_login_user, &cloud_login_password);
- }
- if (new_autocredentials) {
- new_username = cloud_login_user;
- new_password = cloud_login_password;
- }
- started_session_ip = last_ip_address;
- std::string address = extract_address_from_name(new_name);
- if (!address.empty()) new_name = address;
- const bool name_changed = (new_name != name);
- if (!new_use_cloud_connect && name_changed)
- {
- {
- SettingsLock lock(node_dir);
- node_dir->set_value_string("ip_address", "");
- last_ip_address.clear();
- try_get_address_from_cc = false;
- node_dir->set_value_integer("address_from_cc_success", 0);
- }
- started_session_ip.clear();
- }
- const bool cloud_id_changed = new_use_cloud_connect &&
- cloud_id!=new_cloud_id && extract_address_from_name(new_name)!=new_cloud_id;
- if (cloud_id_changed) {
- SettingsLock lock(node_dir);
- node_dir->set_value_string("name", new_cloud_id);
- new_name = new_cloud_id;
- }
- bool something_changed =
- name_changed ||
- cloud_id != new_cloud_id ||
- new_use_cloud_connect != use_cloud_connect ||
- new_username != username ||
- new_password != password ||
- new_port_rpc != port_rpc ||
- new_port_video != port_video ||
- new_economy_mode != economy_mode ||
- new_recurse_level != requested_recurse_level ||
- new_relay_count != requested_relay_count || // wtf?
- new_disable_mainstream != disable_mainstream ||
- new_buffering != buffering ||
- new_autocredentials != autocredentials ||
- cloud_login != new_cloud_login;
- {
- boost::mutex::scoped_lock slock(fingerprint_mutex);
- something_changed |= (new_fingerprint != fingerprint);
- fingerprint = new_fingerprint;
- }
- if (something_changed) {
- bad_username = false;
- disconnect();
- }
- if (new_autocredentials && new_username.empty()) {
- login_error("local user doesn't use Cloud Login");
- }
- name = new_name;
- cloud_id = new_cloud_id;
- username = new_username;
- password = new_password;
- use_cloud_connect = new_use_cloud_connect;
- port_rpc = new_port_rpc;
- port_video = new_port_video;
- economy_mode = new_economy_mode;
- requested_recurse_level = new_recurse_level;
- disable_mainstream = new_disable_mainstream;
- buffering = new_buffering;
- autocredentials = new_autocredentials;
- cloud_login = new_cloud_login;
- origin_account = new_origin_account;
- if (!should_be) {
- bad_username = false; // reset 'bad' state if disabled
- }
- if (should_be_connected != should_be) {
- should_be_connected = should_be;
- if (!is_virtual_node) {
- if (should_be_connected) {
- increment_should_be_connected_counter();
- } else {
- decrement_should_be_connected_counter();
- update_node_health(0);
- }
- } else if (!should_be_connected) {
- update_node_health(0);
- }
- }
- if (!started_session && should_be && !bad_username) {
- {
- boost::mutex::scoped_lock lock(root_server_dir_mutex);
- root_server_dir_dont_want = false;
- }
- bool use_cc_workaround = false;
- std::string last_error;
- {
- SettingsLock lock(node_stat);
- last_error = node_stat->get_value_string("last_error");
- node_stat->set_value_string("last_error", "");
- node_stat->set_value_string("resolve_warning", "");
- node_stat->set_value_string("connected_using", "");
- }
- uint64_t now_ts = now();
- uint64_t cc_delay = 5*60*1000000ULL;
- use_cc_workaround = !last_ip_address.empty() && last_error.find("401")==std::string::npos &&
- address_from_cc_success && !cloud_id_changed &&
- (last_cc_timestamp > now_ts-cc_delay || last_error.find("434")!=std::string::npos || last_error.find("408")!=std::string::npos);
- if (use_cloud_connect && !use_cc_workaround) {
- assert(0 == started_session_id);
- const std::string extracted_cloud_id = extract_cloud_id(cloud_id);
- //const std::string cloud_authorization_token = extract_cloud_authorization_token(cloud_id);
- try {
- //if (cloud_authorization_token.empty())
- // throw std::runtime_error("cloud login and password cannot be empty");
- // Better to do this inside CC, have 3 methods to autorize:
- // - sid
- // - tsid
- // - account_name+password_current
- //cloud_authorization_token = tech1->redir_want_client_sid();
- if (extracted_cloud_id.empty())
- throw std::runtime_error("cloud id is empty");
- if (origin_account.empty())
- throw std::runtime_error("account is empty");
- if (tech1->cloud_license_id() == extracted_cloud_id || tech1->server_guid() == extracted_cloud_id)
- throw std::runtime_error("connection to self is not allowed");
- started_session_id = 0;
- try_get_address_from_cc = !address_from_cc_success && !try_get_address_from_cc;
- fingerprint_from_cc = false;
- boost::shared_ptr<CloudConnectRequest> request(
- new CloudConnectRequest);
- request->server_id = extracted_cloud_id;
- request->account = origin_account;
- request->description = RPC_DESCRIPTION;
- request->on_success = boost::bind(&cloud_connect_on_success,
- boost::weak_ptr<NetworkNodeTracker>(shared_from_this()), _1);
- request->on_info = boost::bind(&cloud_connect_on_info,
- boost::weak_ptr<NetworkNodeTracker>(shared_from_this()), _1);
- client_cloud_connect(request);
- try_get_address_from_cc = !try_get_address_from_cc;
- started_session = true;
- started_session_port = 0;
- use_connection_via_cloud = 1;
- {
- SettingsLock lock(node_dir);
- node_dir->set_value_string("last_cc_timestamp", print_uint64(now_ts));
- }
- } catch (const std::logic_error& e) {
- log_warning("NETCLIENT: cloud_connect: %s\n", e.what());
- {
- SettingsLock lock(node_stat);
- node_stat->set_value_string("last_error", e.what());
- }
- update_node_health(0);
- bad_username = true;
- return;
- }
- } else {
- try {
- if (name.empty())
- throw std::runtime_error("address is empty");
- update_node_health(0); // not connected yet
- actual_name = use_cloud_connect ? last_ip_address : name;
- Rpc::Callbacks callbacks(
- check_cert,
- socket_error_callback,
- NULL,
- update_node_ip_callback
- );
- started_session_id = clientrm->client_session_start(
- actual_name,
- port_rpc,
- last_ip_address,
- callbacks
- );
- started_session = true;
- started_session_port = port_rpc;
- use_connection_via_cloud = 0;
- } catch (const std::logic_error& e) {
- // duplicate address
- {
- SettingsLock lock(node_stat);
- node_stat->set_value_string("last_error", e.what());
- }
- update_node_health(0);
- bad_username = true;
- return;
- }
- }
- }
- if (started_session && !should_be_connected) {
- disconnect();
- update_node_health(0);
- }
- boost::shared_ptr<NetworkStatNodeTracker> tmp;
- if (remove_stats) {
- {
- SettingsLock lock(node_dir);
- node_dir->dir_remove("stats");
- }
- {
- boost::mutex::scoped_lock lock(stat_tracker_mutex);
- tmp.swap(stat_tracker);
- }
- }
- }
- void constellation_values_changed(const Settings& tracked_dir)
- {
- connect_or_not();
- }
- void constellation_folder_added(const boost::shared_ptr<Dir> &tracked_dir, const boost::shared_ptr<Dir> &new_folder)
- {
- if (new_folder->name() == "stats") {
- boost::shared_ptr<NetworkStatNodeTracker> tmp;
- tmp.reset(new NetworkStatNodeTracker(new_folder, shared_from_this()));
- {
- SettingsLock lock(new_folder);
- new_folder->add_notification(tmp, Dir::FIRE_VALUE_NOTIFICATION_NOW);
- }
- {
- boost::mutex::scoped_lock lock(stat_tracker_mutex);
- tmp.swap(stat_tracker);
- }
- }
- }
- // called from welcome server message below
- void connected_successfully(
- const std::string& server_guid,
- const boost::shared_ptr<NetServerWelcome>& remote_welcome,
- uint64_t salt)
- {
- // socket thread
- Settings node_stat = node_dir->cd("stats", false);
- int v = remote_welcome->interface_version();
- if(node_stat)
- {
- SettingsLock lock(node_stat);
- node_stat->set_value_string("last_error", "");
- }
- update_node_health(1);
- log("NETCLIENT: connection to %s:%i, user '%s', recurse %i, remote version %i\n",
- name.c_str(), port_rpc, username.c_str(), requested_recurse_level,
- v);
- if (!hashed_password_only && v<=100) {
- remote_welcome->network_login(
- username,
- password,
- "Trassir-3.0",
- shared_from_this(),
- !!economy_mode,
- requested_recurse_level);
- } else { // Trassir 3.3
- if (salt==0) {
- log_warning("LOGIN: zero salt, will do nothing\n");
- return;
- }
- std::vector<uint8_t> pass_hash = expensive_password_hash(salt, password);
- std::string pwd;
- if (!autocredentials) {
- pwd += "SALTED ";
- for (std::vector<uint8_t>::iterator x=pass_hash.begin(); x!=pass_hash.end(); x++)
- pwd += stdprintf("%02x", (int) *x);
- pwd += "\n";
- } else {
- Json::Value acc = tech1->redir_want_client_primary(0, false);
- if (!acc.isMember("account")) throw std::logic_error("no 'account'");
- std::vector<uint8_t> sid_hash = expensive_password_hash(salt, acc["account"].asString() );
- if (!sid_hash.size())
- log_warning("NETCLIENT: cloud client sid empty\n");
- pwd += "CLOUDSID ";
- for (std::vector<uint8_t>::iterator x=sid_hash.begin(); x!=sid_hash.end(); x++)
- pwd += stdprintf("%02x", (int) *x);
- pwd += "\n";
- std::string offline_password;
- {
- SettingsLock lock(network_folder);
- std::list<PasswordData> lst = string_to_password_data_list(network_folder->get_value_string("offline_passwords"));
- std::list<PasswordData>::iterator x;
- uint64_t ts_now = now();
- for (x=lst.begin(); x!=lst.end();) {
- if (ts_now - x->last_successful_login_ts > 28*24*60*60*1000000ULL) {
- x = lst.erase(x);
- continue;
- }
- if (cloud_id == x->server_guid)
- offline_password = x->offline_password;
- ++x;
- }
- }
- pwd += stdprintf("OFFLINE %s\n", offline_password.c_str()); // for offline generated password
- }
- log_timestamp("LOGIN: sending username=%s, password='%s'\n", username.c_str(), pwd.c_str());
- remote_welcome->network_login(
- username,
- pwd,
- "Trassir-3.0",
- shared_from_this(),
- !!economy_mode,
- requested_recurse_level);
- }
- }
- void add_server(
- const std::string& server_guid,
- const std::string& server_name,
- const std::string& server_media_route,
- const boost::shared_ptr<NetServerDir>& server_dir,
- int recurse_level);
- boost::mutex root_server_dir_mutex;
- boost::shared_ptr<NetServerDir> root_server_dir;
- bool root_server_dir_dont_want;
- void keep_reference_on_root_folder(const boost::shared_ptr<NetServerDir>& sd)
- {
- boost::mutex::scoped_lock lock(root_server_dir_mutex);
- if (root_server_dir_dont_want) return;
- root_server_dir = sd;
- }
- // from network (NetClientServiceListReceiver)
- void login_error(const std::string& message)
- {
- log("NETCLIENT: login error: %s\n", message.c_str());
- bad_username = true;
- Settings node_stats = node_dir->cd("stats", false);
- if(node_stats) {
- SettingsLock lock(node_stats);
- node_stats->set_value_string("last_error", message);
- }
- update_node_health(0);
- }
- // user has deleted node, must disconnect, it will not happen automatically since
- // this object referenced though network as NetClientServiceListReceiver
- void constellation_tracked_dir_erased(
- const boost::shared_ptr<Dir>& tracked_dir)
- {
- boost::mutex::scoped_lock lock(root_server_dir_mutex);
- root_server_dir_dont_want = true;
- root_server_dir.reset();
- }
- // from network (NetClientServiceListReceiver)
- void on_disconnect()
- {
- boost::mutex::scoped_lock lock(root_server_dir_mutex);
- root_server_dir_dont_want = true;
- root_server_dir.reset();
- }
- void update_node_health(int new_connected)
- {
- const std::string& node_guid = node_dir->name();
- std::string username;
- std::string node_name;
- Settings node_stats;
- {
- SettingsLock nlock(node_dir);
- node_name = node_dir->get_value_string("name");
- username = node_dir->get_value_string("username");
- node_stats = node_dir->dir_find("stats", false);
- }
- std::string node_last_error;
- boost::mutex::scoped_lock lock(health_defender);
- if (node_stats)
- {
- SettingsLock slock(node_stats);
- node_last_error = node_stats->get_value_string("last_error");
- connected_state = node_stats->get_value_integer("connected");
- node_stats->set_value_integer("connected", new_connected);
- }
- if( node_dir->prototype_name() != "NetworkNodeVirtual" ) {
- if (connected_state==0 && new_connected==1) {
- ++health_connected_counter;
- #ifdef T1_SERVER
- boost::shared_ptr<ServerObject> so = tech1->serverobject();
- if (so)
- tech1->fire_event(so, &event_connected_to, node_name, username, "");
- #endif
- }
- if (connected_state==1 && new_connected==0) {
- --health_connected_counter;
- #ifdef T1_SERVER
- boost::shared_ptr<ServerObject> so = tech1->serverobject();
- if (so)
- tech1->fire_event(so, &event_disconnected_from, node_name, "", "");
- #endif
- }
- connected_state = new_connected;
- update_global_health(!new_connected, node_guid, node_last_error);
- }
- update_node_icon(node_dir, new_connected);
- }
- void update_offline_password(const std::string& new_password)
- {
- uint64_t now_ts = now();
- SettingsLock lock(network_folder);
- std::list<PasswordData> offline_passwords = string_to_password_data_list(
- network_folder->get_value_string("offline_passwords") );
- std::list<PasswordData>::iterator x;
- bool add_new = true;
- for (x=offline_passwords.begin(); x!=offline_passwords.end(); ++x) {
- if (x->server_guid == cloud_id) {
- x->offline_password = new_password;
- x->last_successful_login_ts = now_ts;
- add_new = false;
- break;
- }
- }
- if (add_new)
- offline_passwords.push_back( PasswordData(cloud_id, new_password, now_ts) );
- network_folder->set_value_string("offline_passwords",
- password_data_list_to_string(offline_passwords));
- }
- void whitelist_send(const std::string& server_guid, const std::string& whitelist)
- {
- remoteserver_whitelist = whitelist;
- log_timestamp("NETCLIENT: for RemoteServer '%s' got whitelist: '%s'\n", server_guid.c_str(), whitelist.c_str());
- }
- private:
- void increment_should_be_connected_counter()
- {
- boost::mutex::scoped_lock lock(health_defender);
- ++health_should_be_counter;
- update_global_health(false, "", "");
- }
- void decrement_should_be_connected_counter()
- {
- boost::mutex::scoped_lock lock(health_defender);
- --health_should_be_counter;
- assert(health_should_be_counter >= 0);
- update_global_health(0, "", "");
- }
- static
- void cloud_connect_on_success(const boost::weak_ptr<NetworkNodeTracker>& weak,
- const boost::shared_ptr<CloudConnectSocket>& cc_socket)
- {
- boost::shared_ptr<NetworkNodeTracker> tracker = weak.lock();
- if (!tracker) {
- log_warning("NETSERVER: cloud_connect_on_success, node tracker not found!\n");
- cc_socket->close_callback();
- return;
- }
- Rpc::Callbacks callbacks;
- callbacks.error_callback = socket_error_callback;
- callbacks.update_node_address_callback = update_node_address_callback;
- if (tracker->fingerprint_from_cc)
- callbacks.check_cert_fingerprint = check_cert;
- tracker->started_session_id = rpc_inject_socket(cc_socket, callbacks);
- }
- static
- void cloud_connect_on_info(const boost::weak_ptr<NetworkNodeTracker>& weak,
- const std::string& json_info)
- {
- boost::shared_ptr<NetworkNodeTracker> tracker = weak.lock();
- if (!tracker) {
- log_warning("NETSERVER: cloud_connect_on_info, node tracker not found!\n");
- return;
- }
- std::string ssl_fingerprint;
- try {
- Json::Value v = json_parse_or_die(json_info, true);
- ssl_fingerprint = json_value_require(v, "ssl_fingerprint", Json::stringValue).asString();
- } catch (const std::exception& /*e*/) {
- log_timestamp("NETSERVER: fingerprint is missing for %s\n",
- extract_cloud_id(tracker->cloud_id).c_str()
- );
- return;
- }
- if (!ssl_fingerprint.empty()) {
- {
- boost::mutex::scoped_lock lock(tracker->fingerprint_mutex);
- tracker->fingerprint = ssl_fingerprint;
- }
- {
- SettingsLock lock(tracker->node_dir);
- tracker->node_dir->set_value_string("accepted_fingerprint", ssl_fingerprint);
- }
- tracker->fingerprint_from_cc = true;
- }
- }
- };
- static const char* AMERGE_SESSION_NODE = "vtrassir_amerge";
- class AmergeRpcSession
- : public NetClientServiceListReceiver
- , public NetClientDir
- , public boost::enable_shared_from_this<AmergeRpcSession>
- {
- public:
- int64_t rpc_session_id;
- boost::mutex dirs_mutex;
- boost::shared_ptr<NetServerDir> root_server_dir;
- Settings remote_server_dir;
- AmergeRpcSession()
- : rpc_session_id(0)
- {}
- ~AmergeRpcSession()
- {
- disconnect();
- }
- void connect()
- {
- boost::shared_ptr<CloudConnectRequest> request(
- new CloudConnectRequest);
- request->server_id = "vtrassir";
- request->description = RPC_DESCRIPTION;
- request->on_success = boost::bind(&cloud_connect_on_success,
- boost::weak_ptr<AmergeRpcSession>(shared_from_this()), _1);
- client_cloud_connect(request);
- }
- void disconnect()
- {
- cloud_disconnect("vtrassir");
- if (rpc_session_id != 0 && clientrm)
- clientrm->client_session_stop(rpc_session_id);
- rpc_session_id = 0;
- }
- void connected_successfully(
- const boost::shared_ptr<NetServerWelcome>& remote_welcome)
- {
- remote_welcome->network_login(
- "AmergeServiceUser",
- "",
- "Trassir-3.0",
- shared_from_this(),
- false,
- 1);
- }
- void login_error(const std::string& message)
- {
- log("NETCLIENT: amerge login error: %s\n", message.c_str());
- //TODO: reconnect ???
- }
- void keep_reference_on_root_folder(const boost::shared_ptr<NetServerDir>& sd)
- {
- boost::mutex::scoped_lock lock(dirs_mutex);
- root_server_dir = sd;
- }
- void add_server(
- const std::string& server_guid,
- const std::string& server_name,
- const std::string& server_media_route,
- const boost::shared_ptr<NetServerDir>& root_server_dir,
- int recurse_level)
- {
- Settings new_remote_server_dir;
- {
- SettingsLock lock(root_under_admin);
- new_remote_server_dir = root_under_admin->dir_create(
- server_guid + "_amerge",
- tech1->common_prototypes()->HiddenServer
- ); // exception if bad guid
- }
- {
- SettingsLock lock(new_remote_server_dir);
- new_remote_server_dir->set_value_string("media_route", "/asio:ip=vtrassir:port=0");
- }
- {
- boost::mutex::scoped_lock lock(dirs_mutex);
- remote_server_dir = new_remote_server_dir;
- }
- root_server_dir->pass_dir_receiver(shared_from_this());
- root_server_dir->client2server_start_work();
- }
- void update_offline_password(const std::string& new_password) {}
- void whitelist_send(const std::string&,const std::string&) {}
- void update_values(int rev, const std::string& s)
- {
- Settings server_dir;
- {
- boost::mutex::scoped_lock lock(dirs_mutex);
- server_dir = remote_server_dir;
- }
- if (server_dir) {
- SettingsLock lock(server_dir);
- server_dir->network_unserialize_server2client_values(1000+rev, s, false, false);
- }
- }
- void update_effective_rights(uint32_t) {}
- void add_folder(
- const std::string& folder_name,
- const std::string& prototype,
- const boost::shared_ptr<NetServerDir>& server_dir,
- uint32_t rights,
- int recurse_level)
- {
- }
- void remove_folder(const std::string& folder_name) {}
- void initial_add_completed() {}
- void add_service(const boost::shared_ptr<Interface>& service)
- {
- if (!service) {
- log("AMERGE_SESSION: add_service() ERROR (1)\n");
- return;
- }
- Settings server_dir;
- {
- boost::mutex::scoped_lock lock(dirs_mutex);
- server_dir = remote_server_dir;
- }
- if (server_dir) {
- const std::string& key = stdprintf("%s@%s", service->interface_name(), server_dir->name().c_str());
- netclient_found_remote_service(key, server_dir, service);
- }
- }
- void remove_service(const boost::shared_ptr<Interface>& service)
- {
- if (!service) {
- log_warning("AMERGE_SESSION: remove_service ERROR (1)\n");
- return;
- }
- remove_service_v2(service->interface_name());
- }
- void remove_service_v2(const std::string& sname)
- {
- Settings server_dir;
- {
- boost::mutex::scoped_lock lock(dirs_mutex);
- server_dir = remote_server_dir;
- }
- if (server_dir) {
- std::string key = sname + "@" + server_dir->name();
- netclient_lost_remote_service(key);
- }
- }
- void on_disconnect()
- {
- Settings old_remote_server_dir;
- boost::shared_ptr<NetServerDir> old_root_server_dir;
- {
- boost::mutex::scoped_lock lock(dirs_mutex);
- remote_server_dir.swap(old_remote_server_dir);
- root_server_dir.swap(old_root_server_dir);
- }
- if (old_remote_server_dir) {
- netclient_lost_all_services_for_node(old_remote_server_dir);
- {
- SettingsLock lock(root_under_admin);
- root_under_admin->dir_remove(old_remote_server_dir->name());
- }
- }
- if (old_root_server_dir)
- old_root_server_dir->client2server_stop_work();
- }
- private:
- static
- void cloud_connect_on_success(const boost::weak_ptr<AmergeRpcSession>& weak,
- const boost::shared_ptr<CloudConnectSocket>& cc_socket)
- {
- boost::shared_ptr<AmergeRpcSession> session = weak.lock();
- if (!session) {
- log_warning("NETSERVER: cloud_connect_on_success, amerge session not found!\n");
- cc_socket->close_callback();
- return;
- }
- Rpc::Callbacks callbacks;
- callbacks.error_callback = boost::bind(socket_error_callback,
- boost::weak_ptr<AmergeRpcSession>(session));
- session->rpc_session_id = rpc_inject_socket(cc_socket, callbacks);
- }
- static
- void socket_error_callback(const boost::weak_ptr<AmergeRpcSession>& weak)
- {
- boost::shared_ptr<AmergeRpcSession> session = weak.lock();
- if (!session)
- return;
- session->disconnect();
- session->connect();
- }
- };
- void amerge_connection_enable_disable(bool enable)
- {
- boost::shared_ptr<AmergeRpcSession> new_session;
- if (enable) {
- boost::shared_ptr<AmergeRpcSession> session;
- {
- boost::mutex::scoped_lock lock(amerge_session_mutex);
- session = amerge_session;
- }
- if (session)
- return;
- new_session.reset(new AmergeRpcSession);
- new_session->connect();
- }
- {
- boost::mutex::scoped_lock lock(amerge_session_mutex);
- amerge_session.swap(new_session);
- }
- }
- NetworkStatNodeTracker::NetworkStatNodeTracker(const Settings& stat_dir_, boost::shared_ptr<NetworkNodeTracker> node_tracker_):
- Constellation::Dir::Notification("NetworkStatNodeTracker"),
- stat_dir(stat_dir_),
- node_tracker(node_tracker_)
- {}
- void NetworkStatNodeTracker::constellation_values_changed(const boost::shared_ptr<Dir> &tracked_dir)
- {
- std::string new_last_error;
- {
- SettingsLock lock(tracked_dir);
- last_error = tracked_dir->get_value_string("last_error");
- }
- boost::shared_ptr<NetworkNodeTracker> tracker = node_tracker.lock();
- if (tracker && last_error!=new_last_error && !last_error.empty())
- tracker->constellation_values_changed(tracked_dir->parent());
- last_error = new_last_error;
- }
- void ClientDirReal::implement_disable_mainstream(
- const Settings& channel_info_locked,
- const Settings& unfiltered_channel_info)
- {
- boost::shared_ptr<NetworkNodeTracker> node = network_node.lock();
- if (!node) return;
- int disable_mainstream = node->disable_mainstream;
- int buffering = node->buffering;
- std::string vms = unfiltered_channel_info->get_value_string_with_default("address_video_main", "");
- std::string vss = unfiltered_channel_info->get_value_string_with_default("address_video_ss", "");
- // Constellation::RIGHTS_SOUND
- std::string ams = unfiltered_channel_info->get_value_string_with_default("address_audio_main", "");
- std::string ass = unfiltered_channel_info->get_value_string_with_default("address_audio_ss", "");
- if (disable_mainstream && !vss.empty()) {
- channel_info_locked->set_value_string("address_video_main", "");
- channel_info_locked->set_value_string("address_video_ss", vss);
- channel_info_locked->set_value_string("address_audio_main", "");
- channel_info_locked->set_value_string("address_audio_ss", ass);
- } else {
- channel_info_locked->set_value_string("address_video_main", vms);
- channel_info_locked->set_value_string("address_video_ss", vss);
- channel_info_locked->set_value_string("address_audio_main", ams);
- channel_info_locked->set_value_string("address_audio_ss", ass);
- channel_info_locked->set_value_string("address_audio_ss", ass);
- }
- channel_info_locked->set_value_integer("addrflags",
- unfiltered_channel_info->get_value_integer_with_default("addrflags", 0));
- channel_info_locked->set_value_integer("economy_mode",
- unfiltered_channel_info->get_value_integer_with_default("economy_mode", 0));
- channel_info_locked->set_value_string("grabber_path",
- unfiltered_channel_info->get_value_string_with_default("grabber_path", ""));
- channel_info_locked->set_value_string("address_figures_detector",
- unfiltered_channel_info->get_value_string_with_default("address_figures_detector", ""));
- channel_info_locked->set_value_string("address_figures_subtitles",
- unfiltered_channel_info->get_value_string_with_default("address_figures_subtitles", ""));
- channel_info_locked->set_value_integer("grabber_channel_n",
- unfiltered_channel_info->get_value_integer_with_default("grabber_channel_n", 0));
- }
- // tier server
- class TierServer:
- public ClientDirReal,
- public ServerProvider
- {
- public:
- boost::mutex vote_api_mutex;
- std::string guid;
- std::string name;
- std::string media_route;
- boost::shared_ptr<NetServerDir> server_dir;
- int recurse_level;
- std::string through;
- std::string remoteserver_whitelist;
- TierServer(
- const std::string& guid,
- const std::string& name,
- const boost::shared_ptr<NetServerDir>& server_dir,
- const boost::shared_ptr<NetworkNodeTracker>& network_node,
- const std::string& media_route,
- const std::string& remoteserver_whitelist,
- int recurse_level)
- :
- ClientDirReal( Settings(), server_dir, network_node ),
- ServerProvider(recurse_level),
- guid(guid),
- name(name),
- media_route(media_route),
- server_dir(server_dir),
- remoteserver_whitelist(remoteserver_whitelist),
- recurse_level(recurse_level)
- {
- i_work_as_tier_server = true;
- node_dir = network_node->node_dir;
- //i_work_as_root = true;
- }
- ~TierServer()
- {
- boost::mutex::scoped_lock lock(vote_api_mutex);
- provide_server_no_more();
- remove_me_from_voting_cx();
- }
- // called once, after constructor
- void connected_successfully()
- {
- boost::mutex::scoped_lock lock(vote_api_mutex);
- add_me_to_voting_cx(guid, boost::dynamic_pointer_cast<ServerProvider>(shared_from_this()));
- }
- void update_connected_through(const std::string& s)
- {
- if(!s.empty())
- {
- through = s;
- if(i_serve_here)
- {
- SettingsLock slock(i_serve_here);
- i_serve_here->set_value_string("connected_through", s);
- i_serve_here->set_value_string("whitelist", remoteserver_whitelist);
- }
- }
- }
- // virtual ServerProvider
- void you_have_won_the_vote()
- {
- boost::mutex::scoped_lock lock(vote_api_mutex);
- bool success = provide_server_start(name, media_route, recurse_level);
- if (!success) {
- remove_me_from_voting_cx();
- return;
- }
- boost::mutex::scoped_lock dirs_lock(dirs_mutex);
- i_serve_here = voting_cx->remote_server;
- update_connected_through(through);
- server_dir->client2server_start_work();
- log("tier: client2server_start_work()\n");
- }
- // virtual ServerProvider
- void you_have_lost_the_vote()
- {
- boost::mutex::scoped_lock lock(vote_api_mutex);
- provide_server_no_more();
- boost::mutex::scoped_lock dirs_lock(dirs_mutex);
- i_serve_here.reset();
- server_dir->client2server_stop_work();
- log("tier: client2server_stop_work()\n");
- }
- // from network (NetClientDir)
- void add_service(const boost::shared_ptr<Interface>& service)
- {
- if (!service) {
- log("NETCLIENT: add_service() ERROR (1)\n");
- return;
- }
- boost::mutex::scoped_lock dirs_lock(dirs_mutex);
- if (!i_serve_here) {
- log("NETCLIENT: remove_service() ERROR (2)\n");
- return;
- }
- const std::string& key = stdprintf("%s@%s", service->interface_name(), guid.c_str());
- netclient_found_remote_service(key, i_serve_here, service);
- }
- // from network (NetClientDir)
- void remove_service(const boost::shared_ptr<Interface>& service)
- {
- if (!service) {
- log_warning("NETCLIENT: remove_service ERROR (1)\n");
- return;
- }
- remove_service_v2(service->interface_name());
- }
- void remove_service_v2(const std::string& sname)
- {
- std::string key = sname + "@" + guid;
- netclient_lost_remote_service(key);
- }
- };
- void NetworkNodeTracker::add_server(
- const std::string& server_guid,
- const std::string& server_name,
- const std::string& server_media_route,
- const boost::shared_ptr<NetServerDir>& server_dir,
- int recurse_level)
- {
- if (recurse_level<1 || recurse_level>=8) { // 1, 2, 3 ... 7 allowed
- log("NETCLIENT: add_server() bad recurse level %i\n", recurse_level);
- return;
- }
- const std::string route_to_tier =
- server_media_route
- + ((use_cloud_connect && use_connection_via_cloud)
- ? stdprintf("/asio:ip=%s:port=0", extract_cloud_id(cloud_id).c_str())
- : stdprintf("/asio:ip=%s:port=%i", extract_address_from_name(actual_name).c_str(), port_video));
- try {
- boost::shared_ptr<TierServer> tier_server(new TierServer(
- server_guid,
- server_name,
- server_dir,
- shared_from_this(),
- route_to_tier,
- remoteserver_whitelist,
- recurse_level
- ));
- if(recurse_level == 1) {
- const std::string& node_path = node_dir->path();
- server_path = stdprintf("/%s", server_guid.c_str());
- {
- boost::mutex::scoped_lock dirs_lock(tier_server->dirs_mutex);
- tier_server->update_connected_through(node_path);
- }
- for(std::list< boost::weak_ptr< TierServer > >::iterator iter = recursively_created_servers.begin();
- recursively_created_servers.end() != iter; ++iter)
- {
- boost::shared_ptr<TierServer> cur = (*iter).lock();
- if(cur)
- {
- boost::mutex::scoped_lock dirs_lock(cur->dirs_mutex);
- cur->update_connected_through(server_path);
- }
- }
- recursively_created_servers.clear();
- } else {
- if (server_path.empty()) {
- recursively_created_servers.push_back(tier_server);
- } else {
- boost::mutex::scoped_lock dirs_lock(tier_server->dirs_mutex);
- tier_server->update_connected_through(server_path);
- }
- }
- server_dir->pass_dir_receiver(tier_server);
- tier_server->connected_successfully();
- } catch (const std::logic_error& e) {
- // bad server name, etc
- log("CLIENT: add_server(): %s\n", e.what());
- return;
- }
- }
- // network folder tracker
- extern void notify_about_cc_setup_changes(Tech1*);
- class NetworkDirTracker:
- public Constellation::Dir::Notification
- {
- public:
- boost::mutex ntrackers_mutex;
- std::map< std::string, boost::shared_ptr<NetworkNodeTracker> > ntrackers;
- NetworkDirTracker():
- Constellation::Dir::Notification("NetworkDirTracker")
- {
- }
- void constellation_folder_added(
- const Settings& tracked_dir,
- const Settings& new_folder)
- {
- assert(tracked_dir==network_folder);
- if (new_folder->name()=="network_node_add") return;
- boost::shared_ptr<NetworkNodeTracker> nt( new NetworkNodeTracker(new_folder) );
- {
- boost::mutex::scoped_lock tlock(ntrackers_mutex);
- ntrackers[new_folder->name()] = nt;
- }
- {
- SettingsLock lock(new_folder);
- new_folder->add_notification(nt, Constellation::Dir::FIRE_VALUE_NOTIFICATION_NOW|Constellation::Dir::WANT_ADD_REMOVE);
- }
- }
- void constellation_folder_removed(
- const Settings& tracked_dir,
- const Settings& removed_folder)
- {
- assert(tracked_dir==network_folder);
- {
- boost::mutex::scoped_lock tlock(ntrackers_mutex);
- std::map< std::string, boost::shared_ptr<NetworkNodeTracker> >::iterator i = ntrackers.find(removed_folder->name());
- assert( i!=ntrackers.end() );
- ntrackers.erase(i);
- }
- }
- void constellation_values_changed(
- const boost::shared_ptr<Dir>&)
- {
- notify_about_cc_setup_changes(tech1);
- }
- boost::shared_ptr<NetworkNodeTracker> find_node_tracker_locked(
- const std::string& node_guid,
- const boost::mutex::scoped_lock& ntrackers_mutex_locked
- )
- {
- std::map< std::string, boost::shared_ptr<NetworkNodeTracker> >::iterator i = ntrackers.find(node_guid);
- return i!=ntrackers.end() ? i->second : boost::shared_ptr<NetworkNodeTracker>();
- }
- boost::shared_ptr<NetworkNodeTracker> find_node_tracker(const std::string& node_guid)
- {
- boost::mutex::scoped_lock tlock(ntrackers_mutex);
- return find_node_tracker_locked(node_guid, tlock);
- }
- boost::shared_ptr<NetworkNodeTracker> find_node_tracker_by_session_id(int64_t session_id)
- {
- boost::mutex::scoped_lock lock(ntrackers_mutex);
- std::map< std::string, boost::shared_ptr<NetworkNodeTracker> >::iterator x;
- for (x=ntrackers.begin(); x!=ntrackers.end(); ++x) {
- const boost::shared_ptr<NetworkNodeTracker>& t = x->second;
- if (t->started_session_id==session_id) {
- return t;
- }
- }
- return boost::shared_ptr<NetworkNodeTracker>();
- }
- };
- static
- std::list<std::string> get_network_nodes()
- {
- SettingsLock l(network_folder);
- return network_folder->ls_dirs();
- }
- // add tracker
- class NetworkNodeAddTracker:
- public Constellation::Dir::Notification
- {
- struct NodeAddHelper
- {
- std::string id, name, cloud_id, password, username, origin_account;
- int port_rpc, port_video, use_cloud_connect, autocredentials, generated, economy;
- void fill_from_node_add(const SettingsLock&)
- {
- id = node_add_dot_dot_dot->get_value_string("new_node_id");
- name = node_add_dot_dot_dot->get_value_string("new_node_name");
- cloud_id = node_add_dot_dot_dot->get_value_string("new_node_cloud_id");
- origin_account = node_add_dot_dot_dot->get_value_string("new_origin_account");
- username = node_add_dot_dot_dot->get_value_string("new_node_username");
- password = node_add_dot_dot_dot->get_value_string("new_node_password");
- use_cloud_connect = node_add_dot_dot_dot->get_value_integer("new_node_use_cloud_connect");
- port_rpc = node_add_dot_dot_dot->get_value_integer("new_node_port_rpc");
- port_video = node_add_dot_dot_dot->get_value_integer("new_node_port_video");
- autocredentials = node_add_dot_dot_dot->get_value_integer("new_node_autocredentials");
- generated = node_add_dot_dot_dot->get_value_integer("new_node_generated");
- economy = node_add_dot_dot_dot->get_value_integer("new_node_economy");
- }
- std::map<std::string, bool> make_t1cloud_folders(const std::list<std::string>& exist_dirs)
- {
- std::map<std::string, bool> out;
- const Json::Value& accounts = tech1->redir_want_client_accounts(0, false);
- for (size_t index = 0; index < accounts.size(); ++index) {
- const Json::Value& acc = accounts.get(index, Json::Value());
- if (acc["account"].isString() == false)
- continue;
- const std::string& acc_id = acc["account"].asString();
- if (acc_id.empty())
- continue;
- const std::string& foldername = get_cc_t1cloud_foldername(acc_id);
- const std::string& cloudid = get_cc_cloudid_for_t1cloud(acc_id);
- if (std::find(exist_dirs.begin(), exist_dirs.end(), foldername) != exist_dirs.end())
- out[foldername] = false;
- else if (make_connection_folder(foldername, foldername, cloudid, acc_id))
- out[foldername] = true;
- }
- return out;
- }
- bool make_connection_folder(const std::string& id, const std::string& foldername, const std::string& cloud_id, const std::string& origin_account)
- {
- log("NETWORK: add node %s\n", foldername.c_str());
- try {
- Settings new_dir;
- {
- SettingsLock lock(network_folder);
- new_dir = network_folder->dir_create(id,
- is_cc_t1cloud_folder(foldername) ? NetworkNodeVirtual : NetworkNode);
- }
- SettingsLock lock2(new_dir);
- new_dir->set_value_string("name", foldername);
- new_dir->set_value_string("cloud_id", cloud_id);
- new_dir->set_value_string("origin_account", origin_account);
- new_dir->set_value_string("username", username);
- new_dir->set_value_string("password", password);
- new_dir->set_value_integer("use_cloud_connect", use_cloud_connect);
- new_dir->set_value_integer("port_rpc", port_rpc);
- new_dir->set_value_integer("port_video", port_video);
- new_dir->set_value_integer("generated", generated);
- new_dir->set_value_integer("autocredentials", autocredentials);
- new_dir->set_value_integer("economy_mode", economy);
- return true;
- } catch (const already_exists_error&) {
- log_warning("NETWORK: network node guid duplicate, sorry will do nothing\n");
- return false;
- }
- }
- static
- void reset_node_add(const SettingsLock&)
- {
- node_add_dot_dot_dot->set_value_string("new_node_name", "");
- node_add_dot_dot_dot->set_value_string("new_node_cloud_id", "");
- node_add_dot_dot_dot->set_value_string("new_origin_account", "");
- node_add_dot_dot_dot->set_value_string("new_node_username", "");
- node_add_dot_dot_dot->set_value_string("new_node_password", "");
- node_add_dot_dot_dot->unset_value("new_node_use_cloud_connect");
- node_add_dot_dot_dot->unset_value("new_node_port_rpc");
- node_add_dot_dot_dot->unset_value("new_node_port_video");
- node_add_dot_dot_dot->unset_value("new_node_autocredentials");
- node_add_dot_dot_dot->unset_value("new_node_generated");
- node_add_dot_dot_dot->unset_value("new_node_economy");
- }
- };
- public:
- NetworkNodeAddTracker():
- Constellation::Dir::Notification("NetworkNodeAddTracker")
- {
- }
- void renew_next_node_id(SettingsLock& locked_node_add_dot_dot_dot)
- {
- node_add_dot_dot_dot->set_value_string("new_node_id", tech1->random_guid());
- }
- void create_handler()
- {
- NodeAddHelper helper;
- {
- SettingsLock lock(node_add_dot_dot_dot);
- int now = node_add_dot_dot_dot->get_value_integer("create_now");
- if (!now) return;
- node_add_dot_dot_dot->set_value_integer("create_now", 0);
- helper.fill_from_node_add(lock);
- NodeAddHelper::reset_node_add(lock);
- renew_next_node_id(lock);
- }
- if ("vtrassir" == helper.cloud_id) { // it's a kind of magic
- std::string account_found;
- const Json::Value& accounts = tech1->redir_want_client_accounts(0, false);
- for (size_t index = 0; index < accounts.size(); ++index) {
- const Json::Value& acc = accounts.get(index, Json::Value());
- if (!acc["account"].isString())
- continue;
- if (!acc["is_primary"].isBool() || !acc["is_primary"].asBool())
- continue;
- const std::string& acc_id = acc["account"].asString();
- if (acc_id.empty())
- break;
- helper.cloud_id = get_cc_cloudid_for_t1cloud(acc_id);
- helper.origin_account = acc_id;
- break;
- }
- if (helper.origin_account.empty()) {
- log_warning("NETCLIENT: origin_account is empty. are you logged in using cloud-login?\n");
- return;
- }
- }
- helper.make_connection_folder(helper.id, helper.name, helper.cloud_id, helper.origin_account);
- }
- void update_vtrassirs(bool vtrassir_enable)
- {
- const std::list<std::string>& dirs = get_network_nodes();
- std::map<std::string, bool> t1folders;
- if (vtrassir_enable) {
- NodeAddHelper helper;
- helper.autocredentials = 1;
- helper.use_cloud_connect = 1;
- t1folders = helper.make_t1cloud_folders(dirs);
- }
- std::list<std::string>::const_iterator iter;
- for (iter = dirs.begin(); iter != dirs.end(); ++iter)
- if (is_cc_t1cloud_folder(*iter) && t1folders.find(*iter) == t1folders.end())
- delete_node(*iter);
- }
- void delete_handler()
- {
- std::string delete_id;
- {
- SettingsLock lock(node_add_dot_dot_dot);
- delete_id = node_add_dot_dot_dot->get_value_string("delete_node_id");
- if (delete_id.empty()) return;
- node_add_dot_dot_dot->set_value_string("delete_node_id", "");
- }
- if (delete_id == "cloudtrassir")
- delete_vtrassir_nodes();
- else
- delete_node(delete_id);
- }
- void delete_vtrassir_nodes()
- {
- const std::list<std::string>& dirs = get_network_nodes();
- std::list<std::string>::const_iterator it;
- for (it = dirs.begin(); it != dirs.end(); ++it)
- if (is_cc_t1cloud_folder(*it))
- delete_node(*it);
- }
- void delete_node(const std::string& delete_id)
- {
- try {
- SettingsLock lock(network_folder);
- network_folder->dir_remove(delete_id);
- } catch (const not_found_error& e) {
- log("NETSERVER: cannot erase network node: %s\n", e.what());
- }
- }
- void constellation_values_changed(
- const Settings& tracked_dir)
- {
- assert(node_add_dot_dot_dot==tracked_dir);
- create_handler();
- delete_handler();
- }
- };
- namespace {
- class CloudTracker;
- class CloudStatTracker;
- static boost::shared_ptr<CloudTracker> cloud_tracker;
- static boost::shared_ptr<CloudStatTracker> cloud_stat_tracker;
- class CloudTracker : public Constellation::Dir::Notification
- {
- bool vtrassir_enable;
- void constellation_values_changed(const Settings&)
- {
- if (network_node_add_tracker == NULL)
- return;
- const bool enable = is_vtrassir_enable();
- if (enable != vtrassir_enable) {
- vtrassir_enable = enable;
- network_node_add_tracker->update_vtrassirs(enable);
- }
- }
- public:
- CloudTracker():
- Constellation::Dir::Notification("netserver:CloudTracker"),
- vtrassir_enable(false)
- {}
- bool is_vtrassir_enable()
- {
- SettingsLock l(cloudfolder);
- return cloudfolder->get_value_integer("import_channels_enabled") != 0;
- }
- };
- class CloudStatTracker: public Constellation::Dir::Notification
- {
- std::string client_accounts;
- void constellation_values_changed(const Settings& tracked_dir)
- {
- if (network_node_add_tracker == NULL || cloud_tracker == NULL)
- return;
- std::string accounts;
- {
- SettingsLock lock(tracked_dir);
- accounts = tracked_dir->get_value_string("import_accounts");
- }
- if (accounts != client_accounts) {
- client_accounts = accounts;
- network_node_add_tracker->update_vtrassirs(cloud_tracker->is_vtrassir_enable());
- }
- }
- public:
- CloudStatTracker():
- Constellation::Dir::Notification("netserver:CloudStatTracker")
- {}
- };
- }
- #ifdef T1_SERVER
- static
- void login_error_and_ban(const boost::shared_ptr<NetClientServiceListReceiver>& service_client,
- const std::string& error_string)
- {
- FakeObjectInfo info = Rpc::fake_object_info(service_client.get());
- RpcConnection::asio_temporary_ban(info.ip);
- service_client->login_error(error_string);
- }
- typedef std::multimap< std::string, boost::weak_ptr<NetClientServiceListReceiver> > StringClientMap;
- static boost::mutex clients_mmap_mutex;
- static StringClientMap clients_mmap;
- void netserver_kick_user(const std::string& user_guid, const std::string& reason) {
- StringClientMap my_clients;
- {
- boost::mutex::scoped_lock lock(clients_mmap_mutex);
- my_clients = clients_mmap;
- }
- std::pair<StringClientMap::iterator, StringClientMap::iterator> bounds;
- bounds = my_clients.equal_range(user_guid);
- StringClientMap::iterator it;
- for (it = bounds.first; it != bounds.second; ++it) {
- boost::shared_ptr<NetClientServiceListReceiver> service_client = it->second.lock();
- if (!service_client) continue;
- service_client->login_error(reason);
- spontaneous_disconnect(service_client.get());
- log_warning("NETSERVER: User '%s' kicked\n", user_guid.c_str());
- }
- }
- bool user_logged_in(const std::string& user_guid)
- {
- Settings root = tech1->root_under_operator_logged_in();
- if (root && user_guid==root->user_id())
- return true;
- StringClientMap my_clients;
- {
- boost::mutex::scoped_lock lock(clients_mmap_mutex);
- my_clients = clients_mmap;
- }
- return my_clients.count(user_guid)>0;
- }
- // handshake
- class Tech1Welcome: public NetServerWelcome {
- public:
- boost::mutex client_list_mutex;
- std::list< boost::weak_ptr<NetClientServiceListReceiver> > client_list;
- void network_login(
- const std::string& username,
- const std::string& password,
- const std::string& clientversion,
- const boost::shared_ptr<NetClientServiceListReceiver>& service_client,
- bool economy_mode,
- int network_recurse_level
- )
- {
- int actual_connection_count;
- {
- boost::mutex::scoped_lock lock(client_list_mutex);
- std::list<boost::weak_ptr<NetClientServiceListReceiver> >::iterator x;
- for (x=client_list.begin(); x!=client_list.end(); ) {
- boost::shared_ptr<NetClientServiceListReceiver> rcvr = x->lock();
- if (!rcvr) x = client_list.erase(x);
- else x++;
- }
- actual_connection_count = client_list.size();
- }
- if (!service_client) {
- log("NETSERVER: login from remote failed (1)\n");
- return;
- }
- FakeObjectInfo info = Rpc::fake_object_info(service_client.get());
- boost::shared_ptr<ServerObject> so = tech1->serverobject();
- bool supported = false;
- supported |= clientversion.find("Trassir-3.0") != std::string::npos;
- supported |= clientversion.find("Trassir-4.0") != std::string::npos;
- supported |= clientversion.find("Stornix-4.0") != std::string::npos;
- if (!supported) {
- login_error_and_ban(service_client,
- stdprintf("your software version %s not compatible with %s",
- clientversion.c_str(),
- PRODUCT_NAME));
- tech1->useraction_log("LOGIN/WRONG-VERSION", service_client, "~operator", "%s %s",
- username.c_str(), clientversion.c_str());
- log("NETSERVER: login from %s with incompatible version '%s'\n",
- info.ip.c_str(), clientversion.c_str());
- return;
- }
- if (username=="~Cluster~" && !tech1->cluster_node_guid().empty()) {
- if (!cluster_login(password, service_client, info.server_salt)) {
- log_warning("NETSERVER: cluster2cluster password incorrect\n");
- login_error_and_ban(service_client, "401: authorization failed");
- tech1->useraction_log("LOGIN/WRONG-CREDENTIALS", service_client, "", "%s %s",
- username.c_str(), clientversion.c_str());
- if (so) tech1->fire_event(so, &event_login_failed, username.c_str(), info.ip.c_str(), "");
- }
- return;
- }
- std::string user_id = tech1->authorize(
- username, password,
- info.ip, info.server_salt,
- 0);
- if (user_id.empty()) {
- login_error_and_ban(service_client,"401: authorization failed");
- if(password.find("CLOUDSID") != std::string::npos)
- service_client->update_offline_password(""); //erase disposable pass for CC connection
- log("NETSERVER: login %s from %s failed\n", username.c_str(), info.ip.c_str());
- tech1->useraction_log("LOGIN/WRONG-CREDENTIALS", service_client, "~operator", "%s %s",
- username.c_str(), clientversion.c_str());
- if (so)
- tech1->fire_event(so, &event_login_failed, username.c_str(), info.ip.c_str(), "");
- return;
- }
- {
- boost::mutex::scoped_lock lock(clients_mmap_mutex);
- clients_mmap.insert(std::pair< std::string, boost::weak_ptr<NetClientServiceListReceiver> >(user_id, service_client));
- StringClientMap::iterator it;
- StringClientMap::iterator to_erase;
- it = clients_mmap.begin();
- while(it != clients_mmap.end()) {
- if (it->second.expired()) {
- to_erase = it;
- ++it;
- clients_mmap.erase(to_erase);
- } else {
- ++it;
- }
- }
- }
- Settings root_under_name;
- try {
- boost::shared_ptr<Constellation::Root> root = tech1->constellation_root();
- root_under_name = root->root_directory(user_id);
- } catch (const std::logic_error& e) {
- login_error_and_ban(service_client, e.what());
- log_warning("NETSERVER: login from remote failed: %s\n", e.what());
- return;
- }
- Settings network = tech1->local_server_under_admin()->cd("network", false);
- int limit;
- {
- SettingsLock lock(network);
- limit = network->get_value_integer("limit_client_count");
- }
- if(actual_connection_count >= limit) {
- login_error_and_ban(service_client, "client count limit reached (set by administrator)");
- log_warning("NETSERVER: client count limit reached (set by administrator)\n");
- spontaneous_disconnect(service_client.get());
- return;
- }
- if (so)
- tech1->fire_event(so, &event_login_successful, username.c_str(), info.ip.c_str(), "");
- tech1->useraction_log("LOGIN/SUCCESS", service_client, user_id, "%s %s",
- username.c_str(), clientversion.c_str());
- log_timestamp("NETSERVER: connected client %s from %s\n", username.c_str(), info.ip.c_str());
- {
- boost::mutex::scoped_lock lock(client_list_mutex);
- client_list.push_back(service_client);
- }
- boost::shared_ptr<ServerDirReal> root_server_dir(
- new ServerDirReal(root_under_name));
- root_server_dir->i_am_root_server_finder = true;
- if ("AmergeServiceUser" == username) {
- root_server_dir->folders_whitelist = &whitelist_amerge;
- } else if (tech1->have_mini()) {
- if ("Admin" != username)
- root_server_dir->folders_whitelist = &whitelist_cloud;
- } else if (economy_mode) {
- root_server_dir->folders_whitelist = &whitelist_economy;
- } else if (!tech1->cluster_node_guid().empty()) {
- root_server_dir->folders_blacklist = &blacklist_cluster2client;
- }
- root_server_dir->recursion_limit = network_recurse_level;
- root_server_dir->pass_server_receiver(service_client);
- root_server_dir->client2server_start_work();
- service_client->keep_reference_on_root_folder(root_server_dir);
- // offline passwords
- std::string new_password = tech1->random_guid();
- Settings users = tech1->local_server_under_admin()->cd("users", false);
- Settings user = users->cd(user_id, false);
- if (user) {
- SettingsLock lock(user);
- if (!user->get_value_integer("from_cloud")) return; // offline password only for cloud login
- std::string random_passwords = user->get_value_string_with_default("random_passwords", "");
- csv_list random_passwords_list = csv_explode(random_passwords);
- service_client->update_offline_password(new_password);
- uint64_t now_ts = now();
- random_passwords_list.push_back(print_uint64(now_ts));
- random_passwords_list.push_back(new_password);
- user->set_value_string("random_passwords", csv_implode(random_passwords_list));
- }
- }
- bool cluster_login(
- const std::string& password,
- const boost::shared_ptr<NetClientServiceListReceiver>& service_client,
- uint64_t salt)
- {
- std::string ssl_pkey;
- Settings swo = tech1->local_server_under_admin()->cd("system_wide_options", true);
- {
- SettingsLock lock(swo);
- ssl_pkey = swo->get_value_string("ssl_pkey");
- }
- static std::string meerswine;
- if (meerswine.empty()) {
- FILE* f = fopen("meerswine", "rb");
- if (f) {
- fclose(f);
- meerswine = read_file("meerswine");
- } else {
- meerswine = tech1->random_guid() + tech1->random_guid();
- }
- }
- std::string::size_type s_pos = password.find("SALTED ");
- std::string pass = password.substr((s_pos != std::string::npos) ? 7 : 0);
- if (
- !expensive_password_hash_check(meerswine, salt, hex_string_to_bytes_vector(pass)) &&
- !expensive_password_hash_check(ssl_pkey, salt, hex_string_to_bytes_vector(pass))
- ) return false;
- Settings root = tech1->constellation_root()->root_directory("admin");
- boost::shared_ptr<ServerDirReal> root_server_dir(new ServerDirReal(root));
- root_server_dir->i_am_root_server_finder = true;
- root_server_dir->i_am_cluster = true;
- root_server_dir->folders_blacklist = &blacklist_cluster2cluster;
- root_server_dir->recursion_limit = 1;
- root_server_dir->pass_server_receiver(service_client);
- root_server_dir->client2server_start_work();
- service_client->keep_reference_on_root_folder(root_server_dir);
- return true;
- }
- };
- #endif
- extern bool amerge_session_connected_successfully(
- int64_t rpc_session_id,
- const std::string& server_guid,
- const boost::shared_ptr<NetServerWelcome>& remote_welcome,
- uint64_t salt);
- class RpcClient: public Client {
- public:
- void welcome_message_from_server(const boost::shared_ptr<Interface>& sr, const std::string& server_guid)
- {
- if (server_guid.empty()) {
- log("NETCLIENT: connection rejected (0)\n");
- return;
- }
- boost::shared_ptr<NetServerWelcome> remote_welcome = boost::dynamic_pointer_cast<NetServerWelcome>(sr);
- if (!remote_welcome) {
- log("NETCLIENT: connection rejected (1)\n");
- return;
- }
- Rpc::FakeObjectInfo info = fake_object_info(sr.get());
- if (!info.valid) {
- log("NETCLIENT: connection rejected (2)\n");
- return;
- }
- boost::shared_ptr<NetworkNodeTracker> associated_node_tracker =
- network_tracker->find_node_tracker_by_session_id(info.session_id);
- if (!associated_node_tracker) {
- boost::shared_ptr<AmergeRpcSession> session;
- {
- boost::mutex::scoped_lock lock(amerge_session_mutex);
- session = amerge_session;
- }
- if (session)
- session->connected_successfully(remote_welcome);
- else
- log("NETCLIENT: connection rejected (3)\n");
- return;
- }
- //log("RpcClient: remote server guid %s\n", server_guid.c_str());
- if (going_down) return; // little race vs network_tracker.reset(), on shutdown
- try {
- associated_node_tracker->connected_successfully(server_guid, remote_welcome, info.server_salt);
- } catch (const std::logic_error& e) { // access denied, not found (bad server_guid)
- log("NETCLIENT: %s\n", e.what());
- return;
- }
- }
- };
- void update_node_ip_callback(int64_t session_id, const std::string& ip_address)
- {
- if (going_down) return;
- Settings associated_node;
- {
- boost::shared_ptr<NetworkNodeTracker> associated_node_tracker =
- network_tracker->find_node_tracker_by_session_id(session_id);
- if (associated_node_tracker) {
- associated_node = associated_node_tracker->node_dir;
- associated_node_tracker->update_node_health(0);
- }
- }
- if (!associated_node) {
- // already have message in logs, plus
- log("NETCLIENT: cannot find network node to update ip address\n");
- return;
- }
- SettingsLock lock(associated_node);
- associated_node->set_value_string("ip_address", ip_address);
- }
- void update_node_address_callback(int64_t session_id, const std::string& ip_address, int port_rpc, int port_video)
- {
- if (going_down) return;
- Settings associated_node;
- {
- boost::shared_ptr<NetworkNodeTracker> associated_node_tracker =
- network_tracker->find_node_tracker_by_session_id(session_id);
- if (associated_node_tracker) {
- associated_node = associated_node_tracker->node_dir;
- associated_node_tracker->update_node_health(0);
- associated_node_tracker->try_get_address_from_cc = false;
- }
- }
- if (!associated_node) {
- // already have message in logs, plus
- log("NETCLIENT: cannot find network node to update ip address\n");
- return;
- }
- std::string now_ts = print_uint64(now());
- SettingsLock lock(associated_node);
- associated_node->set_value_string("ip_address", ip_address);
- associated_node->set_value_integer("port_rpc", port_rpc);
- associated_node->set_value_integer("port_video", port_video);
- associated_node->set_value_integer("address_from_cc_success", 1);
- }
- void socket_error_callback(int64_t session_id, const std::string& error_message)
- {
- if (going_down) return;
- Settings associated_node;
- {
- boost::shared_ptr<NetworkNodeTracker> associated_node_tracker = network_tracker->find_node_tracker_by_session_id(session_id);
- if (associated_node_tracker) {
- associated_node = associated_node_tracker->node_dir;
- associated_node_tracker->disconnect();
- associated_node_tracker->update_node_health(0);
- }
- }
- if (!associated_node) {
- // already have message in logs, plus
- log("NETCLIENT: cannot find network node to store error: %s\n",
- error_message.c_str());
- return;
- }
- Settings node_stat = associated_node->cd("stats", false);
- if (node_stat) {
- SettingsLock lock(node_stat);
- const std::string& already_have_error = node_stat->get_value_string("last_error");
- if (already_have_error.empty()) { // first error is better
- node_stat->set_value_string("last_error", error_message);
- }
- }
- SettingsLock lock(associated_node);
- associated_node->set_value_integer("address_from_cc_success", 0);
- }
- #ifdef T1_SERVER
- class RpcServer: public Server {
- public:
- boost::shared_ptr<Tech1Welcome> i_store_welcome;
- RpcServer()
- {
- i_store_welcome.reset(new Tech1Welcome);
- }
- void send_welcome_message_to_client(const boost::shared_ptr<Client>& cl)
- {
- cl->welcome_message_from_server(i_store_welcome, tech1->server_guid());
- }
- };
- #endif
- // voting here
- VotingServerContext::VotingServerContext(const std::string& server_guid):
- server_guid(server_guid),
- Constellation::Dir::Notification("VotingServerContext")
- {
- }
- VotingServerContext::~VotingServerContext()
- {
- assert(!remote_server);
- }
- void VotingServerContext::decide_who_should_proceed()
- {
- boost::shared_ptr<ServerProvider> old_winner;
- boost::shared_ptr<ServerProvider> new_winner;
- {
- boost::mutex::scoped_lock lock(server_voting_mutex);
- old_winner = vote_winner.lock();
- vote_winner.reset();
- sort();
- if (!votes.empty() && !going_down)
- new_winner = votes.front().server_provider.lock();
- // if lock failed, we will be back here, vote again
- vote_winner = new_winner;
- }
- if (old_winner!=new_winner) {
- if (old_winner)
- old_winner->you_have_lost_the_vote();
- if (new_winner)
- new_winner->you_have_won_the_vote();
- }
- }
- bool check_cert(int64_t session_id, const std::string& fingerprint)
- {
- Settings serv_node;
- {
- boost::shared_ptr<NetworkNodeTracker> nn_tracker =
- network_tracker->find_node_tracker_by_session_id(session_id);
- if (nn_tracker)
- serv_node = nn_tracker->node_dir;
- }
- if (!serv_node) {
- log_warning("NETCLIENT: cannot find network node to check certificate\n");
- return false;
- }
- Settings serv_stats = serv_node->cd("stats", false);
- if (!serv_stats) {
- log_critical_error("NETCLIENT: cannot find network node stat dir\n");
- return false;
- }
- std::string allowed_fingerprint;
- {
- SettingsLock slock(serv_node);
- allowed_fingerprint = serv_node->get_value_string("accepted_fingerprint");
- }
- {
- SettingsLock sslock(serv_stats);
- serv_stats->set_value_string("fingerprint", fingerprint);
- }
- return (fingerprint == allowed_fingerprint);
- }
- class LocalOperatorTracker:
- public Dir::Notification
- {
- std::string local_operator;
- std::string cloud_client_sid;
- public:
- LocalOperatorTracker()
- :Constellation::Dir::Notification("LocalOperatorTracker")
- {
- }
- void constellation_values_changed(const Settings& tracked_dir)
- {
- std::string new_local_operator, new_cloud_client_sid;
- {
- Json::Value acc = tech1->redir_want_client_primary(0, false);
- SettingsLock lock(health);
- new_local_operator = health->get_value_string("local_operator");
- new_cloud_client_sid = acc["client_sid"].asString();
- }
- bool cloud_enabled = false;
- bool predefined_user = false;
- if (cloudfolder) {
- SettingsLock lock(cloudfolder);
- std::string predefined_username = cloudfolder->get_value_string("predefined_user_login");
- predefined_user = !!cloudfolder->get_value_integer("predefined_user");
- predefined_user &= !predefined_username.empty();
- cloud_enabled = !!cloudfolder->get_value_integer("cloud_enabled");
- }
- if (local_operator!=new_local_operator && !predefined_user) {
- std::string path;
- Settings user;
- if (!new_local_operator.empty()) {
- path = stdprintf("users/%s", new_local_operator.c_str());
- user = tech1->local_server_under_admin()->cd(path, false);
- }
- bool from_cloud = false;
- if (user) {
- SettingsLock lock(user);
- from_cloud = !!user->get_value_integer("from_cloud");
- } else {
- cloud_client_logout();
- }
- if (from_cloud) cloud_client_start_thread(user);
- }
- if (local_operator != new_local_operator ||
- cloud_client_sid != new_cloud_client_sid)
- {
- std::list<std::string> network_nodes = get_network_nodes();
- std::list<std::string>::iterator x;
- for (x=network_nodes.begin(); x!= network_nodes.end(); x++) {
- Settings node = network_folder->cd(*x, false);
- if (node->prototype_name()!="NetworkNode" && node->prototype_name()!="NetworkNodeVirtual")
- continue;
- if (!node) continue;
- int autocredentials, should_be_connected, use_cloud_connect;
- {
- SettingsLock lock(node);
- autocredentials = node->get_value_integer("autocredentials");
- should_be_connected = node->get_value_integer("should_be_connected");
- use_cloud_connect = node->get_value_integer("use_cloud_connect");
- }
- if (!should_be_connected || (!autocredentials && !use_cloud_connect)) continue;
- boost::shared_ptr<NetworkNodeTracker> tracker = network_tracker->find_node_tracker(*x);
- if (tracker)
- node->fire_values_notification(tracker);
- }
- }
- cloud_client_sid = new_cloud_client_sid;
- local_operator = new_local_operator;
- }
- };
- static const int iface_tracking_timeout_sec = 1;
- static bool terminate_iface_tracking = false;
- static boost::shared_ptr<boost::thread> iface_traker_thread;
- static boost::mutex subscribers_mutex;
- static std::list< boost::weak_ptr<NetworkAddressesChangeCallback> > network_addresses_subscribtions;
- void network_subscribe_on_addresses_change(
- const boost::weak_ptr<NetworkAddressesChangeCallback>& callback_weak
- )
- {
- network_addresses_subscribtions.push_back(callback_weak);
- }
- #ifdef T1_SERVER
- static
- void send_current_addresses_to_subscribers()
- {
- try {
- std::list< boost::weak_ptr<NetworkAddressesChangeCallback> > subscribtions;
- {
- boost::mutex::scoped_lock slock(subscribers_mutex);
- network_addresses_subscribtions.remove_if(boost::mem_fn(&boost::weak_ptr<NetworkAddressesChangeCallback>::expired));
- subscribtions = network_addresses_subscribtions;
- }
- std::list< boost::weak_ptr<NetworkAddressesChangeCallback> >::iterator i;
- for (i = subscribtions.begin(); subscribtions.end() != i; ++i) {
- const boost::shared_ptr<NetworkAddressesChangeCallback>& cur = i->lock();
- if (!cur) continue;
- cur->network_addresses_changed();
- }
- } catch (const std::exception& e) {
- log_warning("NETWORK_INTERFACES update: %s\n", e.what());
- }
- }
- #endif
- #ifdef WIN32
- #include <winsock2.h>
- #include <iphlpapi.h>
- #include <stdio.h>
- #include <windows.h>
- #ifdef T1_SERVER
- static
- void windows_iface_track_thread_func()
- {
- set_thread_name("net/server/win-track-ip-changes");
- while (!terminate_iface_tracking) {
- OVERLAPPED overlap = {0};
- overlap.hEvent = WSACreateEvent();
- HANDLE hand = NULL;
- const DWORD rc = NotifyAddrChange(&hand, &overlap);
- if (ERROR_IO_PENDING != rc) {
- log_warning("NETWORK: fail to subscribe for address change; error code %d\n", rc);
- sleep_relative(1000);
- continue;
- }
- while (!terminate_iface_tracking) {
- const DWORD rz = WaitForSingleObject(overlap.hEvent, iface_tracking_timeout_sec * 1000);
- if (rz == WAIT_OBJECT_0) {
- log_timestamp("NETWORK: IP configuration changed\n");
- send_current_addresses_to_subscribers();
- break; // restart outer loop to get more IP change notifications
- } else if (rz != WAIT_TIMEOUT) {
- log_warning("NETWORK: fail to wait for address change; retcode %d, last error code %d\n", rz, GetLastError());
- break; // restart outer loop
- }
- }
- CancelIPChangeNotify(&overlap); // optional but reccomended in WINAPI
- CloseHandle(overlap.hEvent);
- }
- }
- #endif // T1_SERVER
- #endif // WIN32
- #ifdef __linux__
- #include <stdio.h>
- #include <string.h>
- #include <netinet/in.h>
- #include <linux/netlink.h>
- #include <linux/rtnetlink.h>
- #include <net/if.h>
- #ifdef T1_SERVER
- static
- void linux_iface_track_thread_func()
- {
- set_thread_name("ifaddr_tracker");
- fd_set readfds;
- int socketfd, len;
- char buffer[4096];
- struct sockaddr_nl addr;
- struct nlmsghdr *nlh;
- struct timeval tv;
- if ((socketfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
- log_warning("couldn't open NETLINK_ROUTE socket");
- return;
- }
- const int default_flags = fcntl(socketfd, F_GETFL, 0);
- fcntl(socketfd, F_SETFL, default_flags | O_NONBLOCK);
- memset(&addr, 0, sizeof(addr));
- addr.nl_family = AF_NETLINK;
- addr.nl_groups = RTMGRP_IPV4_IFADDR;
- if (bind(socketfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
- log_warning("couldn't bind");
- return;
- }
- nlh = (struct nlmsghdr *)buffer;
- while (!terminate_iface_tracking) {
- tv.tv_sec = iface_tracking_timeout_sec;
- tv.tv_usec = 0;
- FD_ZERO(&readfds);
- FD_SET(socketfd, &readfds);
- const int rc = select(0, &readfds, NULL, NULL, &tv);
- if (rc < 0) {
- log_warning("IFACE_TRACKER: select error\n");
- return;
- }
- if (!FD_ISSET(socketfd, &readfds)) {
- continue;
- }
- if ((len = recv(socketfd, nlh, 4096, 0)) > 0) {
- while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) {
- if (RTM_NEWADDR == nlh->nlmsg_type || RTM_DELADDR == nlh->nlmsg_type)
- send_current_addresses_to_subscribers();
- nlh = NLMSG_NEXT(nlh, len);
- }
- }
- }
- }
- #endif
- #endif // __linux__
- #ifdef T1_SERVER
- static
- void start_track_interfaces_change()
- {
- if (iface_traker_thread)
- return;
- terminate_iface_tracking = false;
- #ifdef __linux__
- iface_traker_thread.reset(new boost::thread(&linux_iface_track_thread_func));
- #endif // __linux__
- #ifdef WIN32
- iface_traker_thread.reset(new boost::thread(&windows_iface_track_thread_func));
- #endif // WIN32
- }
- static
- void stop_track_interfaces_change()
- {
- if (!iface_traker_thread)
- return;
- terminate_iface_tracking = true;
- iface_traker_thread->join();
- iface_traker_thread.reset();
- }
- #endif
- // init/done
- void network_init(Tech1* t1)
- {
- static bool init_once = true;
- if (init_once) {
- rpc_json_init();
- register_all_agent_factories_tech1network();
- register_all_fake_factories_tech1network();
- t1->registry = Rpc::registry;
- init_once = false;
- }
- going_down = false;
- tech1 = t1;
- root_under_admin = tech1->constellation_root()->root_directory("admin");
- create_network_prototypes(root_under_admin);
- RpcConnection::asio_startup();
- cloud_connect_init(t1);
- }
- void net_set_server_name()
- {
- Settings local_server = tech1->local_server_under_admin();
- std::string alternative_name;
- std::string name_prefix;
- {
- Settings swo = local_server->cd("system_wide_options", false);
- assert(swo);
- SettingsLock lock(swo);
- alternative_name = swo->get_value_string("alternative_name");
- const std::string opmode = swo->get_value_string("operation_mode");
- if (opmode == "freeversion")
- name_prefix = "Trassir-FREE-";
- }
- {
- SettingsLock lock(local_server);
- if (local_server->prototype_name()=="LocalServer") {
- local_server->set_value_string("name", name_prefix
- + (alternative_name.empty() ? dssl_gethostname() : alternative_name));
- }
- }
- }
- #ifdef T1_SERVER
- void net_server_after_load()
- {
- try {
- Settings swo = tech1->local_server_under_admin()->cd("system_wide_options", true);
- tech1->server.reset(new RpcServer);
- serverrm = endpoint_create();
- serverrm->evolve_into_server(tech1->server);
- std::string cert_str, pkey_str;
- {
- SettingsLock lock1(swo);
- cert_str = swo->get_value_string("ssl_cert");
- pkey_str = swo->get_value_string("ssl_pkey");
- }
- boost::shared_ptr<Endpoint> tmp = endpoint_create();
- tmp->evolve_into_server(tech1->server);
- {
- boost::mutex::scoped_lock sclock(rm_mutex);
- serverrm = tmp;
- }
- if(cert_str.empty() || pkey_str.empty()) {
- throw std::runtime_error("cannot read server certificate");
- }
- RpcConnection::asio_create_server(
- cert_str, pkey_str,
- tech1->system_wide_options()->ifaces_rpc,
- tech1->system_wide_options()->port_rpc,
- boost::dynamic_pointer_cast<RpcConnection::Server>(serverrm)
- );
- start_track_interfaces_change();
- } catch (const std::exception& e) {
- log_critical_error("NETSERVER: create server failed: %s\n", e.what());
- exit(1);
- }
- }
- #endif
- extern void store_clientrm(const boost::shared_ptr<Rpc::Endpoint>&);
- static
- void lookup_initial_configuration(Settings& network_folder)
- {
- FILE* f;
- try {
- f = open_or_die(webdog_custom_path_str, "rt");
- log_timestamp("CLOUD: reading '%s'\n", webdog_custom_path_str);
- } catch (const std::exception&) {
- return;
- }
- Settings local_server = tech1->local_server_under_admin();
- Settings swo = local_server->cd("system_wide_options", false);
- SettingsLock slock(network_folder);
- SettingsLock lock(swo);
- static boost::regex key_val("\\s*(\\w+)\\s*=\\s*([^\n]*)\n?");
- static boost::regex skip("(\\s*\n)|(\\s*#.*\n)");
- char buf[32768];
- size_t line = 0;
- while (fgets(buf, 32768, f)) {
- ++line;
- boost::cmatch what;
- if (boost::regex_match(buf, what, skip)) {
- continue;
- }
- if (!boost::regex_match(buf, what, key_val)) {
- log_warning("NETWORK: bad file \"%s\", can not parse line %d : %s\n", webdog_custom_path_str, line, buf);
- continue;
- }
- std::string val = what[2].str();
- int v = atoi(val.c_str());
- if (what[1].str()=="cloud_host" || what[1].str()=="cloud_address" ) {
- swo->set_value_string("cloud_address", val);
- } else if (what[1].str()=="automatic_update_url") {
- swo->set_value_string("automatic_update_url", val);
- } else if (what[1].str()=="cloud_connect_enable") {
- network_folder->set_value_integer("cloud_connect_enable", v);
- } else {
- log("NETWORK: parse file \"%s\" ignore line %d : %s\n", webdog_custom_path_str, line, buf);
- }
- }
- fclose(f);
- }
- void webdog_custom_erase()
- {
- static bool skip = false;
- if (skip) return;
- skip = !boost::filesystem::exists(webdog_custom_path_str);
- if (skip) return;
- boost::system::error_code ec;
- boost::filesystem::remove(webdog_custom_path_str, ec);
- if (ec)
- log_warning("NETWORK: cannot erase '%s': %s\n", webdog_custom_path_str, ec.message().c_str());
- else
- log_timestamp("NETWORK: file '%s' erased\n", webdog_custom_path_str);
- }
- void net_client_after_load()
- {
- client.reset(new RpcClient);
- boost::shared_ptr<Endpoint> tmp = endpoint_create();
- tmp->evolve_into_client(client);
- {
- boost::mutex::scoped_lock sclock(rm_mutex);
- clientrm = tmp;
- }
- store_clientrm(tmp);
- Settings local_server = tech1->local_server_under_admin();
- {
- SettingsLock lock(local_server);
- network_folder = local_server->dir_find("network", false);
- if (!network_folder) {
- network_folder = local_server->dir_create("network", NetworkFolder);
- }
- }
- lookup_initial_configuration(network_folder);
- local_operator_tracker.reset(new LocalOperatorTracker);
- cloudfolder = local_server->cd("cloud", false);
- cloudstat = cloudfolder->cd("stat", false);
- health = local_server->cd("health", false);
- if (!health) {
- log_critical_error("NETCLIENT: cannot find server health.\n");
- } else {
- SettingsLock lock(health);
- health->add_notification(local_operator_tracker, Dir::FIRE_VALUE_NOTIFICATION_NOW);
- }
- network_tracker.reset(new NetworkDirTracker);
- {
- SettingsLock lock(network_folder);
- network_folder->add_notification(network_tracker, Dir::WANT_ADD_REMOVE | Dir::FIRE_VALUE_NOTIFICATION_NOW);
- node_add_dot_dot_dot = network_folder->dir_create(
- "network_node_add",
- NetworkNodeAdd
- );
- }
- cloud_tracker.reset(new CloudTracker);
- {
- SettingsLock lock(cloudfolder);
- cloudfolder->add_notification(cloud_tracker, Constellation::Dir::FIRE_VALUE_NOTIFICATION_NOW);
- }
- cloud_stat_tracker.reset(new CloudStatTracker);
- {
- SettingsLock lock(cloudstat);
- cloudstat->add_notification(cloud_stat_tracker, Constellation::Dir::FIRE_VALUE_NOTIFICATION_NOW);
- }
- network_node_add_tracker.reset(new NetworkNodeAddTracker);
- {
- SettingsLock lock(node_add_dot_dot_dot);
- network_node_add_tracker->renew_next_node_id(lock);
- node_add_dot_dot_dot->add_notification(network_node_add_tracker, 0);
- }
- cloud_connect_after_load();
- }
- void network_done()
- {
- cloud_connect_done();
- going_down = true;
- network_tracker.reset(); // used in client code, don't destroy until no other threads can access it
- NetworkNode.reset();
- NetworkNodeStats.reset();
- NetworkFolder.reset();
- NetworkNodeAdd.reset();
- NetworkNodeVirtual.reset();
- node_add_dot_dot_dot.reset();
- network_node_add_tracker.reset();
- cloud_stat_tracker.reset();
- cloud_tracker.reset();
- cloudstat.reset();
- boost::shared_ptr<AmergeRpcSession> empty_session;
- {
- boost::mutex::scoped_lock lock(amerge_session_mutex);
- amerge_session.swap(empty_session);
- }
- empty_session.reset();
- #ifdef T1_SERVER
- if (serverrm) {
- stop_track_interfaces_change();
- try {
- RpcConnection::asio_destroy_server(
- boost::dynamic_pointer_cast<RpcConnection::Server>(serverrm));
- } catch (const std::exception& e) {
- log_warning("NETWORK: cannot destroy server: %s\n", e.what());
- }
- }
- #endif
- {
- boost::mutex::scoped_lock lock(subscribers_mutex);
- network_addresses_subscribtions.clear();
- }
- RpcConnection::asio_cleanup();
- #ifdef T1_SERVER
- if (serverrm) {
- serverrm->assert_empty();
- serverrm.reset();
- tech1->server->i_store_welcome.reset();
- tech1->server.reset();
- }
- #endif
- boost::shared_ptr<Endpoint> tmp;
- {
- boost::mutex::scoped_lock sclock(rm_mutex);
- tmp.swap(clientrm);
- }
- if (tmp)
- tmp->assert_empty();
- tmp.reset();
- client.reset();
- tech1 = 0;
- root_under_admin.reset();
- network_folder.reset();
- health.reset();
- cloudfolder.reset();
- local_operator_tracker.reset();
- voting_registry.clear(); // weak_ptr-s should be freed too before DLL unload
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement