-/*
- Configure connection_t myself and set up the local sockets (listen only)
-*/
-int setup_myself(void)
-{
- config_t const *cfg;
- config_t *next;
- subnet_t *net;
-cp
- myself = new_connection();
-
- asprintf(&myself->hostname, "MYSELF"); /* FIXME? Do hostlookup on ourselves? */
- myself->flags = 0;
- myself->protocol_version = PROT_CURRENT;
-
- if(!(cfg = get_config_val(config, config_name))) /* Not acceptable */
- {
- syslog(LOG_ERR, _("Name for tinc daemon required!"));
- return -1;
- }
- else
- asprintf(&myself->name, "%s", (char*)cfg->data.val);
-
- if(check_id(myself->name))
- {
- syslog(LOG_ERR, _("Invalid name for myself!"));
- return -1;
- }
-cp
- if(!(cfg = get_config_val(config, config_privatekey)))
- {
- syslog(LOG_ERR, _("Private key for tinc daemon required!"));
- return -1;
- }
- else
- {
- myself->rsa_key = RSA_new();
- BN_hex2bn(&myself->rsa_key->d, cfg->data.ptr);
- BN_hex2bn(&myself->rsa_key->e, "FFFF");
- }
-
- if(read_host_config(myself))
- {
- syslog(LOG_ERR, _("Cannot open host configuration file for myself!"));
- return -1;
- }
-cp
- if(!(cfg = get_config_val(myself->config, config_publickey)))
- {
- syslog(LOG_ERR, _("Public key for tinc daemon required!"));
- return -1;
- }
- else
- {
- BN_hex2bn(&myself->rsa_key->n, cfg->data.ptr);
- }
-/*
- if(RSA_check_key(myself->rsa_key) != 1)
- {
- syslog(LOG_ERR, _("Invalid public/private keypair!"));
- return -1;
- }
-*/
- if(!(cfg = get_config_val(myself->config, config_port)))
- myself->port = 655;
- else
- myself->port = cfg->data.val;
-
- if((cfg = get_config_val(myself->config, config_indirectdata)))
- if(cfg->data.val == stupid_true)
- myself->flags |= EXPORTINDIRECTDATA;
-
- if((cfg = get_config_val(myself->config, config_tcponly)))
- if(cfg->data.val == stupid_true)
- myself->flags |= TCPONLY;
-
-/* Read in all the subnets specified in the host configuration file */
-
- for(next = myself->config; (cfg = get_config_val(next, config_subnet)); next = cfg->next)
- {
- net = new_subnet();
- net->type = SUBNET_IPV4;
- net->net.ipv4.address = cfg->data.ip->address;
- net->net.ipv4.mask = cfg->data.ip->mask;
-
- /* Teach newbies what subnets are... */
-
- if((net->net.ipv4.address & net->net.ipv4.mask) != net->net.ipv4.address)
- {
- syslog(LOG_ERR, _("Network address and subnet mask do not match!"));
- return -1;
- }
-
- subnet_add(myself, net);
- }
-
- if((myself->meta_socket = setup_listen_meta_socket(myself->port)) < 0)
- {
- syslog(LOG_ERR, _("Unable to set up a listening socket!"));
- return -1;
- }
-
- /* Generate packet encryption key */
-
- myself->cipher_pkttype = EVP_bf_cfb();
-
- myself->cipher_pktkeylength = myself->cipher_pkttype->key_len + myself->cipher_pkttype->iv_len;
-
- myself->cipher_pktkey = (char *)xmalloc(myself->cipher_pktkeylength);
- RAND_bytes(myself->cipher_pktkey, myself->cipher_pktkeylength);
-
- if(!(cfg = get_config_val(config, config_keyexpire)))
- keylifetime = 3600;
- else
- keylifetime = cfg->data.val;
-
- keyexpires = time(NULL) + keylifetime;
-
- /* Activate ourselves */
-
- myself->status.active = 1;
-
- syslog(LOG_NOTICE, _("Ready: listening on port %hd"), myself->port);
-
- child_pids = list_new();
-cp
- return 0;
-}
+ contradicting_add_edge = 0;
+ contradicting_del_edge = 0;
+
+ /* If AutoConnect is set, check if we need to make or break connections. */
+
+ if(autoconnect && node_tree->count > 1) {
+ /* Count number of active connections */
+ int nc = 0;
+ for list_each(connection_t, c, connection_list) {
+ if(c->edge)
+ nc++;
+ }
+
+ if(nc < 3) {
+ /* Not enough active connections, try to add one.
+ Choose a random node, if we don't have a connection to it,
+ and we are not already trying to make one, create an
+ outgoing connection to this node.
+ */
+ int r = rand() % node_tree->count;
+ int i = 0;
+
+ for splay_each(node_t, n, node_tree) {
+ if(i++ != r)
+ continue;
+
+ if(n->connection)
+ break;
+
+ bool found = false;
+
+ for list_each(outgoing_t, outgoing, outgoing_list) {
+ if(!strcmp(outgoing->name, n->name)) {
+ found = true;
+ break;
+ }
+ }
+
+ if(!found) {
+ logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
+ outgoing_t *outgoing = xzalloc(sizeof *outgoing);
+ outgoing->name = xstrdup(n->name);
+ list_insert_tail(outgoing_list, outgoing);
+ setup_outgoing_connection(outgoing);
+ }
+ break;
+ }
+ } else if(nc > 3) {
+ /* Too many active connections, try to remove one.
+ Choose a random outgoing connection to a node
+ that has at least one other connection.
+ */
+ int r = rand() % nc;
+ int i = 0;
+
+ for list_each(connection_t, c, connection_list) {
+ if(!c->edge)
+ continue;
+
+ if(i++ != r)
+ continue;
+
+ if(!c->outgoing || !c->node || c->node->edge_tree->count < 2)
+ break;
+
+ logger(DEBUG_CONNECTIONS, LOG_INFO, "Autodisconnecting from %s", c->name);
+ list_delete(outgoing_list, c->outgoing);
+ c->outgoing = NULL;
+ terminate_connection(c, c->edge);
+ break;
+ }
+ }
+
+ if(nc >= 3) {
+ /* If we have enough active connections,
+ remove any pending outgoing connections.
+ */
+ for list_each(outgoing_t, o, outgoing_list) {
+ bool found = false;
+ for list_each(connection_t, c, connection_list) {
+ if(c->outgoing == o) {
+ found = true;
+ break;
+ }
+ }
+ if(!found) {
+ logger(DEBUG_CONNECTIONS, LOG_INFO, "Cancelled outgoing connection to %s", o->name);
+ list_delete_node(outgoing_list, node);
+ }
+ }
+ }
+ }