Use lowbw scheduler and clean old unused stuff
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
This commit is contained in:
392
mud.c
392
mud.c
@@ -65,19 +65,19 @@
|
|||||||
#define MUD_PACKET_MARK(X) ((X) | UINT64_C(1))
|
#define MUD_PACKET_MARK(X) ((X) | UINT64_C(1))
|
||||||
|
|
||||||
#define MUD_PACKET_MIN_SIZE (MUD_U48_SIZE + MUD_MAC_SIZE)
|
#define MUD_PACKET_MIN_SIZE (MUD_U48_SIZE + MUD_MAC_SIZE)
|
||||||
#define MUD_PACKET_MAX_SIZE (9000U)
|
#define MUD_PACKET_MAX_SIZE (1500U)
|
||||||
|
|
||||||
#define MUD_PACKET_TC (192) // CS6
|
#define MUD_PACKET_TC (192) // CS6
|
||||||
|
|
||||||
#define MUD_MTU (1280U + MUD_PACKET_MIN_SIZE)
|
#define MUD_MTU_MIN (1280U + MUD_PACKET_MIN_SIZE)
|
||||||
|
#define MUD_MTU_MAX (1450U + MUD_PACKET_MIN_SIZE)
|
||||||
|
|
||||||
#define MUD_TIME_BITS (48)
|
#define MUD_TIME_BITS (48)
|
||||||
#define MUD_TIME_MASK(X) ((X) & ((UINT64_C(1) << MUD_TIME_BITS) - 2))
|
#define MUD_TIME_MASK(X) ((X) & ((UINT64_C(1) << MUD_TIME_BITS) - 2))
|
||||||
|
|
||||||
#define MUD_STAT_TIMEOUT (100 * MUD_ONE_MSEC)
|
#define MUD_SEND_TIMEOUT (100 * MUD_ONE_MSEC)
|
||||||
#define MUD_KEYX_TIMEOUT (60 * MUD_ONE_MIN)
|
#define MUD_KEYX_TIMEOUT (60 * MUD_ONE_MIN)
|
||||||
#define MUD_KEYX_RESET_TIMEOUT (2 * MUD_STAT_TIMEOUT)
|
#define MUD_KEYX_RESET_TIMEOUT (200 * MUD_ONE_MSEC)
|
||||||
#define MUD_SEND_TIMEOUT (MUD_ONE_SEC)
|
|
||||||
#define MUD_TIME_TOLERANCE (10 * MUD_ONE_MIN)
|
#define MUD_TIME_TOLERANCE (10 * MUD_ONE_MIN)
|
||||||
|
|
||||||
#define MUD_CTRL_SIZE (CMSG_SPACE(MUD_PKTINFO_SIZE) + \
|
#define MUD_CTRL_SIZE (CMSG_SPACE(MUD_PKTINFO_SIZE) + \
|
||||||
@@ -122,8 +122,6 @@ struct mud_packet {
|
|||||||
unsigned char latmin[MUD_U48_SIZE];
|
unsigned char latmin[MUD_U48_SIZE];
|
||||||
unsigned char rate[MUD_U48_SIZE];
|
unsigned char rate[MUD_U48_SIZE];
|
||||||
unsigned char ratemax[MUD_U48_SIZE];
|
unsigned char ratemax[MUD_U48_SIZE];
|
||||||
unsigned char max[MUD_U48_SIZE];
|
|
||||||
unsigned char max_time[MUD_U48_SIZE];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mud {
|
struct mud {
|
||||||
@@ -156,6 +154,7 @@ struct mud {
|
|||||||
uint64_t time;
|
uint64_t time;
|
||||||
} decrypt, difftime, keyx;
|
} decrypt, difftime, keyx;
|
||||||
} bad;
|
} bad;
|
||||||
|
unsigned long long window;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -170,7 +169,8 @@ mud_addr_is_v6(struct mud_addr *addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mud_encrypt_opt(const struct mud_crypto_key *k, const struct mud_crypto_opt *c)
|
mud_encrypt_opt(const struct mud_crypto_key *k,
|
||||||
|
const struct mud_crypto_opt *c)
|
||||||
{
|
{
|
||||||
if (k->aes) {
|
if (k->aes) {
|
||||||
unsigned char npub[crypto_aead_aes256gcm_NPUBBYTES] = {0};
|
unsigned char npub[crypto_aead_aes256gcm_NPUBBYTES] = {0};
|
||||||
@@ -208,7 +208,8 @@ mud_encrypt_opt(const struct mud_crypto_key *k, const struct mud_crypto_opt *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mud_decrypt_opt(const struct mud_crypto_key *k, const struct mud_crypto_opt *c)
|
mud_decrypt_opt(const struct mud_crypto_key *k,
|
||||||
|
const struct mud_crypto_opt *c)
|
||||||
{
|
{
|
||||||
if (k->aes) {
|
if (k->aes) {
|
||||||
unsigned char npub[crypto_aead_aes256gcm_NPUBBYTES] = {0};
|
unsigned char npub[crypto_aead_aes256gcm_NPUBBYTES] = {0};
|
||||||
@@ -317,74 +318,19 @@ mud_unmapv4(struct sockaddr_storage *addr)
|
|||||||
memcpy(addr, &sin, sizeof(sin));
|
memcpy(addr, &sin, sizeof(sin));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
mud_update_mtu(struct mud *mud)
|
|
||||||
{
|
|
||||||
size_t mtu = MUD_PACKET_MAX_SIZE;
|
|
||||||
size_t count = 0;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < mud->count; i++) {
|
|
||||||
struct mud_path *path = &mud->paths[i];
|
|
||||||
|
|
||||||
if (path->state <= MUD_DOWN)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (mtu > path->mtu.ok)
|
|
||||||
mtu = path->mtu.ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
mud->mtu = count ? mtu : MUD_MTU;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct mud_path *
|
static struct mud_path *
|
||||||
mud_select_path(struct mud *mud, unsigned k)
|
mud_select_path(struct mud *mud, unsigned k)
|
||||||
{
|
{
|
||||||
unsigned long long n = 0;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < mud->count; i++) {
|
|
||||||
struct mud_path *path = &mud->paths[i];
|
|
||||||
|
|
||||||
path->prob = 0;
|
|
||||||
|
|
||||||
if (!path->ok || path->state <= MUD_DOWN)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
unsigned long long coef = 18;
|
|
||||||
uint64_t dt = (path->r_lat - path->r_latmin) / MUD_ONE_MSEC;
|
|
||||||
|
|
||||||
if (dt >= 300) {
|
|
||||||
coef = 0;
|
|
||||||
} else if (dt >= 50) {
|
|
||||||
coef = (16 - ((dt - 50) * 16)/(300 - 50)) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long long r = (path->r_ratemax * coef) / 16;
|
|
||||||
|
|
||||||
if (r == 0)
|
|
||||||
r = 10000;
|
|
||||||
|
|
||||||
if (path->send.bytes >= r)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
path->prob = r - path->send.bytes;
|
|
||||||
n += path->prob;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!n)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
unsigned w = 0;
|
unsigned w = 0;
|
||||||
struct mud_path *last = NULL;
|
struct mud_path *last = NULL;
|
||||||
|
|
||||||
for (unsigned i = 0; i < mud->count; i++) {
|
for (unsigned i = 0; i < mud->count; i++) {
|
||||||
struct mud_path *path = &mud->paths[i];
|
struct mud_path *path = &mud->paths[i];
|
||||||
|
|
||||||
if (!path->prob)
|
if (!path->window)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
w += ((path->prob << 16) + (n >> 1)) / n;
|
w += ((path->window << 16) + (mud->window >> 1)) / mud->window;
|
||||||
last = path;
|
last = path;
|
||||||
|
|
||||||
if (k <= w)
|
if (k <= w)
|
||||||
@@ -469,11 +415,6 @@ mud_send_path(struct mud *mud, struct mud_path *path, uint64_t now,
|
|||||||
path->send.bytes += size;
|
path->send.bytes += size;
|
||||||
path->send.time = now;
|
path->send.time = now;
|
||||||
|
|
||||||
if (path->send.max <= size) {
|
|
||||||
path->send.max = size;
|
|
||||||
path->send.max_time = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,16 +454,6 @@ mud_cmp_addr(struct sockaddr_storage *a, struct sockaddr_storage *b)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long
|
|
||||||
mud_sync(struct mud *mud)
|
|
||||||
{
|
|
||||||
const uint64_t last = mud->last_recv_time;
|
|
||||||
|
|
||||||
mud_send(mud, NULL, 0, 0);
|
|
||||||
|
|
||||||
return last ? MUD_TIME_MASK(mud_now() - last) / MUD_ONE_MSEC : ~0UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mud_path *
|
struct mud_path *
|
||||||
mud_get_paths(struct mud *mud, unsigned *ret_count)
|
mud_get_paths(struct mud *mud, unsigned *ret_count)
|
||||||
{
|
{
|
||||||
@@ -593,10 +524,14 @@ mud_copy_port(struct sockaddr_storage *d, struct sockaddr_storage *s)
|
|||||||
static void
|
static void
|
||||||
mud_reset_path(struct mud *mud, struct mud_path *path)
|
mud_reset_path(struct mud *mud, struct mud_path *path)
|
||||||
{
|
{
|
||||||
path->state = MUD_UP;
|
path->mtu.ok = MUD_MTU_MIN;
|
||||||
path->mtu.ok = MUD_MTU;
|
path->mtu.min = MUD_MTU_MIN;
|
||||||
path->mtu.probe = mud->mtu;
|
path->mtu.max = MUD_MTU_MAX;
|
||||||
|
path->mtu.count = 0;
|
||||||
|
path->send.ratemax = 0;
|
||||||
|
path->window = 0;
|
||||||
path->ok = 0;
|
path->ok = 0;
|
||||||
|
path->stat_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mud_path *
|
static struct mud_path *
|
||||||
@@ -656,8 +591,8 @@ mud_get_path(struct mud *mud, struct sockaddr_storage *local_addr,
|
|||||||
memcpy(&path->local_addr, local_addr, sizeof(*local_addr));
|
memcpy(&path->local_addr, local_addr, sizeof(*local_addr));
|
||||||
memcpy(&path->addr, addr, sizeof(*addr));
|
memcpy(&path->addr, addr, sizeof(*addr));
|
||||||
|
|
||||||
|
path->state = MUD_UP;
|
||||||
mud_reset_path(mud, path);
|
mud_reset_path(mud, path);
|
||||||
mud_update_mtu(mud);
|
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
@@ -815,8 +750,7 @@ mud_set_state(struct mud *mud, struct sockaddr *addr, enum mud_state state)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
path->state = state;
|
path->state = state;
|
||||||
|
mud_reset_path(mud, path);
|
||||||
mud_update_mtu(mud);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1002,7 +936,7 @@ mud_create(struct sockaddr *addr)
|
|||||||
mud->time_tolerance = MUD_TIME_TOLERANCE;
|
mud->time_tolerance = MUD_TIME_TOLERANCE;
|
||||||
mud->keyx_timeout = MUD_KEYX_TIMEOUT;
|
mud->keyx_timeout = MUD_KEYX_TIMEOUT;
|
||||||
mud->tc = MUD_PACKET_TC;
|
mud->tc = MUD_PACKET_TC;
|
||||||
mud->mtu = MUD_MTU;
|
mud->mtu = MUD_MTU_MIN;
|
||||||
|
|
||||||
memcpy(&mud->addr, addr, addrlen);
|
memcpy(&mud->addr, addr, addrlen);
|
||||||
|
|
||||||
@@ -1130,13 +1064,14 @@ mud_localaddr(struct sockaddr_storage *addr, struct msghdr *msg)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
mud_packet_send(struct mud *mud, struct mud_path *path,
|
mud_packet_send(struct mud *mud, struct mud_path *path,
|
||||||
uint64_t now, uint64_t sent, int probe)
|
uint64_t now, uint64_t sent, size_t size)
|
||||||
{
|
{
|
||||||
unsigned char dst[MUD_PACKET_MAX_SIZE];
|
unsigned char dst[MUD_PACKET_MAX_SIZE];
|
||||||
unsigned char src[MUD_PACKET_MAX_SIZE] = {0};
|
unsigned char src[MUD_PACKET_MAX_SIZE] = {0};
|
||||||
|
|
||||||
struct mud_packet *packet = (struct mud_packet *)src;
|
struct mud_packet *packet = (struct mud_packet *)src;
|
||||||
size_t size = sizeof(struct mud_packet);
|
|
||||||
|
if (size < MUD_PACKET_MIN_SIZE + sizeof(struct mud_packet))
|
||||||
|
size = MUD_PACKET_MIN_SIZE + sizeof(struct mud_packet);
|
||||||
|
|
||||||
mud_write48(dst, MUD_PACKET_MARK(now));
|
mud_write48(dst, MUD_PACKET_MARK(now));
|
||||||
mud_write48(packet->sent, sent);
|
mud_write48(packet->sent, sent);
|
||||||
@@ -1166,26 +1101,20 @@ mud_packet_send(struct mud *mud, struct mud_path *path,
|
|||||||
|
|
||||||
packet->aes = (unsigned char)mud->crypto.aes;
|
packet->aes = (unsigned char)mud->crypto.aes;
|
||||||
|
|
||||||
mud_write48(packet->lat, path->lat);
|
mud_write48(packet->lat, path->lat.val);
|
||||||
mud_write48(packet->latmin, path->latmin);
|
mud_write48(packet->latmin, path->latmin);
|
||||||
mud_write48(packet->max, path->recv.max);
|
mud_write48(packet->rate, path->rate.val);
|
||||||
mud_write48(packet->max_time, path->recv.max_time);
|
|
||||||
mud_write48(packet->rate, path->recv.rate);
|
|
||||||
mud_write48(packet->ratemax, path->recv.ratemax);
|
mud_write48(packet->ratemax, path->recv.ratemax);
|
||||||
|
|
||||||
if (probe)
|
|
||||||
size = path->mtu.probe - MUD_PACKET_MIN_SIZE;
|
|
||||||
|
|
||||||
const struct mud_crypto_opt opt = {
|
const struct mud_crypto_opt opt = {
|
||||||
.dst = dst,
|
.dst = dst,
|
||||||
.src = src,
|
.src = src,
|
||||||
.size = size,
|
.size = size - MUD_PACKET_MIN_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
mud_encrypt_opt(&mud->crypto.private, &opt);
|
mud_encrypt_opt(&mud->crypto.private, &opt);
|
||||||
|
|
||||||
return mud_send_path(mud, path, now,
|
return mud_send_path(mud, path, now, dst, size,
|
||||||
dst, size + MUD_PACKET_MIN_SIZE,
|
|
||||||
mud->tc, sent ? MSG_CONFIRM : 0);
|
mud->tc, sent ? MSG_CONFIRM : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1212,15 +1141,16 @@ mud_packet_decrypt(struct mud *mud,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mud_compute_rtt(struct mud_path *path, const uint64_t rtt)
|
mud_value_update(struct mud_value *value, const uint64_t val)
|
||||||
{
|
{
|
||||||
if (path->rtt) {
|
if (value->setup) {
|
||||||
path->rttvar = ((path->rttvar << 1) + path->rttvar
|
const uint64_t var = mud_abs_diff(value->val, val);
|
||||||
+ mud_abs_diff(path->rtt, rtt)) >> 2;
|
value->var = ((value->var << 1) + value->var + var) >> 2;
|
||||||
path->rtt = ((path->rtt << 3) - path->rtt + rtt) >> 3;
|
value->val = ((value->val << 3) - value->val + val) >> 3;
|
||||||
} else {
|
} else {
|
||||||
path->rttvar = rtt >> 1;
|
value->setup = 1;
|
||||||
path->rtt = rtt;
|
value->var = val >> 1;
|
||||||
|
value->val = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1238,7 +1168,7 @@ mud_ss_from_packet(struct sockaddr_storage *ss, struct mud_packet *pkt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
mud_packet_recv(struct mud *mud, struct mud_path *path,
|
mud_packet_recv(struct mud *mud, struct mud_path *path,
|
||||||
uint64_t now, uint64_t sent,
|
uint64_t now, uint64_t sent,
|
||||||
unsigned char *data, size_t size)
|
unsigned char *data, size_t size)
|
||||||
@@ -1253,7 +1183,12 @@ mud_packet_recv(struct mud *mud, struct mud_path *path,
|
|||||||
const uint64_t peer_sent = mud_read48(packet->sent);
|
const uint64_t peer_sent = mud_read48(packet->sent);
|
||||||
|
|
||||||
if (peer_sent) {
|
if (peer_sent) {
|
||||||
mud_compute_rtt(path, MUD_TIME_MASK(now - peer_sent));
|
mud_value_update(&path->rtt, MUD_TIME_MASK(now - peer_sent));
|
||||||
|
if (path->mtu.ok < size) {
|
||||||
|
path->mtu.ok = size;
|
||||||
|
path->mtu.min = size + 1;
|
||||||
|
path->mtu.count = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mud_keyx_init(mud, now);
|
mud_keyx_init(mud, now);
|
||||||
}
|
}
|
||||||
@@ -1270,7 +1205,7 @@ mud_packet_recv(struct mud *mud, struct mud_path *path,
|
|||||||
if (mud_keyx(mud, packet->pub, packet->aes)) {
|
if (mud_keyx(mud, packet->pub, packet->aes)) {
|
||||||
mud->bad.keyx.addr = path->addr;
|
mud->bad.keyx.addr = path->addr;
|
||||||
mud->bad.keyx.time = now;
|
mud->bad.keyx.time = now;
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mud->peer.set) {
|
if (!mud->peer.set) {
|
||||||
@@ -1286,8 +1221,6 @@ mud_packet_recv(struct mud *mud, struct mud_path *path,
|
|||||||
MUD_PUB_SIZE))
|
MUD_PUB_SIZE))
|
||||||
mud->paths[i].state = MUD_EMPTY;
|
mud->paths[i].state = MUD_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
mud_packet_send(mud, path, now, sent, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
path->pub = mud->crypto.pub;
|
path->pub = mud->crypto.pub;
|
||||||
@@ -1297,16 +1230,31 @@ mud_packet_recv(struct mud *mud, struct mud_path *path,
|
|||||||
|
|
||||||
path->r_lat = mud_read48(packet->lat);
|
path->r_lat = mud_read48(packet->lat);
|
||||||
path->r_latmin = mud_read48(packet->latmin);
|
path->r_latmin = mud_read48(packet->latmin);
|
||||||
path->r_max = mud_read48(packet->max);
|
|
||||||
path->r_max_time = mud_read48(packet->max_time);
|
|
||||||
path->r_rate = mud_read48(packet->rate);
|
path->r_rate = mud_read48(packet->rate);
|
||||||
path->r_ratemax = mud_read48(packet->ratemax);
|
path->r_ratemax = mud_read48(packet->ratemax);
|
||||||
|
|
||||||
if (path->mtu.ok < path->r_max)
|
// TODO
|
||||||
path->mtu.ok = path->r_max;
|
|
||||||
|
|
||||||
mud_update_mtu(mud);
|
const uint64_t dt = MUD_TIME_MASK(path->r_lat - path->r_latmin);
|
||||||
path->ok = 1;
|
const uint64_t target = 15 * MUD_ONE_MSEC;
|
||||||
|
const uint64_t a = (path->r_ratemax * 1500) >> 1;
|
||||||
|
const uint64_t b = (path->send.ratemax ?: 5000) * target;
|
||||||
|
|
||||||
|
if (dt < target) {
|
||||||
|
uint64_t delta = ((target - dt) * a) / b;
|
||||||
|
path->send.ratemax += delta;
|
||||||
|
} else if (dt > target) {
|
||||||
|
uint64_t delta = ((dt - target) * a) / b;
|
||||||
|
if (path->send.ratemax > delta) {
|
||||||
|
path->send.ratemax -= delta;
|
||||||
|
} else {
|
||||||
|
path->send.ratemax = 5000;
|
||||||
|
}
|
||||||
|
if (path->send.ratemax < 5000)
|
||||||
|
path->send.ratemax = 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!peer_sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -1372,83 +1320,87 @@ mud_recv(struct mud *mud, void *data, size_t size)
|
|||||||
if (!path)
|
if (!path)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
path->ok = 1;
|
||||||
|
path->stat_count = 0;
|
||||||
path->recv.total++;
|
path->recv.total++;
|
||||||
path->recv.time = now;
|
path->recv.time = now;
|
||||||
mud->last_recv_time = now;
|
mud->last_recv_time = now;
|
||||||
|
|
||||||
if (path->recv.max <= packet_size) {
|
const uint64_t lat = MUD_TIME_MASK(now - send_time + mud->time_tolerance);
|
||||||
path->recv.max = packet_size;
|
mud_value_update(&path->lat, lat);
|
||||||
path->recv.max_time = send_time;
|
|
||||||
if (path->mtu.ok < path->recv.max) {
|
if (!path->latmin)
|
||||||
path->mtu.ok = path->recv.max;
|
path->latmin = path->lat.val;
|
||||||
mud_update_mtu(mud);
|
|
||||||
}
|
size_t reply_size = 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (MUD_PACKET(send_time))
|
if (MUD_PACKET(send_time))
|
||||||
mud_packet_recv(mud, path, now, send_time, data, ret);
|
if (!mud_packet_recv(mud, path, now, send_time, data, packet_size))
|
||||||
|
reply_size = packet_size;
|
||||||
|
|
||||||
if (mud_timeout(now, path->recv.stat_time, MUD_STAT_TIMEOUT)) {
|
if (mud_timeout(now, path->recv.stat_time, mud->send_timeout)) {
|
||||||
const uint64_t rate = path->recv.bytes;
|
const uint64_t rate = path->recv.bytes;
|
||||||
|
mud_value_update(&path->rate, rate);
|
||||||
|
|
||||||
path->lat = MUD_TIME_MASK(now - send_time + mud->time_tolerance);
|
if (path->recv.ratemax < path->rate.val) {
|
||||||
|
path->recv.ratemax = path->rate.val;
|
||||||
if (path->latmin) {
|
|
||||||
if (path->latmin > path->lat)
|
|
||||||
path->latmin = path->lat;
|
|
||||||
|
|
||||||
if (path->latmax < path->lat)
|
|
||||||
path->latmax = path->lat;
|
|
||||||
} else {
|
} else {
|
||||||
path->latmin = path->lat;
|
if (path->lat.val > path->latmin + 4 * path->lat.var) {
|
||||||
path->latmax = path->lat;
|
path->recv.ratemax = (rate + 7 * path->recv.ratemax) / 8;
|
||||||
}
|
|
||||||
|
|
||||||
if (path->recv.ratemax > rate) {
|
|
||||||
if (rate < (7 * path->recv.ratemax) / 8)
|
|
||||||
path->latmin = (7 * path->latmin + path->lat) / 8;
|
|
||||||
if (path->latmin < path->lat) {
|
|
||||||
const uint64_t a = path->lat - path->latmin;
|
|
||||||
const uint64_t b = path->latmax - path->lat;
|
|
||||||
const uint64_t r = path->latmax - path->latmin;
|
|
||||||
path->recv.ratemax = (a * rate + (b + r) * path->recv.ratemax) / (r << 1);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
path->recv.ratemax = rate;
|
// TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
path->recv.rate = rate;
|
if (path->latmin > path->lat.val) {
|
||||||
|
path->latmin = path->lat.val;
|
||||||
|
} else {
|
||||||
|
if (path->rate.val + 4 * path->rate.var < path->recv.ratemax) {
|
||||||
|
path->latmin = (lat + 7 * path->latmin) / 8;
|
||||||
|
} else {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reply_size)
|
||||||
|
reply_size = path->mtu.ok;
|
||||||
|
|
||||||
path->recv.bytes = packet_size;
|
path->recv.bytes = packet_size;
|
||||||
|
|
||||||
mud_packet_send(mud, path, now, send_time, 0);
|
|
||||||
path->recv.stat_time = now;
|
path->recv.stat_time = now;
|
||||||
} else {
|
} else {
|
||||||
path->recv.bytes += packet_size;
|
path->recv.bytes += packet_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reply_size)
|
||||||
|
mud_packet_send(mud, path, now, send_time, reply_size);
|
||||||
|
|
||||||
return MUD_PACKET(send_time) ? 0 : ret;
|
return MUD_PACKET(send_time) ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mud_probe_mtu(struct mud *mud, struct mud_path *path, uint64_t now)
|
mud_probe_mtu(struct mud *mud, struct mud_path *path, uint64_t now)
|
||||||
{
|
{
|
||||||
if ((!path->rtt) ||
|
if (path->mtu.min > path->mtu.max)
|
||||||
(!mud_timeout(now, path->mtu.time, path->rtt)))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while ((path->mtu.probe != path->r_max + 1) &&
|
if (path->mtu.count && path->rtt.setup &&
|
||||||
(path->r_max != MUD_PACKET_MAX_SIZE)) {
|
!mud_timeout(now, path->mtu.time, path->rtt.val + 4 * path->rtt.var))
|
||||||
|
return;
|
||||||
if (path->mtu.probe > path->mtu.ok) {
|
|
||||||
path->mtu.probe = (path->mtu.probe + path->mtu.ok) >> 1;
|
|
||||||
} else {
|
|
||||||
path->mtu.probe = (MUD_PACKET_MAX_SIZE + path->mtu.ok + 1) >> 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
path->mtu.time = now;
|
path->mtu.time = now;
|
||||||
|
|
||||||
if ((path->mtu.probe == MUD_MTU) ||
|
while (1) {
|
||||||
(mud_packet_send(mud, path, now, 0, 1) != -1) ||
|
const size_t probe = (path->mtu.min + path->mtu.max) >> 1;
|
||||||
|
|
||||||
|
if (path->mtu.count == 2) {
|
||||||
|
path->mtu.max = probe - 1;
|
||||||
|
path->mtu.count = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
path->mtu.count++;
|
||||||
|
|
||||||
|
if ((mud_packet_send(mud, path, now, 0, probe) != -1) ||
|
||||||
(errno != EMSGSIZE))
|
(errno != EMSGSIZE))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1464,41 +1416,121 @@ mud_update(struct mud *mud, uint64_t now)
|
|||||||
mud_keyx_reset(mud);
|
mud_keyx_reset(mud);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long long window = 0;
|
||||||
|
size_t mtu = 0;
|
||||||
|
|
||||||
for (unsigned i = 0; i < mud->count; i++) {
|
for (unsigned i = 0; i < mud->count; i++) {
|
||||||
struct mud_path *path = &mud->paths[i];
|
struct mud_path *path = &mud->paths[i];
|
||||||
|
|
||||||
if (path->state < MUD_DOWN)
|
if (path->state < MUD_DOWN)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (path->send.bytes && path->recv.time &&
|
path->window = 0;
|
||||||
mud_timeout(now, path->recv.time, mud->send_timeout))
|
|
||||||
|
if (path->ok) {
|
||||||
|
if (path->stat_count >= 10) {
|
||||||
mud_reset_path(mud, path);
|
mud_reset_path(mud, path);
|
||||||
|
} else {
|
||||||
|
if (!mtu || mtu > path->mtu.ok)
|
||||||
|
mtu = path->mtu.ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int reset = mud_timeout(now, path->send.stat_time, mud->send_timeout / 2);
|
||||||
|
|
||||||
|
if (reset) {
|
||||||
|
if (path->send.bytes > path->send.ratemax) {
|
||||||
|
path->send.bytes -= path->send.ratemax;
|
||||||
|
} else {
|
||||||
|
path->send.bytes = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path->ok && path->send.ratemax > path->send.bytes) {
|
||||||
|
path->window = path->send.ratemax - path->send.bytes;
|
||||||
|
window += path->window;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reset)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
path->send.stat_time = now;
|
||||||
|
|
||||||
if (mud->peer.set) {
|
if (mud->peer.set) {
|
||||||
if (mud->crypto.ready)
|
if (path->ok)
|
||||||
mud_packet_send(mud, path, now, 0, 0);
|
|
||||||
|
|
||||||
mud_probe_mtu(mud, path, now);
|
mud_probe_mtu(mud, path, now);
|
||||||
|
|
||||||
|
if (mud_timeout(now, path->send.time, mud->send_timeout))
|
||||||
|
mud_packet_send(mud, path, now, 0, 0); //path->mtu.ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mud_timeout(now, path->send.stat_time, MUD_STAT_TIMEOUT)) {
|
if (path->ok)
|
||||||
path->send.bytes = 0;
|
path->stat_count++;
|
||||||
path->send.stat_time = now;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mud->window = window;
|
||||||
|
mud->mtu = mtu ?: MUD_MTU_MIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
mud_send_wait(struct mud *mud)
|
||||||
|
{
|
||||||
|
const uint64_t now = mud_now();
|
||||||
|
|
||||||
|
mud_update(mud, now);
|
||||||
|
|
||||||
|
if (mud->window)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unsigned long dt = MUD_ONE_SEC - 1;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < mud->count; i++) {
|
||||||
|
struct mud_path *path = &mud->paths[i];
|
||||||
|
|
||||||
|
if (path->state < MUD_DOWN || !path->ok)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!path->send.stat_time) // TODO
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint64_t elapsed = MUD_TIME_MASK(now - path->send.stat_time);
|
||||||
|
|
||||||
|
if (elapsed >= mud->send_timeout / 2)
|
||||||
|
continue; // TODO
|
||||||
|
|
||||||
|
uint64_t new_dt = (mud->send_timeout / 2) - elapsed;
|
||||||
|
|
||||||
|
if ((uint64_t)dt > new_dt)
|
||||||
|
dt = (unsigned long)new_dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
mud_sync(struct mud *mud)
|
||||||
|
{
|
||||||
|
const uint64_t last = mud->last_recv_time;
|
||||||
|
const uint64_t now = mud_now();
|
||||||
|
|
||||||
|
mud_update(mud, now);
|
||||||
|
|
||||||
|
return last ? MUD_TIME_MASK(now - last) / MUD_ONE_MSEC : ~0UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
mud_send(struct mud *mud, const void *data, size_t size, unsigned tc)
|
mud_send(struct mud *mud, const void *data, size_t size, unsigned tc)
|
||||||
{
|
{
|
||||||
unsigned char packet[MUD_PACKET_MAX_SIZE];
|
if (!size)
|
||||||
const uint64_t now = mud_now();
|
|
||||||
|
|
||||||
mud_update(mud, now);
|
|
||||||
|
|
||||||
if (!size || !mud->count)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!mud->window) {
|
||||||
|
errno = EAGAIN;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char packet[MUD_PACKET_MAX_SIZE];
|
||||||
|
const uint64_t now = mud_now();
|
||||||
const int packet_size = mud_encrypt(mud, now, packet, sizeof(packet), data, size);
|
const int packet_size = mud_encrypt(mud, now, packet, sizeof(packet), data, size);
|
||||||
|
|
||||||
if (!packet_size) {
|
if (!packet_size) {
|
||||||
|
|||||||
28
mud.h
28
mud.h
@@ -20,35 +20,31 @@ struct mud_public {
|
|||||||
unsigned char local[MUD_PUB_SIZE];
|
unsigned char local[MUD_PUB_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mud_value {
|
||||||
|
uint64_t val;
|
||||||
|
uint64_t var;
|
||||||
|
int setup;
|
||||||
|
};
|
||||||
|
|
||||||
struct mud_path {
|
struct mud_path {
|
||||||
enum mud_state state;
|
enum mud_state state;
|
||||||
struct sockaddr_storage local_addr, addr, r_addr;
|
struct sockaddr_storage local_addr, addr, r_addr;
|
||||||
struct {
|
struct mud_value rtt, lat, rate;
|
||||||
uint64_t send_time;
|
|
||||||
int remote;
|
|
||||||
} conf;
|
|
||||||
uint64_t rtt;
|
|
||||||
uint64_t rttvar;
|
|
||||||
uint64_t lat;
|
|
||||||
uint64_t latmin;
|
uint64_t latmin;
|
||||||
uint64_t latmax;
|
|
||||||
uint64_t r_lat;
|
uint64_t r_lat;
|
||||||
uint64_t r_latmin;
|
uint64_t r_latmin;
|
||||||
uint64_t r_rate;
|
uint64_t r_rate;
|
||||||
uint64_t r_ratemax;
|
uint64_t r_ratemax;
|
||||||
uint64_t r_max;
|
uint64_t window;
|
||||||
uint64_t r_max_time;
|
|
||||||
uint64_t prob;
|
|
||||||
struct {
|
struct {
|
||||||
|
size_t min;
|
||||||
|
size_t max;
|
||||||
size_t ok;
|
size_t ok;
|
||||||
size_t probe;
|
|
||||||
uint64_t time;
|
uint64_t time;
|
||||||
|
unsigned char count;
|
||||||
} mtu;
|
} mtu;
|
||||||
struct {
|
struct {
|
||||||
uint64_t max;
|
|
||||||
uint64_t max_time;
|
|
||||||
uint64_t total;
|
uint64_t total;
|
||||||
uint64_t rate;
|
|
||||||
uint64_t ratemax;
|
uint64_t ratemax;
|
||||||
uint64_t bytes;
|
uint64_t bytes;
|
||||||
uint64_t stat_time;
|
uint64_t stat_time;
|
||||||
@@ -56,6 +52,7 @@ struct mud_path {
|
|||||||
} send, recv;
|
} send, recv;
|
||||||
struct mud_public pub;
|
struct mud_public pub;
|
||||||
unsigned char ok;
|
unsigned char ok;
|
||||||
|
unsigned char stat_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mud *mud_create (struct sockaddr *);
|
struct mud *mud_create (struct sockaddr *);
|
||||||
@@ -69,6 +66,7 @@ int mud_get_key (struct mud *, unsigned char *, size_t *);
|
|||||||
void mud_set_mtu (struct mud *, size_t);
|
void mud_set_mtu (struct mud *, size_t);
|
||||||
size_t mud_get_mtu (struct mud *);
|
size_t mud_get_mtu (struct mud *);
|
||||||
|
|
||||||
|
unsigned long mud_send_wait (struct mud *);
|
||||||
unsigned long mud_sync (struct mud *);
|
unsigned long mud_sync (struct mud *);
|
||||||
|
|
||||||
int mud_set_send_timeout (struct mud *, unsigned long);
|
int mud_set_send_timeout (struct mud *, unsigned long);
|
||||||
|
|||||||
Reference in New Issue
Block a user