-/*
- check all connections to see if anything
- happened on their sockets
-*/
-void check_network_activity(fd_set *f)
-{
- conn_list_t *p;
- int x, l = sizeof(x);
-cp
- for(p = conn_list; p != NULL; p = p->next)
- {
- if(p->status.remove)
- continue;
-
- if(p->status.dataopen)
- if(FD_ISSET(p->socket, f))
- {
- /*
- The only thing that can happen to get us here is apparently an
- error on this outgoing(!) UDP socket that isn't immediate (i.e.
- something that will not trigger an error directly on send()).
- I've once got here when it said `No route to host'.
- */
- getsockopt(p->socket, SOL_SOCKET, SO_ERROR, &x, &l);
- syslog(LOG_ERR, _("Outgoing data socket error for %s (%s): %s"),
- p->name, p->hostname, strerror(x));
- terminate_connection(p);
- return;
- }
-
- if(p->status.meta)
- if(FD_ISSET(p->meta_socket, f))
- if(receive_meta(p) < 0)
- {
- terminate_connection(p);
- return;
- }
- }
-
- if(FD_ISSET(myself->socket, f))
- handle_incoming_vpn_data();
-
- if(FD_ISSET(myself->meta_socket, f))
- handle_new_meta_connection();
-cp
+int reload_configuration(void) {
+ char fname[PATH_MAX];
+
+ /* Reread our own configuration file */
+
+ exit_configuration(&config_tree);
+ init_configuration(&config_tree);
+
+ if(!read_server_config()) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reread configuration file.");
+ return EINVAL;
+ }
+
+ read_config_options(config_tree, NULL);
+
+ snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, myself->name);
+ read_config_file(config_tree, fname, true);
+
+ /* Parse some options that are allowed to be changed while tinc is running */
+
+ setup_myself_reloadable();
+
+ /* If StrictSubnet is set, expire deleted Subnets and read new ones in */
+
+ if(strictsubnets) {
+ for splay_each(subnet_t, subnet, subnet_tree)
+ if(subnet->owner) {
+ subnet->expires = 1;
+ }
+ }
+
+ for splay_each(node_t, n, node_tree) {
+ n->status.has_address = false;
+ }
+
+ load_all_nodes();
+
+ if(strictsubnets) {
+ for splay_each(subnet_t, subnet, subnet_tree) {
+ if(!subnet->owner) {
+ continue;
+ }
+
+ if(subnet->expires == 1) {
+ send_del_subnet(everyone, subnet);
+
+ if(subnet->owner->status.reachable) {
+ subnet_update(subnet->owner, subnet, false);
+ }
+
+ subnet_del(subnet->owner, subnet);
+ } else if(subnet->expires == -1) {
+ subnet->expires = 0;
+ } else {
+ send_add_subnet(everyone, subnet);
+
+ if(subnet->owner->status.reachable) {
+ subnet_update(subnet->owner, subnet, true);
+ }
+ }
+ }
+ } else { /* Only read our own subnets back in */
+ for splay_each(subnet_t, subnet, myself->subnet_tree)
+ if(!subnet->expires) {
+ subnet->expires = 1;
+ }
+
+ config_t *cfg = lookup_config(config_tree, "Subnet");
+
+ while(cfg) {
+ subnet_t *subnet, *s2;
+
+ if(get_config_subnet(cfg, &subnet)) {
+ if((s2 = lookup_subnet(myself, subnet))) {
+ if(s2->expires == 1) {
+ s2->expires = 0;
+ }
+
+ free_subnet(subnet);
+ } else {
+ subnet_add(myself, subnet);
+ send_add_subnet(everyone, subnet);
+ subnet_update(myself, subnet, true);
+ }
+ }
+
+ cfg = lookup_config_next(config_tree, cfg);
+ }
+
+ for splay_each(subnet_t, subnet, myself->subnet_tree) {
+ if(subnet->expires == 1) {
+ send_del_subnet(everyone, subnet);
+ subnet_update(myself, subnet, false);
+ subnet_del(myself, subnet);
+ }
+ }
+ }
+
+ /* Try to make outgoing connections */
+
+ try_outgoing_connections();
+
+ /* Close connections to hosts that have a changed or deleted host config file */
+
+ for list_each(connection_t, c, connection_list) {
+ if(c->status.control) {
+ continue;
+ }
+
+ snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
+ struct stat s;
+
+ if(stat(fname, &s) || s.st_mtime > last_config_check) {
+ logger(DEBUG_CONNECTIONS, LOG_INFO, "Host config file of %s has been changed", c->name);
+ terminate_connection(c, c->edge);
+ }
+ }
+
+ last_config_check = now.tv_sec;
+
+ return 0;