smartlist_free(desc->hsdir_missing_info);
/* Cleanup all intro points. */
digest256map_free(desc->intro_points.map, service_intro_point_free_);
+ digestmap_free(desc->intro_points.failed_id, tor_free_);
tor_free(desc);
}
sdesc->desc = tor_malloc_zero(sizeof(hs_descriptor_t));
/* Initialize the intro points map. */
sdesc->intro_points.map = digest256map_new();
+ sdesc->intro_points.failed_id = digestmap_new();
sdesc->hsdir_missing_info = smartlist_new();
return sdesc;
}
+/* From the given service, remove all expired failing intro points for each
+ * descriptor. */
+static void
+remove_expired_failing_intro(hs_service_t *service, time_t now)
+{
+ tor_assert(service);
+
+ /* For both descriptors, cleanup the failing intro points list. */
+ FOR_EACH_DESCRIPTOR_BEGIN(service, desc) {
+ DIGESTMAP_FOREACH_MODIFY(desc->intro_points.failed_id, key, time_t *, t) {
+ time_t failure_time = *t;
+ if ((failure_time + INTRO_CIRC_RETRY_PERIOD) <= now) {
+ MAP_DEL_CURRENT(key);
+ tor_free(t);
+ }
+ } DIGESTMAP_FOREACH_END;
+ } FOR_EACH_DESCRIPTOR_END;
+}
+
+/* For the given descriptor desc, put all node_t object found from its failing
+ * intro point list and put them in the given node_list. */
+static void
+setup_intro_point_exclude_list(const hs_service_descriptor_t *desc,
+ smartlist_t *node_list)
+{
+ tor_assert(desc);
+ tor_assert(node_list);
+
+ DIGESTMAP_FOREACH(desc->intro_points.failed_id, key, time_t *, t) {
+ (void) t; /* Make gcc happy. */
+ const node_t *node = node_get_by_id(key);
+ if (node) {
+ smartlist_add(node_list, (void *) node);
+ }
+ } DIGESTMAP_FOREACH_END;
+}
+
+/* For the given failing intro point ip, we add its time of failure to the
+ * failed map and index it by identity digest (legacy ID) in the descriptor
+ * desc failed id map. */
+static void
+remember_failing_intro_point(const hs_service_intro_point_t *ip,
+ hs_service_descriptor_t *desc, time_t now)
+{
+ time_t *time_of_failure, *prev_ptr;
+ const hs_desc_link_specifier_t *legacy_ls;
+
+ tor_assert(ip);
+ tor_assert(desc);
+
+ time_of_failure = tor_malloc_zero(sizeof(time_t));
+ *time_of_failure = now;
+ legacy_ls = get_link_spec_by_type(ip, LS_LEGACY_ID);
+ tor_assert(legacy_ls);
+ prev_ptr = digestmap_set(desc->intro_points.failed_id,
+ (const char *) legacy_ls->u.legacy_id,
+ time_of_failure);
+ tor_free(prev_ptr);
+}
+
/* Copy the descriptor link specifier object from src to dst. */
static void
link_specifier_copy(hs_desc_link_specifier_t *dst,
hs_service_intro_point_t *, ip) {
smartlist_add(exclude_nodes, (void *) get_node_from_intro_point(ip));
} DIGEST256MAP_FOREACH_END;
+ /* Also, add the failing intro points that our descriptor encounteered in
+ * the exclude node list. */
+ setup_intro_point_exclude_list(desc, exclude_nodes);
for (i = 0; i < num_needed_ip; i++) {
hs_service_intro_point_t *ip;
* reached the maximum number of retry with a non existing circuit. */
if (has_expired || node == NULL ||
(ocirc == NULL &&
- ip->circuit_retries >= MAX_INTRO_POINT_CIRCUIT_RETRIES)) {
+ ip->circuit_retries > MAX_INTRO_POINT_CIRCUIT_RETRIES)) {
+ /* Remove intro point from descriptor map. We'll add it to the failed
+ * map if we retried it too many times. */
MAP_DEL_CURRENT(key);
+
+ /* We've retried too many times, remember it has a failed intro point
+ * so we don't pick it up again. It will be retried in
+ * INTRO_CIRC_RETRY_PERIOD seconds. */
+ if (ip->circuit_retries >= MAX_INTRO_POINT_CIRCUIT_RETRIES) {
+ remember_failing_intro_point(ip, desc, now);
+ }
service_intro_point_free(ip);
+
/* XXX: Legacy code does NOT do that, it keeps the circuit open until
* a new descriptor is uploaded and then closed all expiring intro
* point circuit. Here, we close immediately and because we just
/* Cleanup invalid intro points from the service descriptor. */
cleanup_intro_points(service, now);
+ /* Remove expired failing intro point from the descriptor failed list. We
+ * reset them at each INTRO_CIRC_RETRY_PERIOD. */
+ remove_expired_failing_intro(service, now);
+
/* At this point, the service is now ready to go through the scheduled
* events guaranteeing a valid state. Intro points might be missing from
* the descriptors after the cleanup but the update/build process will