|  | @@ -671,7 +671,9 @@ int
 | 
	
		
			
				|  |  |  protover_all_supported(const char *s, char **missing_out)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    int all_supported = 1;
 | 
	
		
			
				|  |  | -  smartlist_t *missing;
 | 
	
		
			
				|  |  | +  smartlist_t *missing_some;
 | 
	
		
			
				|  |  | +  smartlist_t *missing_completely;
 | 
	
		
			
				|  |  | +  smartlist_t *missing_all;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (!s) {
 | 
	
		
			
				|  |  |      return 1;
 | 
	
	
		
			
				|  | @@ -684,7 +686,8 @@ protover_all_supported(const char *s, char **missing_out)
 | 
	
		
			
				|  |  |      return 1;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  missing = smartlist_new();
 | 
	
		
			
				|  |  | +  missing_some = smartlist_new();
 | 
	
		
			
				|  |  | +  missing_completely = smartlist_new();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    SMARTLIST_FOREACH_BEGIN(entries, const proto_entry_t *, ent) {
 | 
	
		
			
				|  |  |      protocol_type_t tp;
 | 
	
	
		
			
				|  | @@ -696,26 +699,86 @@ protover_all_supported(const char *s, char **missing_out)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      SMARTLIST_FOREACH_BEGIN(ent->ranges, const proto_range_t *, range) {
 | 
	
		
			
				|  |  | +      proto_entry_t *unsupported = tor_malloc_zero(sizeof(proto_entry_t));
 | 
	
		
			
				|  |  | +      proto_range_t *versions = tor_malloc_zero(sizeof(proto_range_t));
 | 
	
		
			
				|  |  |        uint32_t i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      unsupported->name = tor_strdup(ent->name);
 | 
	
		
			
				|  |  | +      unsupported->ranges = smartlist_new();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |        for (i = range->low; i <= range->high; ++i) {
 | 
	
		
			
				|  |  |          if (!protover_is_supported_here(tp, i)) {
 | 
	
		
			
				|  |  | -          goto unsupported;
 | 
	
		
			
				|  |  | +          if (versions->low == 0 && versions->high == 0) {
 | 
	
		
			
				|  |  | +            versions->low = i;
 | 
	
		
			
				|  |  | +            /* Pre-emptively add the high now, just in case we're in a single
 | 
	
		
			
				|  |  | +             * version range (e.g. "Link=999"). */
 | 
	
		
			
				|  |  | +            versions->high = i;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          /* If the last one to be unsupported is one less than the current
 | 
	
		
			
				|  |  | +           * one, we're in a continous range, so set the high field. */
 | 
	
		
			
				|  |  | +          if ((versions->high && versions->high == i - 1) ||
 | 
	
		
			
				|  |  | +              /* Similarly, if the last high wasn't set and we're currently
 | 
	
		
			
				|  |  | +               * one higher than the low, add current index as the highest
 | 
	
		
			
				|  |  | +               * known high. */
 | 
	
		
			
				|  |  | +              (!versions->high && versions->low == i - 1)) {
 | 
	
		
			
				|  |  | +            versions->high = i;
 | 
	
		
			
				|  |  | +            continue;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          /* If we hit a supported version, and we previously had a range,
 | 
	
		
			
				|  |  | +           * we've hit a non-continuity. Copy the previous range and add it to
 | 
	
		
			
				|  |  | +           * the unsupported->ranges list and zero-out the previous range for
 | 
	
		
			
				|  |  | +           * the next iteration. */
 | 
	
		
			
				|  |  | +          if (versions->low != 0 && versions->high != 0) {
 | 
	
		
			
				|  |  | +            proto_range_t *versions_to_add = tor_malloc(sizeof(proto_range_t));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            versions_to_add->low = versions->low;
 | 
	
		
			
				|  |  | +            versions_to_add->high = versions->high;
 | 
	
		
			
				|  |  | +            smartlist_add(unsupported->ranges, versions_to_add);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            versions->low = 0;
 | 
	
		
			
				|  |  | +            versions->high = 0;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | +      /* Once we've run out of versions to check, see if we had any unsupported
 | 
	
		
			
				|  |  | +       * ones and, if so, add them to unsupported->ranges. */
 | 
	
		
			
				|  |  | +      if (versions->low != 0 && versions->high != 0) {
 | 
	
		
			
				|  |  | +        smartlist_add(unsupported->ranges, versions);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      /* Finally, if we had something unsupported, add it to the list of
 | 
	
		
			
				|  |  | +       * missing_some things and mark that there was something missing. */
 | 
	
		
			
				|  |  | +      if (smartlist_len(unsupported->ranges) != 0) {
 | 
	
		
			
				|  |  | +        smartlist_add(missing_some, (void*) unsupported);
 | 
	
		
			
				|  |  | +        all_supported = 0;
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        proto_entry_free(unsupported);
 | 
	
		
			
				|  |  | +        tor_free(versions);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      } SMARTLIST_FOREACH_END(range);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      continue;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    unsupported:
 | 
	
		
			
				|  |  |      all_supported = 0;
 | 
	
		
			
				|  |  | -    smartlist_add(missing, (void*) ent);
 | 
	
		
			
				|  |  | +    smartlist_add(missing_completely, (void*) ent);
 | 
	
		
			
				|  |  |    } SMARTLIST_FOREACH_END(ent);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  /* We keep the two smartlists separate so that we can free the proto_entry_t
 | 
	
		
			
				|  |  | +   * we created and put in missing_some, so here we add them together to build
 | 
	
		
			
				|  |  | +   * the string. */
 | 
	
		
			
				|  |  | +  missing_all = smartlist_new();
 | 
	
		
			
				|  |  | +  smartlist_add_all(missing_all, missing_some);
 | 
	
		
			
				|  |  | +  smartlist_add_all(missing_all, missing_completely);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    if (missing_out && !all_supported) {
 | 
	
		
			
				|  |  | -    tor_assert(0 != smartlist_len(missing));
 | 
	
		
			
				|  |  | -    *missing_out = encode_protocol_list(missing);
 | 
	
		
			
				|  |  | +    tor_assert(smartlist_len(missing_all) != 0);
 | 
	
		
			
				|  |  | +    *missing_out = encode_protocol_list(missing_all);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  smartlist_free(missing);
 | 
	
		
			
				|  |  | +  SMARTLIST_FOREACH(missing_some, proto_entry_t *, ent, proto_entry_free(ent));
 | 
	
		
			
				|  |  | +  smartlist_free(missing_some);
 | 
	
		
			
				|  |  | +  smartlist_free(missing_completely);
 | 
	
		
			
				|  |  | +  smartlist_free(missing_all);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    SMARTLIST_FOREACH(entries, proto_entry_t *, ent, proto_entry_free(ent));
 | 
	
		
			
				|  |  |    smartlist_free(entries);
 |