1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
#include "uplink.h"
#include <pthread.h>
#include <sys/socket.h>
#include <string.h>
dnbd3_alt_server_t *_alt_servers[SERVER_MAX_ALTS];
int _num_alts = 0;
pthread_spinlock_t _alts_lock;
/**
* Get <size> known (working) alt servers, ordered by network closeness
* (by finding the smallest possible subnet)
*/
int uplink_get_matching_alt_servers(dnbd3_host_t *host, dnbd3_server_entry_t *output, int size)
{
if ( host == NULL || host->type == 0 ) return 0;
int i, j;
int count = 0;
int distance[size];
pthread_spin_lock( &_alts_lock );
for (i = 0; i < _num_alts; ++i) {
if ( host->type != _alt_servers[i]->host.type ) continue; // Wrong address family
if ( count == 0 ) {
// Trivial - this is the first entry
memcpy( &output[0].host, &_alt_servers[i]->host, sizeof(dnbd3_host_t) );
output[0].failures = 0;
distance[0] = uplink_net_closeness( host, &output[0].host );
count++;
} else {
// Other entries already exist, insert in proper position
const int dist = uplink_net_closeness( host, &_alt_servers[i]->host );
for (j = 0; j < size; ++j) {
if ( j < count && dist <= distance[j] ) continue;
if (j > count) break; // Should never happen but just in case...
if ( j < count ) {
// Check if we're in the middle and need to move other entries...
if (j + 1 < size) {
memmove(&output[j + 1], &output[j], sizeof(dnbd3_server_entry_t) * (size - j - 1));
memmove(&distance[j + 1], &distance[j], sizeof(int) * (size - j - 1));
}
} else {
count++;
}
memcpy( &output[j].host, &_alt_servers[i]->host, sizeof(dnbd3_host_t) );
output[j].failures = 0;
distance[j] = dist;
break;
}
}
}
pthread_spin_unlock( &_alts_lock );
return count;
}
/**
* Determine how close two addresses are to each other by comparing the number of
* matching bits from the left of the address. Does not count individual bits but
* groups of 4 for speed.
*/
int uplink_net_closeness(dnbd3_host_t *host1, dnbd3_host_t *host2)
{
if ( host1 == NULL || host2 == NULL || host1->type != host2->type ) return -1;
int retval = 0;
const int max = host1->type == AF_INET ? 4 : 16;
for (int i = 0; i < max; ++i) {
if ( (host1->addr[i] & 0xf0) != (host2->addr[i] & 0xf0) ) return retval;
++retval;
if ( (host1->addr[i] & 0x0f) != (host2->addr[i] & 0x0f) ) return retval;
++retval;
}
return retval;
}
void uplink_shutdown( dnbd3_connection_t *uplink)
{
return;
}
|