static void check_reachability(meshlink_handle_t *mesh) {
/* Check reachability status. */
+ int reachable = -1; /* Don't count ourself */
+
for splay_each(node_t, n, mesh->nodes) {
+ if(n->status.visited) {
+ reachable++;
+ }
+
/* Check for nodes that have changed session_id */
if(n->status.visited && n->prevedge && n->prevedge->reverse->session_id != n->session_id) {
n->session_id = n->prevedge->reverse->session_id;
}
}
}
+
+ if(mesh->reachable != reachable) {
+ if(!reachable) {
+ mesh->last_unreachable = mesh->loop.now.tv_sec;
+
+ if(mesh->threadstarted) {
+ timeout_set(&mesh->loop, &mesh->periodictimer, &(struct timeval) {
+ 0, prng(mesh, TIMER_FUDGE)
+ });
+ }
+ }
+
+ mesh->reachable = reachable;
+ }
}
void graph(meshlink_handle_t *mesh) {
* @param pingtimeout The required time within which a peer should respond, in seconds. The default is 5.
* The timeout must be smaller than the interval.
*/
- void set_dev_class_timeouts(dev_class_t devclass, int pinginterval, int pingtimeout);
+ void set_dev_class_timeouts(dev_class_t devclass, int pinginterval, int pingtimeout) {
+ meshlink_set_dev_class_timeouts(handle, devclass, pinginterval, pingtimeout);
+ }
+
+ /// Set device class fast retry period
+ /** This sets the fast retry period for a given device class.
+ * During this period after the last time the mesh becomes unreachable, connections are tried once a second.
+ *
+ * @param devclass The device class to update
+ * @param fast_retry_period The period during which fast connection retries are done. The default is 0.
+ */
+ void set_dev_class_fast_retry_period(dev_class_t devclass, int fast_retry_period) {
+ meshlink_set_dev_class_fast_retry_period(handle, devclass, fast_retry_period);
+ }
private:
// non-copyable:
pthread_mutex_unlock(&mesh->mutex);
}
+void meshlink_set_dev_class_fast_retry_period(meshlink_handle_t *mesh, dev_class_t devclass, int fast_retry_period) {
+ if(!mesh || devclass < 0 || devclass >= DEV_CLASS_COUNT) {
+ meshlink_errno = EINVAL;
+ return;
+ }
+
+ if(fast_retry_period < 0) {
+ meshlink_errno = EINVAL;
+ return;
+ }
+
+ pthread_mutex_lock(&mesh->mutex);
+ mesh->dev_class_traits[devclass].fast_retry_period = fast_retry_period;
+ pthread_mutex_unlock(&mesh->mutex);
+}
+
void handle_network_change(meshlink_handle_t *mesh, bool online) {
(void)online;
*/
extern void meshlink_set_dev_class_timeouts(struct meshlink_handle *mesh, dev_class_t devclass, int pinginterval, int pingtimeout);
+/// Set device class fast retry period
+/** This sets the fast retry period for a given device class.
+ * During this period after the last time the mesh becomes unreachable, connections are tried once a second.
+ *
+ * \memberof meshlink_handle
+ * @param mesh A handle which represents an instance of MeshLink.
+ * @param devclass The device class to update
+ * @param fast_retry_period The period during which fast connection retries are done. The default is 0.
+ */
+extern void meshlink_set_dev_class_fast_retry_period(struct meshlink_handle *mesh, dev_class_t devclass, int fast_retry_period);
+
#ifdef __cplusplus
}
#endif
meshlink_set_channel_sndbuf
meshlink_set_connection_try_cb
meshlink_set_default_blacklist
+meshlink_set_dev_class_fast_retry_period
meshlink_set_dev_class_timeouts
meshlink_set_error_cb
meshlink_set_invitation_timeout
typedef struct {
int pinginterval;
int pingtimeout;
+ int fast_retry_period;
unsigned int min_connects;
unsigned int max_connects;
int edge_weight;
meshlink_log_level_t log_level;
// The most important network-related members come first
+ int reachable;
int listen_sockets;
listen_socket_t listen_socket[MAXSOCKETS];
time_t connection_burst_time;
time_t last_config_check;
time_t last_hard_try;
+ time_t last_unreachable;
timeout_t pingtimer;
timeout_t periodictimer;
int pingtimeout = c->node ? mesh->dev_class_traits[c->node->devclass].pingtimeout : default_timeout;
int pinginterval = c->node ? mesh->dev_class_traits[c->node->devclass].pinginterval : default_interval;
+ if(c->outgoing && c->outgoing->timeout < 5) {
+ pingtimeout = 1;
+ }
+
// Also make sure that if outstanding key requests for the UDP counterpart of a connection has timed out, we restart it.
if(c->node) {
if(c->node->status.waitingforkey && c->node->last_req_key + pingtimeout <= mesh->loop.now.tv_sec) {
}
timeout_set(&mesh->loop, data, &(struct timeval) {
- default_timeout, prng(mesh, TIMER_FUDGE)
+ 1, prng(mesh, TIMER_FUDGE)
});
}
*/
void main_loop(meshlink_handle_t *mesh) {
timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timeval) {
- default_timeout, prng(mesh, TIMER_FUDGE)
+ 1, prng(mesh, TIMER_FUDGE)
});
timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval) {
0, 0
/* Done. */
mesh->last_config_check = mesh->loop.now.tv_sec;
+ mesh->last_unreachable = mesh->loop.now.tv_sec;
return true;
}
}
void retry_outgoing(meshlink_handle_t *mesh, outgoing_t *outgoing) {
- outgoing->timeout += 5;
+ if(!mesh->reachable && mesh->loop.now.tv_sec < mesh->last_unreachable + mesh->dev_class_traits[mesh->devclass].fast_retry_period) {
+ outgoing->timeout = 1;
+ } else {
+ outgoing->timeout += 5;
+ }
if(outgoing->timeout > mesh->maxtimeout) {
outgoing->timeout = mesh->maxtimeout;
}
timeout_add(&mesh->loop, &outgoing->ev, retry_outgoing_handler, outgoing, &(struct timeval) {
- outgoing->timeout, rand() % 100000
+ outgoing->timeout, prng(mesh, TIMER_FUDGE)
});
logger(mesh, MESHLINK_INFO, "Trying to re-establish outgoing connection in %d seconds", outgoing->timeout);