|
|
|
@ -218,8 +218,6 @@ struct ast_udptl {
|
|
|
|
|
udptl_fec_rx_buffer_t rx[UDPTL_BUF_MASK + 1];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static AST_RWLIST_HEAD_STATIC(protos, ast_udptl_protocol);
|
|
|
|
|
|
|
|
|
|
struct udptl_global_options {
|
|
|
|
|
unsigned int start; /*< The UDPTL start port */
|
|
|
|
|
unsigned int end; /*< The UDPTL end port */
|
|
|
|
@ -1186,164 +1184,6 @@ int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ast_udptl_proto_unregister(struct ast_udptl_protocol *proto)
|
|
|
|
|
{
|
|
|
|
|
AST_RWLIST_WRLOCK(&protos);
|
|
|
|
|
AST_RWLIST_REMOVE(&protos, proto, list);
|
|
|
|
|
AST_RWLIST_UNLOCK(&protos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ast_udptl_proto_register(struct ast_udptl_protocol *proto)
|
|
|
|
|
{
|
|
|
|
|
struct ast_udptl_protocol *cur;
|
|
|
|
|
|
|
|
|
|
AST_RWLIST_WRLOCK(&protos);
|
|
|
|
|
AST_RWLIST_TRAVERSE(&protos, cur, list) {
|
|
|
|
|
if (cur->type == proto->type) {
|
|
|
|
|
ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
|
|
|
|
|
AST_RWLIST_UNLOCK(&protos);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
AST_RWLIST_INSERT_TAIL(&protos, proto, list);
|
|
|
|
|
AST_RWLIST_UNLOCK(&protos);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct ast_udptl_protocol *get_proto(struct ast_channel *chan)
|
|
|
|
|
{
|
|
|
|
|
struct ast_udptl_protocol *cur = NULL;
|
|
|
|
|
|
|
|
|
|
AST_RWLIST_RDLOCK(&protos);
|
|
|
|
|
AST_RWLIST_TRAVERSE(&protos, cur, list) {
|
|
|
|
|
if (cur->type == ast_channel_tech(chan)->type)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
AST_RWLIST_UNLOCK(&protos);
|
|
|
|
|
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ast_udptl_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
|
|
|
|
|
{
|
|
|
|
|
struct ast_frame *f;
|
|
|
|
|
struct ast_channel *who;
|
|
|
|
|
struct ast_channel *cs[3];
|
|
|
|
|
struct ast_udptl *p0;
|
|
|
|
|
struct ast_udptl *p1;
|
|
|
|
|
struct ast_udptl_protocol *pr0;
|
|
|
|
|
struct ast_udptl_protocol *pr1;
|
|
|
|
|
struct ast_sockaddr ac0;
|
|
|
|
|
struct ast_sockaddr ac1;
|
|
|
|
|
struct ast_sockaddr t0;
|
|
|
|
|
struct ast_sockaddr t1;
|
|
|
|
|
void *pvt0;
|
|
|
|
|
void *pvt1;
|
|
|
|
|
int to;
|
|
|
|
|
|
|
|
|
|
ast_channel_lock_both(c0, c1);
|
|
|
|
|
pr0 = get_proto(c0);
|
|
|
|
|
pr1 = get_proto(c1);
|
|
|
|
|
if (!pr0) {
|
|
|
|
|
ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", ast_channel_name(c0));
|
|
|
|
|
ast_channel_unlock(c0);
|
|
|
|
|
ast_channel_unlock(c1);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (!pr1) {
|
|
|
|
|
ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", ast_channel_name(c1));
|
|
|
|
|
ast_channel_unlock(c0);
|
|
|
|
|
ast_channel_unlock(c1);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
pvt0 = ast_channel_tech_pvt(c0);
|
|
|
|
|
pvt1 = ast_channel_tech_pvt(c1);
|
|
|
|
|
p0 = pr0->get_udptl_info(c0);
|
|
|
|
|
p1 = pr1->get_udptl_info(c1);
|
|
|
|
|
if (!p0 || !p1) {
|
|
|
|
|
/* Somebody doesn't want to play... */
|
|
|
|
|
ast_channel_unlock(c0);
|
|
|
|
|
ast_channel_unlock(c1);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
if (pr0->set_udptl_peer(c0, p1)) {
|
|
|
|
|
ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", ast_channel_name(c0), ast_channel_name(c1));
|
|
|
|
|
memset(&ac1, 0, sizeof(ac1));
|
|
|
|
|
} else {
|
|
|
|
|
/* Store UDPTL peer */
|
|
|
|
|
ast_udptl_get_peer(p1, &ac1);
|
|
|
|
|
}
|
|
|
|
|
if (pr1->set_udptl_peer(c1, p0)) {
|
|
|
|
|
ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", ast_channel_name(c1), ast_channel_name(c0));
|
|
|
|
|
memset(&ac0, 0, sizeof(ac0));
|
|
|
|
|
} else {
|
|
|
|
|
/* Store UDPTL peer */
|
|
|
|
|
ast_udptl_get_peer(p0, &ac0);
|
|
|
|
|
}
|
|
|
|
|
ast_channel_unlock(c0);
|
|
|
|
|
ast_channel_unlock(c1);
|
|
|
|
|
cs[0] = c0;
|
|
|
|
|
cs[1] = c1;
|
|
|
|
|
cs[2] = NULL;
|
|
|
|
|
for (;;) {
|
|
|
|
|
if ((ast_channel_tech_pvt(c0) != pvt0) ||
|
|
|
|
|
(ast_channel_tech_pvt(c1) != pvt1) ||
|
|
|
|
|
(ast_channel_masq(c0) || ast_channel_masqr(c0) || ast_channel_masq(c1) || ast_channel_masqr(c1))) {
|
|
|
|
|
ast_debug(1, "Oooh, something is weird, backing out\n");
|
|
|
|
|
/* Tell it to try again later */
|
|
|
|
|
return -3;
|
|
|
|
|
}
|
|
|
|
|
to = -1;
|
|
|
|
|
ast_udptl_get_peer(p1, &t1);
|
|
|
|
|
ast_udptl_get_peer(p0, &t0);
|
|
|
|
|
if (ast_sockaddr_cmp(&t1, &ac1)) {
|
|
|
|
|
ast_debug(1, "Oooh, '%s' changed end address to %s\n",
|
|
|
|
|
ast_channel_name(c1), ast_sockaddr_stringify(&t1));
|
|
|
|
|
ast_debug(1, "Oooh, '%s' was %s\n",
|
|
|
|
|
ast_channel_name(c1), ast_sockaddr_stringify(&ac1));
|
|
|
|
|
ast_sockaddr_copy(&ac1, &t1);
|
|
|
|
|
}
|
|
|
|
|
if (ast_sockaddr_cmp(&t0, &ac0)) {
|
|
|
|
|
ast_debug(1, "Oooh, '%s' changed end address to %s\n",
|
|
|
|
|
ast_channel_name(c0), ast_sockaddr_stringify(&t0));
|
|
|
|
|
ast_debug(1, "Oooh, '%s' was %s\n",
|
|
|
|
|
ast_channel_name(c0), ast_sockaddr_stringify(&ac0));
|
|
|
|
|
ast_sockaddr_copy(&ac0, &t0);
|
|
|
|
|
}
|
|
|
|
|
who = ast_waitfor_n(cs, 2, &to);
|
|
|
|
|
if (!who) {
|
|
|
|
|
ast_debug(1, "Ooh, empty read...\n");
|
|
|
|
|
/* check for hangup / whentohangup */
|
|
|
|
|
if (ast_check_hangup(c0) || ast_check_hangup(c1))
|
|
|
|
|
break;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
f = ast_read(who);
|
|
|
|
|
if (!f) {
|
|
|
|
|
*fo = f;
|
|
|
|
|
*rc = who;
|
|
|
|
|
ast_debug(1, "Oooh, got a %s\n", f ? "digit" : "hangup");
|
|
|
|
|
/* That's all we needed */
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
if (f->frametype == AST_FRAME_MODEM) {
|
|
|
|
|
/* Forward T.38 frames if they happen upon us */
|
|
|
|
|
if (who == c0) {
|
|
|
|
|
ast_write(c1, f);
|
|
|
|
|
} else if (who == c1) {
|
|
|
|
|
ast_write(c0, f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ast_frfree(f);
|
|
|
|
|
}
|
|
|
|
|
/* Swap priority. Not that it's a big deal at this point */
|
|
|
|
|
cs[2] = cs[0];
|
|
|
|
|
cs[0] = cs[1];
|
|
|
|
|
cs[1] = cs[2];
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *handle_cli_udptl_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
|
|
|
|
{
|
|
|
|
|
switch (cmd) {
|
|
|
|
|