|
|
|
@ -305,6 +305,10 @@ static void unkernelize(struct packet_stream *); |
|
|
|
static void __stream_unkernelize(struct packet_stream *ps); |
|
|
|
static void stream_unkernelize(struct packet_stream *ps); |
|
|
|
static void __monologue_destroy(struct call_monologue *monologue); |
|
|
|
static struct interface_address *get_interface_from_address(struct local_interface *lif, struct in6_addr *addr); |
|
|
|
static struct interface_address *get_interface_address(struct local_interface *lif, int family); |
|
|
|
static struct local_interface *get_local_interface(struct callmaster *m, str *name); |
|
|
|
static const GQueue *get_interface_addresses(struct local_interface *lif, int family); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -573,7 +577,7 @@ void stream_msg_mh_src(struct packet_stream *ps, struct msghdr *mh) { |
|
|
|
} |
|
|
|
|
|
|
|
/* called lock-free */ |
|
|
|
static int stream_packet(struct stream_fd *sfd, str *s, struct sockaddr_in6 *fsin) { |
|
|
|
static int stream_packet(struct stream_fd *sfd, str *s, struct sockaddr_in6 *fsin, struct in6_addr *dst) { |
|
|
|
struct packet_stream *stream, |
|
|
|
*sink = NULL, |
|
|
|
*in_srtp, *out_srtp; |
|
|
|
@ -770,6 +774,23 @@ update_addr: |
|
|
|
update = 1; |
|
|
|
mutex_unlock(&stream->out_lock); |
|
|
|
|
|
|
|
/* check the destination address of the received packet against what we think our |
|
|
|
* local interface to use is */ |
|
|
|
if (dst && memcmp(dst, &media->local_address->addr, sizeof(*dst))) { |
|
|
|
struct interface_address *ifa; |
|
|
|
char ifa_buf[64]; |
|
|
|
smart_ntop(ifa_buf, dst, sizeof(ifa_buf)); |
|
|
|
ifa = get_interface_from_address(media->interface, dst); |
|
|
|
if (!ifa) |
|
|
|
ilog(LOG_ERROR, "No matching local interface for destination address %s found", ifa_buf); |
|
|
|
else { |
|
|
|
ilog(LOG_INFO, "Switching local interface to %s", ifa_buf); |
|
|
|
media->local_address = ifa; |
|
|
|
} |
|
|
|
update = 1; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
kernel_check: |
|
|
|
if (PS_ISSET(stream, NO_KERNEL_SUPPORT)) |
|
|
|
goto forward; |
|
|
|
@ -857,14 +878,16 @@ static void stream_fd_readable(int fd, void *p, uintptr_t u) { |
|
|
|
struct stream_fd *sfd = p; |
|
|
|
char buf[RTP_BUFFER_SIZE]; |
|
|
|
int ret, iters; |
|
|
|
struct sockaddr_storage ss; |
|
|
|
struct sockaddr_in6 sin6; |
|
|
|
struct sockaddr_in *sin; |
|
|
|
unsigned int sinlen; |
|
|
|
void *sinp; |
|
|
|
struct sockaddr_in6 sin6_src; |
|
|
|
int update = 0; |
|
|
|
struct call *ca; |
|
|
|
str s; |
|
|
|
struct msghdr mh; |
|
|
|
struct iovec iov; |
|
|
|
char control[128]; |
|
|
|
struct cmsghdr *cmh; |
|
|
|
struct in6_pktinfo *pi6; |
|
|
|
struct in6_addr *dst; |
|
|
|
|
|
|
|
if (sfd->fd.fd != fd) |
|
|
|
goto out; |
|
|
|
@ -880,9 +903,17 @@ static void stream_fd_readable(int fd, void *p, uintptr_t u) { |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
sinlen = sizeof(ss); |
|
|
|
ret = recvfrom(fd, buf + RTP_BUFFER_HEAD_ROOM, MAX_RTP_PACKET_SIZE, |
|
|
|
0, (struct sockaddr *) &ss, &sinlen); |
|
|
|
ZERO(mh); |
|
|
|
mh.msg_name = &sin6_src; |
|
|
|
mh.msg_namelen = sizeof(sin6_src); |
|
|
|
mh.msg_iov = &iov; |
|
|
|
mh.msg_iovlen = 1; |
|
|
|
mh.msg_control = control; |
|
|
|
mh.msg_controllen = sizeof(control); |
|
|
|
iov.iov_base = buf + RTP_BUFFER_HEAD_ROOM; |
|
|
|
iov.iov_len = MAX_RTP_PACKET_SIZE; |
|
|
|
|
|
|
|
ret = recvmsg(fd, &mh, 0); |
|
|
|
|
|
|
|
if (ret < 0) { |
|
|
|
if (errno == EINTR) |
|
|
|
@ -895,18 +926,16 @@ static void stream_fd_readable(int fd, void *p, uintptr_t u) { |
|
|
|
if (ret >= MAX_RTP_PACKET_SIZE) |
|
|
|
ilog(LOG_WARNING, "UDP packet possibly truncated"); |
|
|
|
|
|
|
|
sinp = &ss; |
|
|
|
if (ss.ss_family == AF_INET) { |
|
|
|
sin = sinp; |
|
|
|
sinp = &sin6; |
|
|
|
ZERO(sin6); |
|
|
|
sin6.sin6_family = AF_INET6; |
|
|
|
sin6.sin6_port = sin->sin_port; |
|
|
|
in4_to_6(&sin6.sin6_addr, sin->sin_addr.s_addr); |
|
|
|
dst = NULL; |
|
|
|
for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) { |
|
|
|
if (cmh->cmsg_level == IPPROTO_IPV6 && cmh->cmsg_type == IPV6_PKTINFO) { |
|
|
|
pi6 = (void *) CMSG_DATA(cmh); |
|
|
|
dst = &pi6->ipi6_addr; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
str_init_len(&s, buf + RTP_BUFFER_HEAD_ROOM, ret); |
|
|
|
ret = stream_packet(sfd, &s, sinp); |
|
|
|
ret = stream_packet(sfd, &s, &sin6_src, dst); |
|
|
|
if (ret == -1) { |
|
|
|
ilog(LOG_WARNING, "Write error on RTP socket"); |
|
|
|
call_destroy(sfd->call); |
|
|
|
@ -1357,6 +1386,12 @@ static void __set_tos(int fd, const struct call *c) { |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
static void __get_pktinfo(int fd) { |
|
|
|
int x; |
|
|
|
x = 1; |
|
|
|
setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &x, sizeof(x)); |
|
|
|
} |
|
|
|
|
|
|
|
static int get_port6(struct udp_fd *r, u_int16_t p, const struct call *c) { |
|
|
|
int fd; |
|
|
|
struct sockaddr_in6 sin; |
|
|
|
@ -1369,6 +1404,7 @@ static int get_port6(struct udp_fd *r, u_int16_t p, const struct call *c) { |
|
|
|
reuseaddr(fd); |
|
|
|
ipv6only(fd, 0); |
|
|
|
__set_tos(fd, c); |
|
|
|
__get_pktinfo(fd); |
|
|
|
|
|
|
|
ZERO(sin); |
|
|
|
sin.sin6_family = AF_INET6; |
|
|
|
@ -2804,7 +2840,7 @@ void callmaster_config_init(struct callmaster *m) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
struct local_interface *get_local_interface(struct callmaster *m, str *name) { |
|
|
|
static struct local_interface *get_local_interface(struct callmaster *m, str *name) { |
|
|
|
struct local_interface *lif; |
|
|
|
|
|
|
|
if (!name) |
|
|
|
@ -2814,7 +2850,7 @@ struct local_interface *get_local_interface(struct callmaster *m, str *name) { |
|
|
|
return lif; |
|
|
|
} |
|
|
|
|
|
|
|
const GQueue *get_interface_addresses(struct local_interface *lif, int family) { |
|
|
|
static const GQueue *get_interface_addresses(struct local_interface *lif, int family) { |
|
|
|
if (!lif) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
@ -2830,7 +2866,7 @@ const GQueue *get_interface_addresses(struct local_interface *lif, int family) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
struct interface_address *get_interface_address(struct local_interface *lif, int family) { |
|
|
|
static struct interface_address *get_interface_address(struct local_interface *lif, int family) { |
|
|
|
const GQueue *q; |
|
|
|
|
|
|
|
q = get_interface_addresses(lif, family); |
|
|
|
@ -2846,3 +2882,22 @@ void get_all_interface_addresses(GQueue *q, struct local_interface *lif, int fam |
|
|
|
else |
|
|
|
g_queue_append(q, get_interface_addresses(lif, AF_INET)); |
|
|
|
} |
|
|
|
|
|
|
|
static struct interface_address *get_interface_from_address(struct local_interface *lif, struct in6_addr *addr) { |
|
|
|
GQueue *q; |
|
|
|
GList *l; |
|
|
|
struct interface_address *ifa; |
|
|
|
|
|
|
|
if (IN6_IS_ADDR_V4MAPPED(addr)) |
|
|
|
q = &lif->ipv4; |
|
|
|
else |
|
|
|
q = &lif->ipv6; |
|
|
|
|
|
|
|
for (l = q->head; l; l = l->next) { |
|
|
|
ifa = l->data; |
|
|
|
if (!memcmp(&ifa->addr, addr, sizeof(*addr))) |
|
|
|
return ifa; |
|
|
|
} |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |