|
|
|
@ -112,6 +112,7 @@ static char *rtp_codecs[] = { |
|
|
|
|
|
|
|
static void call_destroy(struct call *); |
|
|
|
static void unkernelize(struct peer *); |
|
|
|
static void relays_cache_port_used(struct relays_cache *c); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -800,10 +801,9 @@ fail: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int get_port4(struct streamrelay *r, u_int16_t p) { |
|
|
|
static int get_port4(struct streamrelay *r, u_int16_t p, struct callmaster *m) { |
|
|
|
int fd; |
|
|
|
struct sockaddr_in sin; |
|
|
|
struct callmaster *m = r->up->up->call->callmaster; |
|
|
|
|
|
|
|
fd = socket(AF_INET, SOCK_DGRAM, 0); |
|
|
|
if (fd < 0) |
|
|
|
@ -830,10 +830,9 @@ fail: |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
static int get_port6(struct streamrelay *r, u_int16_t p) { |
|
|
|
static int get_port6(struct streamrelay *r, u_int16_t p, struct callmaster *m) { |
|
|
|
int fd; |
|
|
|
struct sockaddr_in6 sin; |
|
|
|
struct callmaster *m = r->up->up->call->callmaster; |
|
|
|
int tos; |
|
|
|
|
|
|
|
fd = socket(AF_INET6, SOCK_DGRAM, 0); |
|
|
|
@ -867,9 +866,8 @@ fail: |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
static int get_port(struct streamrelay *r, u_int16_t p) { |
|
|
|
static int get_port(struct streamrelay *r, u_int16_t p, struct callmaster *m) { |
|
|
|
int ret; |
|
|
|
struct callmaster *m = r->up->up->call->callmaster; |
|
|
|
|
|
|
|
assert(r->fd == -1); |
|
|
|
|
|
|
|
@ -882,9 +880,9 @@ static int get_port(struct streamrelay *r, u_int16_t p) { |
|
|
|
mutex_unlock(&m->portlock); |
|
|
|
|
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&m->conf.ipv6)) |
|
|
|
ret = get_port4(r, p); |
|
|
|
ret = get_port4(r, p, m); |
|
|
|
else |
|
|
|
ret = get_port6(r, p); |
|
|
|
ret = get_port6(r, p, m); |
|
|
|
|
|
|
|
if (ret) { |
|
|
|
mutex_lock(&m->portlock); |
|
|
|
@ -898,9 +896,7 @@ static int get_port(struct streamrelay *r, u_int16_t p) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void release_port(struct streamrelay *r) { |
|
|
|
struct callmaster *m = r->up->up->call->callmaster; |
|
|
|
|
|
|
|
static void release_port(struct streamrelay *r, struct callmaster *m) { |
|
|
|
if (r->fd == -1 || !r->localport) |
|
|
|
return; |
|
|
|
mutex_lock(&m->portlock); |
|
|
|
@ -911,7 +907,7 @@ static void release_port(struct streamrelay *r) { |
|
|
|
r->localport = 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void get_consecutive_ports(struct streamrelay *array, int array_len, int wanted_start_port, struct call *c) { |
|
|
|
static int get_consecutive_ports(struct streamrelay *array, int array_len, int wanted_start_port, struct call *c) { |
|
|
|
int i, j, cycle = 0; |
|
|
|
struct streamrelay *it; |
|
|
|
u_int16_t port; |
|
|
|
@ -942,14 +938,14 @@ static void get_consecutive_ports(struct streamrelay *array, int array_len, int |
|
|
|
goto release_restart; |
|
|
|
} |
|
|
|
|
|
|
|
if (get_port(it, port++)) |
|
|
|
if (get_port(it, port++, m)) |
|
|
|
goto release_restart; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
release_restart: |
|
|
|
for (j = 0; j < i; j++) |
|
|
|
release_port(&array[j]); |
|
|
|
release_port(&array[j], m); |
|
|
|
|
|
|
|
if (cycle >= 2 || wanted_start_port > 0) |
|
|
|
goto fail; |
|
|
|
@ -962,10 +958,11 @@ release_restart: |
|
|
|
|
|
|
|
mylog(LOG_DEBUG, LOG_PREFIX_CI "Opened ports %u..%u for RTP", |
|
|
|
LOG_PARAMS_CI(c), array[0].localport, array[array_len - 1].localport); |
|
|
|
return; |
|
|
|
return 0; |
|
|
|
|
|
|
|
fail: |
|
|
|
mylog(LOG_ERR, LOG_PREFIX_CI "Failed to get RTP port pair", LOG_PARAMS_CI(c)); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
/* caller is responsible for appropriate locking */ |
|
|
|
@ -1054,7 +1051,7 @@ static void steal_peer(struct peer *dest, struct peer *src) { |
|
|
|
mylog(LOG_DEBUG, LOG_PREFIX_CI "Closing port %u in favor of re-use", |
|
|
|
LOG_PARAMS_CI(c), sr->localport); |
|
|
|
poller_del_item(po, sr->fd); |
|
|
|
release_port(sr); |
|
|
|
release_port(sr, m); |
|
|
|
} |
|
|
|
|
|
|
|
sr->fd = srs->fd; |
|
|
|
@ -1087,10 +1084,12 @@ static void steal_peer(struct peer *dest, struct peer *src) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void callstream_init(struct callstream *s, int port1, int port2) { |
|
|
|
int i, j, tport; |
|
|
|
/* XXX no need for a full streamrelay struct, split it */ |
|
|
|
/* XXX return value? */ |
|
|
|
void callstream_init(struct callstream *s, struct relays_cache *rc) { |
|
|
|
int i, j; |
|
|
|
struct peer *p; |
|
|
|
struct streamrelay *r; |
|
|
|
struct streamrelay *r, *relay_AB; |
|
|
|
struct poller_item pi; |
|
|
|
struct call *c = s->call; |
|
|
|
struct poller *po = c->callmaster->poller; |
|
|
|
@ -1099,6 +1098,7 @@ void callstream_init(struct callstream *s, int port1, int port2) { |
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) { |
|
|
|
p = &s->peers[i]; |
|
|
|
relay_AB = rc ? rc->array_ptrs[i] : NULL; |
|
|
|
|
|
|
|
p->idx = i; |
|
|
|
p->up = s; |
|
|
|
@ -1111,15 +1111,11 @@ void callstream_init(struct callstream *s, int port1, int port2) { |
|
|
|
r->idx = j; |
|
|
|
r->up = p; |
|
|
|
r->last = poller_now; |
|
|
|
} |
|
|
|
|
|
|
|
tport = (i == 0) ? port1 : port2; |
|
|
|
|
|
|
|
if (tport >= 0) { |
|
|
|
get_consecutive_ports(p->rtps, 2, tport, c); |
|
|
|
|
|
|
|
for (j = 0; j < 2; j++) { |
|
|
|
r = &p->rtps[j]; |
|
|
|
if (relay_AB && relay_AB[j].fd != -1) { |
|
|
|
r->fd = relay_AB[j].fd; |
|
|
|
r->fd_family = relay_AB[j].fd_family; |
|
|
|
r->localport = relay_AB[j].localport; |
|
|
|
|
|
|
|
pi.fd = r->fd; |
|
|
|
pi.obj = &s->obj; |
|
|
|
@ -1128,15 +1124,21 @@ void callstream_init(struct callstream *s, int port1, int port2) { |
|
|
|
pi.closed = stream_closed; |
|
|
|
|
|
|
|
poller_add_item(po, &pi); |
|
|
|
|
|
|
|
relay_AB[j].fd = -1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (rc) |
|
|
|
relays_cache_port_used(rc); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void callstream_free(void *ptr) { |
|
|
|
struct callstream *s = ptr; |
|
|
|
struct callmaster *m = s->call->callmaster; |
|
|
|
int i, j; |
|
|
|
struct peer *p; |
|
|
|
struct streamrelay *r; |
|
|
|
@ -1146,13 +1148,63 @@ static void callstream_free(void *ptr) { |
|
|
|
|
|
|
|
for (j = 0; j < 2; j++) { |
|
|
|
r = &p->rtps[j]; |
|
|
|
release_port(r); |
|
|
|
release_port(r, m); |
|
|
|
} |
|
|
|
} |
|
|
|
mutex_destroy(&s->lock); |
|
|
|
obj_put(s->call); |
|
|
|
} |
|
|
|
|
|
|
|
static void relays_cache_init(struct relays_cache *c) { |
|
|
|
memset(c, -1, sizeof(*c)); |
|
|
|
c->relays_open = 0; |
|
|
|
c->array_ptrs[0] = c->relays_A; |
|
|
|
c->array_ptrs[1] = c->relays_B; |
|
|
|
} |
|
|
|
|
|
|
|
static int relays_cache_get_ports(struct relays_cache *c, int num, struct call *call) { |
|
|
|
num *= 2; |
|
|
|
if (c->relays_open >= num) |
|
|
|
return 0; |
|
|
|
|
|
|
|
if (c->relays_open + num > ARRAY_SIZE(c->relays_A)) |
|
|
|
return -1; |
|
|
|
if (get_consecutive_ports(&c->relays_A[c->relays_open], num, 0, call)) |
|
|
|
return -1; |
|
|
|
if (get_consecutive_ports(&c->relays_B[c->relays_open], num, 0, call)) |
|
|
|
return -1; |
|
|
|
c->relays_open += num; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void relays_cache_port_used(struct relays_cache *c) { |
|
|
|
if (c->relays_open < 2) |
|
|
|
return; |
|
|
|
|
|
|
|
c->relays_open -= 2; |
|
|
|
if (c->relays_open) { |
|
|
|
memmove(&c->relays_A[0], &c->relays_A[2], c->relays_open * sizeof(*c->relays_A)); |
|
|
|
memmove(&c->relays_B[0], &c->relays_B[2], c->relays_open * sizeof(*c->relays_B)); |
|
|
|
} |
|
|
|
c->relays_A[c->relays_open].fd = -1; |
|
|
|
c->relays_B[c->relays_open].fd = -1; |
|
|
|
} |
|
|
|
|
|
|
|
static void relays_cache_cleanup(struct relays_cache *c, struct callmaster *m) { |
|
|
|
int i; |
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(c->relays_A); i++) { |
|
|
|
if (c->relays_A[i].fd == -1) |
|
|
|
break; |
|
|
|
release_port(&c->relays_A[i], m); |
|
|
|
} |
|
|
|
for (i = 0; i < ARRAY_SIZE(c->relays_B); i++) { |
|
|
|
if (c->relays_B[i].fd == -1) |
|
|
|
break; |
|
|
|
release_port(&c->relays_B[i], m); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* called with call->lock held */ |
|
|
|
static int call_streams(struct call *c, GQueue *s, const str *tag, enum call_opmode opmode) { |
|
|
|
GQueue *q; |
|
|
|
@ -1163,8 +1215,10 @@ static int call_streams(struct call *c, GQueue *s, const str *tag, enum call_opm |
|
|
|
struct callstream *cs, *cs_o; |
|
|
|
struct peer *p, *p2; |
|
|
|
int ret = 1; |
|
|
|
struct relays_cache relays_cache; |
|
|
|
|
|
|
|
q = g_queue_new(); /* new callstreams list */ |
|
|
|
relays_cache_init(&relays_cache); |
|
|
|
|
|
|
|
for (i = s->head; i; i = i->next) { |
|
|
|
t = i->data; |
|
|
|
@ -1208,14 +1262,15 @@ found: |
|
|
|
mutex_lock(&cs->lock); |
|
|
|
|
|
|
|
if (!matched_relay) { |
|
|
|
/* nothing found to re-use, open new ports */ |
|
|
|
callstream_init(cs, 0, 0); |
|
|
|
/* nothing found to re-use, use new ports */ |
|
|
|
relays_cache_get_ports(&relays_cache, 1, c); |
|
|
|
callstream_init(cs, &relays_cache); |
|
|
|
p = &cs->peers[0]; |
|
|
|
setup_peer(p, t, tag); |
|
|
|
} |
|
|
|
else { |
|
|
|
/* re-use, so don't open new ports */ |
|
|
|
callstream_init(cs, -1, -1); |
|
|
|
/* re-use, so don't use new ports */ |
|
|
|
callstream_init(cs, NULL); |
|
|
|
if (matched_relay->up->idx == 0) { |
|
|
|
/* request/lookup came in the same order as before */ |
|
|
|
steal_peer(&cs->peers[0], &cs_o->peers[0]); |
|
|
|
@ -1299,7 +1354,8 @@ got_cs: |
|
|
|
cs_o = cs; |
|
|
|
cs = callstream_new(c, t->stream.num); |
|
|
|
mutex_lock(&cs->lock); |
|
|
|
callstream_init(cs, 0, 0); |
|
|
|
relays_cache_get_ports(&relays_cache, 1, c); |
|
|
|
callstream_init(cs, &relays_cache); |
|
|
|
steal_peer(&cs->peers[0], &cs_o->peers[0]); |
|
|
|
p = &cs->peers[1]; |
|
|
|
setup_peer(p, t, tag); |
|
|
|
@ -1332,6 +1388,7 @@ skip: |
|
|
|
c->callstreams = q; |
|
|
|
} |
|
|
|
|
|
|
|
relays_cache_cleanup(&relays_cache, c->callmaster); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
|