|
|
|
@ -123,6 +123,60 @@ const char *transport_protocol_strings[__PROTO_LAST] = { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int __k_null(struct mediaproxy_srtp *s, struct streamrelay *r); |
|
|
|
static int __k_srtp_encrypt(struct mediaproxy_srtp *s, struct streamrelay *r); |
|
|
|
static int __k_srtp_decrypt(struct mediaproxy_srtp *s, struct streamrelay *r); |
|
|
|
|
|
|
|
static int call_avp2savp_rtp(str *s, struct streamrelay *r); |
|
|
|
static int call_savp2avp_rtp(str *s, struct streamrelay *r); |
|
|
|
static int call_avp2savp_rtcp(str *s, struct streamrelay *r); |
|
|
|
static int call_savp2avp_rtcp(str *s, struct streamrelay *r); |
|
|
|
static int call_avpf2avp_rtcp(str *s, struct streamrelay *r); |
|
|
|
static int call_avpf2savp_rtcp(str *s, struct streamrelay *r); |
|
|
|
static int call_savpf2avp_rtcp(str *s, struct streamrelay *r); |
|
|
|
static int call_savpf2savp_rtcp(str *s, struct streamrelay *r); |
|
|
|
|
|
|
|
static const struct streamhandler __sh_noop = { |
|
|
|
.kernel_decrypt = __k_null, |
|
|
|
.kernel_encrypt = __k_null, |
|
|
|
}; |
|
|
|
static const struct streamhandler __sh_rtp_avp2savp = { |
|
|
|
.rewrite = call_avp2savp_rtp, |
|
|
|
.kernel_decrypt = __k_null, |
|
|
|
.kernel_encrypt = __k_srtp_encrypt, |
|
|
|
}; |
|
|
|
static const struct streamhandler __sh_rtp_savp2avp = { |
|
|
|
.rewrite = call_savp2avp_rtp, |
|
|
|
.kernel_decrypt = __k_srtp_decrypt, |
|
|
|
.kernel_encrypt = __k_null, |
|
|
|
}; |
|
|
|
static const struct streamhandler __sh_rtcp_avp2savp = { |
|
|
|
.rewrite = call_avp2savp_rtcp, |
|
|
|
}; |
|
|
|
static const struct streamhandler __sh_rtcp_savp2avp = { |
|
|
|
.rewrite = call_savp2avp_rtcp, |
|
|
|
}; |
|
|
|
static const struct streamhandler __sh_rtcp_avpf2avp = { |
|
|
|
.rewrite = call_avpf2avp_rtcp, |
|
|
|
}; |
|
|
|
static const struct streamhandler __sh_rtcp_avpf2savp = { |
|
|
|
.rewrite = call_avpf2savp_rtcp, |
|
|
|
}; |
|
|
|
static const struct streamhandler __sh_rtcp_savpf2avp = { |
|
|
|
.rewrite = call_savpf2avp_rtcp, |
|
|
|
}; |
|
|
|
static const struct streamhandler __sh_rtcp_savpf2savp = { |
|
|
|
.rewrite = call_savpf2savp_rtcp, |
|
|
|
}; |
|
|
|
|
|
|
|
static const struct mediaproxy_srtp __mps_null = { |
|
|
|
.cipher = MPC_NULL, |
|
|
|
.hmac = MPH_NULL, |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void call_destroy(struct call *); |
|
|
|
@ -161,7 +215,7 @@ void kernelize(struct callstream *c) { |
|
|
|
int i, j; |
|
|
|
struct peer *p, *pp; |
|
|
|
struct streamrelay *r, *rp; |
|
|
|
struct kernel_stream ks; |
|
|
|
struct mediaproxy_target_info mpt; |
|
|
|
struct callmaster *cm = c->call->callmaster; |
|
|
|
|
|
|
|
if (cm->conf.kernelfd < 0 || cm->conf.kernelid == -1) |
|
|
|
@ -169,7 +223,7 @@ void kernelize(struct callstream *c) { |
|
|
|
|
|
|
|
mylog(LOG_DEBUG, LOG_PREFIX_C "Kernelizing RTP streams", LOG_PARAMS_C(c->call)); |
|
|
|
|
|
|
|
ZERO(ks); |
|
|
|
ZERO(mpt); |
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) { |
|
|
|
p = &c->peers[i]; |
|
|
|
@ -184,29 +238,40 @@ void kernelize(struct callstream *c) { |
|
|
|
|
|
|
|
if (is_addr_unspecified(&r->peer_advertised.ip46) |
|
|
|
|| !r->fd.fd_family || !r->peer_advertised.port) |
|
|
|
continue; |
|
|
|
goto no_kernel_stream; |
|
|
|
if (!r->handler->kernel_decrypt |
|
|
|
|| !r->handler->kernel_encrypt) |
|
|
|
goto no_kernel_stream; |
|
|
|
|
|
|
|
ks.local_port = r->fd.localport; |
|
|
|
ks.tos = cm->conf.tos; |
|
|
|
ks.src.port = rp->fd.localport; |
|
|
|
ks.dest.port = r->peer.port; |
|
|
|
mpt.target_port = r->fd.localport; |
|
|
|
mpt.tos = cm->conf.tos; |
|
|
|
mpt.src_addr.port = rp->fd.localport; |
|
|
|
mpt.dst_addr.port = r->peer.port; |
|
|
|
|
|
|
|
if (IN6_IS_ADDR_V4MAPPED(&r->peer.ip46)) { |
|
|
|
ks.src.family = AF_INET; |
|
|
|
ks.src.ipv4 = cm->conf.ipv4; |
|
|
|
ks.dest.family = AF_INET; |
|
|
|
ks.dest.ipv4 = r->peer.ip46.s6_addr32[3]; |
|
|
|
mpt.src_addr.family = AF_INET; |
|
|
|
mpt.src_addr.ipv4 = cm->conf.ipv4; |
|
|
|
mpt.dst_addr.family = AF_INET; |
|
|
|
mpt.dst_addr.ipv4 = r->peer.ip46.s6_addr32[3]; |
|
|
|
} |
|
|
|
else { |
|
|
|
ks.src.family = AF_INET6; |
|
|
|
ks.src.ipv6 = cm->conf.ipv6; |
|
|
|
ks.dest.family = AF_INET6; |
|
|
|
ks.dest.ipv6 = r->peer.ip46; |
|
|
|
mpt.src_addr.family = AF_INET6; |
|
|
|
memcpy(mpt.src_addr.ipv6, &cm->conf.ipv6, sizeof(mpt.src_addr.ipv6)); |
|
|
|
mpt.dst_addr.family = AF_INET6; |
|
|
|
memcpy(mpt.dst_addr.ipv6, &r->peer.ip46, sizeof(mpt.src_addr.ipv6)); |
|
|
|
} |
|
|
|
|
|
|
|
r->handler->kernel_decrypt(&mpt.decrypt, r); |
|
|
|
r->handler->kernel_encrypt(&mpt.encrypt, r); |
|
|
|
|
|
|
|
ZERO(r->kstats); |
|
|
|
|
|
|
|
kernel_add_stream(cm->conf.kernelfd, &ks, 0); |
|
|
|
kernel_add_stream(cm->conf.kernelfd, &mpt, 0); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
no_kernel_stream: |
|
|
|
r->no_kernel_support = 1; |
|
|
|
} |
|
|
|
|
|
|
|
p->kernelized = 1; |
|
|
|
@ -216,10 +281,7 @@ void kernelize(struct callstream *c) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int __dummy_stream_handler(str *s, struct streamrelay *r) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
static int call_avpf2avp(str *s, struct streamrelay *r) { |
|
|
|
static int call_avpf2avp_rtcp(str *s, struct streamrelay *r) { |
|
|
|
return rtcp_avpf2avp(s); |
|
|
|
} |
|
|
|
static int call_avp2savp_rtp(str *s, struct streamrelay *r) { |
|
|
|
@ -260,25 +322,76 @@ static int call_savpf2savp_rtcp(str *s, struct streamrelay *r) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static stream_handler determine_handler(struct streamrelay *in) { |
|
|
|
if (in->peer.protocol == in->peer_advertised.protocol) |
|
|
|
goto dummy; |
|
|
|
if (in->peer_advertised.protocol == PROTO_UNKNOWN) |
|
|
|
goto dummy; |
|
|
|
static int __k_null(struct mediaproxy_srtp *s, struct streamrelay *r) { |
|
|
|
*s = __mps_null; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
static int __k_srtp_crypt(struct mediaproxy_srtp *s, struct crypto_context *c) { |
|
|
|
*s = (struct mediaproxy_srtp) { |
|
|
|
.cipher = c->crypto_suite->kernel_cipher, |
|
|
|
.hmac = c->crypto_suite->kernel_hmac, |
|
|
|
.mki = c->mki, |
|
|
|
.mki_len = c->mki_len, |
|
|
|
.last_index = c->s_l, |
|
|
|
.auth_tag_len = c->crypto_suite->srtp_auth_tag, |
|
|
|
}; |
|
|
|
memcpy(s->master_key, c->master_key, c->crypto_suite->master_key_len); |
|
|
|
memcpy(s->master_salt, c->master_salt, c->crypto_suite->master_salt_len); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
static int __k_srtp_encrypt(struct mediaproxy_srtp *s, struct streamrelay *r) { |
|
|
|
return __k_srtp_crypt(s, &r->crypto.out); |
|
|
|
} |
|
|
|
static int __k_srtp_decrypt(struct mediaproxy_srtp *s, struct streamrelay *r) { |
|
|
|
return __k_srtp_crypt(s, &r->other->crypto.in); |
|
|
|
} |
|
|
|
|
|
|
|
static const struct streamhandler *determine_handler_rtp(struct streamrelay *in) { |
|
|
|
switch (in->peer.protocol) { |
|
|
|
case PROTO_UNKNOWN: |
|
|
|
goto dummy; |
|
|
|
case PROTO_RTP_AVP: |
|
|
|
case PROTO_RTP_AVPF: |
|
|
|
switch (in->peer_advertised.protocol) { |
|
|
|
case PROTO_RTP_AVP: |
|
|
|
case PROTO_RTP_AVPF: |
|
|
|
return NULL; |
|
|
|
|
|
|
|
case PROTO_RTP_SAVP: |
|
|
|
case PROTO_RTP_SAVPF: |
|
|
|
return &__sh_rtp_avp2savp; |
|
|
|
|
|
|
|
default: |
|
|
|
abort(); |
|
|
|
} |
|
|
|
|
|
|
|
case PROTO_RTP_SAVP: |
|
|
|
case PROTO_RTP_SAVPF: |
|
|
|
switch (in->peer_advertised.protocol) { |
|
|
|
case PROTO_RTP_AVP: |
|
|
|
case PROTO_RTP_AVPF: |
|
|
|
return &__sh_rtp_savp2avp; |
|
|
|
|
|
|
|
case PROTO_RTP_SAVPF: |
|
|
|
case PROTO_RTP_SAVP: |
|
|
|
return NULL; |
|
|
|
|
|
|
|
default: |
|
|
|
abort(); |
|
|
|
} |
|
|
|
|
|
|
|
default: |
|
|
|
abort(); |
|
|
|
} |
|
|
|
} |
|
|
|
static const struct streamhandler *determine_handler_rtcp(struct streamrelay *in) { |
|
|
|
switch (in->peer.protocol) { |
|
|
|
case PROTO_RTP_AVP: |
|
|
|
switch (in->peer_advertised.protocol) { |
|
|
|
case PROTO_RTP_AVPF: |
|
|
|
goto dummy; |
|
|
|
return NULL; |
|
|
|
|
|
|
|
case PROTO_RTP_SAVP: |
|
|
|
case PROTO_RTP_SAVPF: |
|
|
|
return in->rtcp ? call_avp2savp_rtcp |
|
|
|
: call_avp2savp_rtp; |
|
|
|
return &__sh_rtcp_avp2savp; |
|
|
|
|
|
|
|
default: |
|
|
|
abort(); |
|
|
|
@ -288,11 +401,10 @@ static stream_handler determine_handler(struct streamrelay *in) { |
|
|
|
switch (in->peer_advertised.protocol) { |
|
|
|
case PROTO_RTP_AVP: |
|
|
|
case PROTO_RTP_AVPF: |
|
|
|
return in->rtcp ? call_savp2avp_rtcp |
|
|
|
: call_savp2avp_rtp; |
|
|
|
return &__sh_rtcp_savp2avp; |
|
|
|
|
|
|
|
case PROTO_RTP_SAVPF: |
|
|
|
goto dummy; |
|
|
|
return NULL; |
|
|
|
|
|
|
|
default: |
|
|
|
abort(); |
|
|
|
@ -301,17 +413,14 @@ static stream_handler determine_handler(struct streamrelay *in) { |
|
|
|
case PROTO_RTP_AVPF: |
|
|
|
switch (in->peer_advertised.protocol) { |
|
|
|
case PROTO_RTP_AVP: |
|
|
|
if (!in->rtcp) |
|
|
|
goto dummy; |
|
|
|
return call_avpf2avp; |
|
|
|
return &__sh_rtcp_avpf2avp; |
|
|
|
|
|
|
|
case PROTO_RTP_SAVP: |
|
|
|
return in->rtcp ? call_avpf2savp_rtcp |
|
|
|
: call_avp2savp_rtp; |
|
|
|
return &__sh_rtcp_avpf2savp; |
|
|
|
|
|
|
|
case PROTO_RTP_SAVPF: |
|
|
|
return in->rtcp ? call_avp2savp_rtcp |
|
|
|
: call_avp2savp_rtp; |
|
|
|
return &__sh_rtcp_avp2savp; |
|
|
|
|
|
|
|
default: |
|
|
|
abort(); |
|
|
|
} |
|
|
|
@ -319,17 +428,13 @@ static stream_handler determine_handler(struct streamrelay *in) { |
|
|
|
case PROTO_RTP_SAVPF: |
|
|
|
switch (in->peer_advertised.protocol) { |
|
|
|
case PROTO_RTP_AVP: |
|
|
|
return in->rtcp ? call_savpf2avp_rtcp |
|
|
|
: call_savp2avp_rtp; |
|
|
|
return &__sh_rtcp_savpf2avp; |
|
|
|
|
|
|
|
case PROTO_RTP_AVPF: |
|
|
|
return in->rtcp ? call_savp2avp_rtcp |
|
|
|
: call_savp2avp_rtp; |
|
|
|
return &__sh_rtcp_savp2avp; |
|
|
|
|
|
|
|
case PROTO_RTP_SAVP: |
|
|
|
if (!in->rtcp) |
|
|
|
goto dummy; |
|
|
|
return call_savpf2savp_rtcp; |
|
|
|
return &__sh_rtcp_savpf2savp; |
|
|
|
|
|
|
|
default: |
|
|
|
abort(); |
|
|
|
@ -338,9 +443,28 @@ static stream_handler determine_handler(struct streamrelay *in) { |
|
|
|
default: |
|
|
|
abort(); |
|
|
|
} |
|
|
|
} |
|
|
|
static const struct streamhandler *determine_handler(struct streamrelay *in) { |
|
|
|
const struct streamhandler *ret; |
|
|
|
|
|
|
|
if (in->peer.protocol == in->peer_advertised.protocol) |
|
|
|
goto dummy; |
|
|
|
if (in->peer.protocol == PROTO_UNKNOWN) |
|
|
|
goto dummy; |
|
|
|
if (in->peer_advertised.protocol == PROTO_UNKNOWN) |
|
|
|
goto dummy; |
|
|
|
|
|
|
|
if (in->rtcp) |
|
|
|
ret = determine_handler_rtcp(in); |
|
|
|
else |
|
|
|
ret = determine_handler_rtp(in); |
|
|
|
|
|
|
|
if (!ret) |
|
|
|
goto dummy; |
|
|
|
return ret; |
|
|
|
|
|
|
|
dummy: |
|
|
|
return __dummy_stream_handler; |
|
|
|
return &__sh_noop; |
|
|
|
} |
|
|
|
|
|
|
|
/* called with r->up (== cs) locked */ |
|
|
|
@ -392,7 +516,8 @@ static int stream_packet(struct streamrelay *sr_incoming, str *s, struct sockadd |
|
|
|
|
|
|
|
if (!sr_incoming->handler) |
|
|
|
sr_incoming->handler = determine_handler(sr_incoming); |
|
|
|
handler_ret = sr_incoming->handler(s, sr_incoming); |
|
|
|
if (sr_incoming->handler->rewrite) |
|
|
|
handler_ret = sr_incoming->handler->rewrite(s, sr_incoming); |
|
|
|
|
|
|
|
use_cand: |
|
|
|
if (p_incoming->confirmed || !p_incoming->filled || sr_incoming->idx != 0) |
|
|
|
@ -424,7 +549,7 @@ peerinfo: |
|
|
|
|
|
|
|
update = 1; |
|
|
|
|
|
|
|
if (sr_incoming->handler != __dummy_stream_handler) |
|
|
|
if (sr_incoming->no_kernel_support) |
|
|
|
goto forward; |
|
|
|
|
|
|
|
if (p_incoming->confirmed && p_outgoing->confirmed && p_outgoing->filled) |
|
|
|
@ -1592,6 +1717,7 @@ static void unkernelize(struct peer *p) { |
|
|
|
for (i = 0; i < 2; i++) { |
|
|
|
r = &p->rtps[i]; |
|
|
|
kernel_del_stream(p->up->call->callmaster->conf.kernelfd, r->fd.localport); |
|
|
|
r->no_kernel_support = 0; |
|
|
|
} |
|
|
|
|
|
|
|
p->kernelized = 0; |
|
|
|
|