diff options
author | matteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b> | 2003-02-16 06:00:12 +0000 |
---|---|---|
committer | matteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b> | 2003-02-16 06:00:12 +0000 |
commit | 175c755fefa75d02deeff70541cd7821ce670678 (patch) | |
tree | 09bad30a14c0eef808c9d0d2720e797ff76c44f4 /channels | |
parent | dae2009f9537257ba729035caa92eb3661c93aa1 (diff) |
Sun Feb 16 07:00:01 CET 2003
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@616 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rwxr-xr-x | channels/chan_mgcp.c | 61 | ||||
-rwxr-xr-x | channels/chan_sip.c | 227 |
2 files changed, 242 insertions, 46 deletions
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 88a0d2cf0..08ef81499 100755 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -131,6 +131,7 @@ struct mgcp_endpoint { int outgoing; struct ast_channel *owner; struct ast_rtp *rtp; + struct sockaddr_in tmpdest; struct mgcp_endpoint *next; struct mgcp_gateway *parent; }; @@ -317,6 +318,7 @@ static int mgcp_hangup(struct ast_channel *ast) p->owner = NULL; if (strlen(p->cxident)) transmit_connection_del(p); + strcpy(p->cxident, ""); if (!p->alreadygone && (!p->outgoing || (ast->_state == AST_STATE_UP))) transmit_notify_request(p, "ro", 1); else @@ -324,8 +326,9 @@ static int mgcp_hangup(struct ast_channel *ast) ast->pvt->pvt = NULL; p->alreadygone = 0; p->outgoing = 0; - strcpy(p->cxident, ""); strcpy(p->callid, ""); + /* Reset temporary destination */ + memset(&p->tmpdest, 0, sizeof(p->tmpdest)); if (p->rtp) { ast_rtp_destroy(p->rtp); p->rtp = NULL; @@ -515,6 +518,7 @@ static struct ast_channel *mgcp_new(struct mgcp_endpoint *i, int state) tmp->pvt->indicate = mgcp_indicate; tmp->pvt->fixup = mgcp_fixup; tmp->pvt->send_digit = mgcp_senddigit; + tmp->pvt->bridge = ast_rtp_bridge; if (strlen(i->language)) strncpy(tmp->language, i->language, sizeof(tmp->language)-1); i->owner = tmp; @@ -951,8 +955,15 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_endpoint *p, struct as if (rtp) { ast_rtp_get_peer(rtp, &dest); } else { - dest.sin_addr = p->parent->ourip; - dest.sin_port = sin.sin_port; + if (p->tmpdest.sin_addr.s_addr) { + dest.sin_addr = p->tmpdest.sin_addr; + dest.sin_port = p->tmpdest.sin_port; + /* Reset temporary destination */ + memset(&p->tmpdest, 0, sizeof(p->tmpdest)); + } else { + dest.sin_addr = p->parent->ourip; + dest.sin_port = sin.sin_port; + } } printf("We're at %s port %d\n", inet_ntoa(p->parent->ourip), ntohs(sin.sin_port)); snprintf(v, sizeof(v), "v=0\r\n"); @@ -991,6 +1002,12 @@ static int transmit_modify_with_sdp(struct mgcp_endpoint *p, struct ast_rtp *rtp char local[256]; char tmp[80]; int x; + if (!strlen(p->cxident) && rtp) { + /* We don't have a CXident yet, store the destination and + wait a bit */ + ast_rtp_get_peer(rtp, &p->tmpdest); + return 0; + } snprintf(local, sizeof(local), "p:20"); for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) { if (p->capability & x) { @@ -1003,6 +1020,7 @@ static int transmit_modify_with_sdp(struct mgcp_endpoint *p, struct ast_rtp *rtp add_header(&resp, "L", local); add_header(&resp, "M", "sendrecv"); add_header(&resp, "X", p->txident); + add_header(&resp, "I", p->cxident); add_header(&resp, "S", ""); add_sdp(&resp, p, rtp); p->lastout = oseq; @@ -1278,8 +1296,14 @@ static int mgcpsock_read(int *id, int fd, short events, void *ignore) p = find_endpoint(NULL, ident, &sin); if (p) { handle_response(p, result, ident); - if ((c = get_header(&req, "I"))) - strncpy(p->cxident, c, sizeof(p->cxident) - 1); + if ((c = get_header(&req, "I"))) { + if (strlen(c)) { + strncpy(p->cxident, c, sizeof(p->cxident) - 1); + if (p->tmpdest.sin_addr.s_addr) { + transmit_modify_with_sdp(p, NULL); + } + } + } if (req.lines) process_sdp(p, &req); } @@ -1483,6 +1507,31 @@ struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) return gw; } +static struct ast_rtp *mgcp_get_rtp_peer(struct ast_channel *chan) +{ + struct mgcp_endpoint *p; + p = chan->pvt->pvt; + if (p && p->rtp) + return p->rtp; + return NULL; +} + +static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp) +{ + struct mgcp_endpoint *p; + p = chan->pvt->pvt; + if (p) { + transmit_modify_with_sdp(p, rtp); + return 0; + } + return -1; +} + +static struct ast_rtp_protocol mgcp_rtp = { + get_rtp_info: mgcp_get_rtp_peer, + set_rtp_peer: mgcp_set_rtp_peer, +}; + int load_module() { struct ast_config *cfg; @@ -1590,6 +1639,8 @@ int load_module() ast_destroy(cfg); return -1; } + mgcp_rtp.type = type; + ast_rtp_proto_register(&mgcp_rtp); ast_cli_register(&cli_show_endpoints); /* And start the monitor for the first time */ restart_monitor(); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b9f235c3c..a057eb89e 100755 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -32,6 +32,7 @@ #include <asterisk/cli.h> #include <asterisk/md5.h> #include <asterisk/app.h> +#include <asterisk/musiconhold.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/if.h> @@ -47,8 +48,12 @@ /* #define VOCAL_DATA_HACK */ #define SIPDUMPER -#define DEFAULT_EXPIREY 120 -#define MAX_EXPIREY 3600 +#define DEFAULT_DEFAULT_EXPIREY 120 +#define DEFAULT_MAX_EXPIREY 3600 + +static int max_expirey = DEFAULT_MAX_EXPIREY; +static int default_expirey = DEFAULT_DEFAULT_EXPIREY; + #define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */ #define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */ @@ -142,6 +147,7 @@ static struct sip_pvt { char refer_to[AST_MAX_EXTENSION]; /* Place to store REFER-TO extension */ char referred_by[AST_MAX_EXTENSION];/* Place to store REFERRED-BY extension */ char refer_contact[AST_MAX_EXTENSION];/* Place to store Contact info from a REFER extension */ + struct sip_pvt *refer_call; /* Call we are referring */ char record_route[256]; char record_route_info[256]; char remote_party_id[256]; @@ -728,6 +734,7 @@ static int sip_indicate(struct ast_channel *ast, int condition) } +#if 0 static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) { struct sip_pvt *p0, *p1; @@ -742,6 +749,7 @@ static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, ast_pthread_mutex_lock(&c1->lock); p0 = c0->pvt->pvt; p1 = c1->pvt->pvt; + ast_log(LOG_DEBUG, "Reinvite? %s: %s, %s: %s\n", c0->name, p0->canreinvite ? "yes" : "no", c1->name, p1->canreinvite ? "yes" : "no"); if (!p0->canreinvite || !p1->canreinvite) { /* Not gonna support reinvite */ ast_pthread_mutex_unlock(&c0->lock); @@ -796,6 +804,7 @@ static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, } return -1; } +#endif static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title) { @@ -808,7 +817,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title) tmp->nativeformats = capability; fmt = ast_best_codec(tmp->nativeformats); if (title) - snprintf(tmp->name, sizeof(tmp->name), "SIP/%s", title); + snprintf(tmp->name, sizeof(tmp->name), "SIP/%s-%04x", title, rand() & 0xffff); else snprintf(tmp->name, sizeof(tmp->name), "SIP/%s:%d", inet_ntoa(i->sa.sin_addr), ntohs(i->sa.sin_port)); tmp->type = type; @@ -830,7 +839,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title) tmp->pvt->indicate = sip_indicate; tmp->pvt->fixup = sip_fixup; tmp->pvt->send_digit = sip_senddigit; - tmp->pvt->bridge = sip_bridge; + tmp->pvt->bridge = ast_rtp_bridge; if (strlen(i->language)) strncpy(tmp->language, i->language, sizeof(tmp->language)-1); i->owner = tmp; @@ -1087,7 +1096,7 @@ static int sip_register(char *value, int lineno) if (secret) strncpy(reg->secret, secret, sizeof(reg->secret)-1); reg->expire = -1; - reg->refresh = DEFAULT_EXPIREY; + reg->refresh = default_expirey; reg->addr.sin_family = AF_INET; memcpy(®->addr.sin_addr, hp->h_addr, sizeof(®->addr.sin_addr)); reg->addr.sin_port = porta ? htons(atoi(porta)) : htons(DEFAULT_SIP_PORT); @@ -1237,11 +1246,21 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req) ast_log(LOG_WARNING, "No compatible codecs!\n"); return -1; } - if (p->owner && !(p->owner->nativeformats & p->capability)) { - ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %d and not %d\n", p->capability, p->owner->nativeformats); - p->owner->nativeformats = p->capability; - ast_set_read_format(p->owner, p->owner->readformat); - ast_set_write_format(p->owner, p->owner->writeformat); + if (p->owner) { + if (p->owner->nativeformats & p->capability) { + ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %d and not %d\n", p->capability, p->owner->nativeformats); + p->owner->nativeformats = p->capability; + ast_set_read_format(p->owner, p->owner->readformat); + ast_set_write_format(p->owner, p->owner->writeformat); + } + if (p->owner->bridge) { + /* Turn on/off music on hold if we are holding/unholding */ + if (sin.sin_addr.s_addr) { + ast_moh_stop(p->owner->bridge); + } else { + ast_moh_start(p->owner->bridge, NULL); + } + } } return 0; @@ -1830,7 +1849,7 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth) if (auth) add_header(&req, "Authorization", auth); - snprintf(tmp, sizeof(tmp), "%d", DEFAULT_EXPIREY); + snprintf(tmp, sizeof(tmp), "%d", default_expirey); add_header(&req, "Expires", tmp); add_header(&req, "Event", "registration"); copy_request(&p->initreq, &req); @@ -1933,8 +1952,8 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req strcpy(p->username, ""); if (p->expire > -1) ast_sched_del(sched, p->expire); - if ((expirey < 1) || (expirey > MAX_EXPIREY)) - expirey = DEFAULT_EXPIREY; + if ((expirey < 1) || (expirey > max_expirey)) + expirey = max_expirey; p->expire = ast_sched_add(sched, expirey * 1000, expire_register, p); pvt->expirey = expirey; if (memcmp(&p->addr, &oldsin, sizeof(oldsin))) { @@ -2130,7 +2149,9 @@ static int get_refer_info(struct sip_pvt *p, struct sip_request *oreq) char tmp2[256] = "", *c2, *a2; char tmp3[256]; char tmp4[256]; + char tmp5[256] = ""; /* CallID to replace */ struct sip_request *req; + struct sip_pvt *p2; req = oreq; if (!req) @@ -2151,32 +2172,81 @@ static int get_refer_info(struct sip_pvt *p, struct sip_request *oreq) } c += 4; c2 += 4; - if ((a = strchr(c, '@')) || (a = strchr(c, ';'))) { + if ((a = strchr(c, '?'))) { + /* Search for arguemnts */ *a = '\0'; + a++; + if (!strncasecmp(a, "REPLACES=", strlen("REPLACES="))) { + strncpy(tmp5, a + strlen("REPLACES="), sizeof(tmp5) - 1); + if ((a = strchr(tmp5, '%'))) { + /* Yuck! Pingtel converts the '@' to a %40, icky icky! Convert + back to an '@' */ + if ((a[1] == '4') && (a[2] == '0')) { + *a = '@'; + memmove(a + 1, a+3, strlen(a + 3)); + } + } + if ((a = strchr(tmp5, '%'))) + *a = '\0'; + } } - if ((a2 = strchr(c2, '@')) || (a2 = strchr(c2, ';'))) { + + if ((a = strchr(c, '@'))) + *a = '\0'; + if ((a = strchr(c, ';'))) + *a = '\0'; + + + if ((a2 = strchr(c2, '@'))) *a2 = '\0'; - } + + if ((a2 = strchr(c2, ';'))) + *a2 = '\0'; + if (sipdebug) ast_verbose("Looking for %s in %s\n", c, p->context); ast_verbose("Looking for %s in %s\n", c2, p->context); - - if (ast_exists_extension(NULL, p->context, c, 1, NULL) && ast_exists_extension(NULL, p->context, c2, 1, NULL)) { - if (!oreq) - ast_log(LOG_DEBUG,"Something is wrong with this line.\n"); //This line is ignored for some reason.... - ast_log(LOG_DEBUG,"Assigning Extension %s to REFER-TO\n", c); - ast_log(LOG_DEBUG,"Assigning Extension %s to REFERRED-BY\n", c2); - ast_log(LOG_DEBUG,"Assigning Contact Info %s to REFER_CONTACT\n", tmp3); - ast_log(LOG_DEBUG,"Assigning Remote-Party-ID Info %s to REMOTE_PARTY_ID\n",tmp4); - strncpy(p->refer_to, c, sizeof(p->refer_to) - 1); - strncpy(p->referred_by, c2, sizeof(p->referred_by) - 1); - strncpy(p->refer_contact, tmp3, sizeof(p->refer_contact) - 1); - strncpy(p->remote_party_id, tmp4, sizeof(p->remote_party_id) - 1); + + if (strlen(tmp5)) { + /* This is a supervised transfer */ + ast_log(LOG_DEBUG,"Assigning Replace-Call-ID Info %s to REPLACE_CALL_ID\n",tmp5); + + strncpy(p->refer_to, "", sizeof(p->refer_to) - 1); + strncpy(p->referred_by, "", sizeof(p->referred_by) - 1); + strncpy(p->refer_contact, "", sizeof(p->refer_contact) - 1); + strncpy(p->remote_party_id, "", sizeof(p->remote_party_id) - 1); + p->refer_call = NULL; + ast_pthread_mutex_lock(&iflock); + /* Search interfaces and find the match */ + p2 = iflist; + while(p2) { + if (!strcmp(p2->callid, tmp5)) { + /* Go ahead and lock it before returning */ + ast_pthread_mutex_lock(&p2->lock); + p->refer_call = p2; + break; + } + p2 = p2->next; + } + ast_pthread_mutex_unlock(&iflock); + if (p->refer_call) return 0; - } - - if (ast_canmatch_extension(NULL, p->context, c, 1, NULL)) { + else + ast_log(LOG_NOTICE, "Supervised transfer requested, but unable to find callid '%s'\n", tmp5); + } else if (ast_exists_extension(NULL, p->context, c, 1, NULL) && ast_exists_extension(NULL, p->context, c2, 1, NULL)) { + /* This is an unsupervised transfer */ + ast_log(LOG_DEBUG,"Assigning Extension %s to REFER-TO\n", c); + ast_log(LOG_DEBUG,"Assigning Extension %s to REFERRED-BY\n", c2); + ast_log(LOG_DEBUG,"Assigning Contact Info %s to REFER_CONTACT\n", tmp3); + ast_log(LOG_DEBUG,"Assigning Remote-Party-ID Info %s to REMOTE_PARTY_ID\n",tmp4); + strncpy(p->refer_to, c, sizeof(p->refer_to) - 1); + strncpy(p->referred_by, c2, sizeof(p->referred_by) - 1); + strncpy(p->refer_contact, tmp3, sizeof(p->refer_contact) - 1); + strncpy(p->remote_party_id, tmp4, sizeof(p->remote_party_id) - 1); + p->refer_call = NULL; + return 0; + } else if (ast_canmatch_extension(NULL, p->context, c, 1, NULL)) { return 1; } @@ -2735,7 +2805,7 @@ retrylock: if (r->expire != -1) ast_sched_del(sched, r->expire); expires=atoi(get_header(req, "expires")); - if (!expires) expires=DEFAULT_EXPIREY; + if (!expires) expires=default_expirey; r->expire=ast_sched_add(sched, (expires-2)*1000, sip_reregister, r); } @@ -2879,6 +2949,37 @@ static int determine_firstline_parts( struct sip_request *req ) { return 1; } +static int attempt_transfer(struct sip_pvt *p1, struct sip_pvt *p2) +{ + if (!p1->owner || !p2->owner) { + ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n"); + return -1; + } + if (p1->owner->bridge) { + if (p2->owner->bridge) + ast_moh_stop(p2->owner->bridge); + ast_moh_stop(p1->owner->bridge); + ast_moh_stop(p1->owner); + ast_moh_stop(p2->owner); + if (ast_channel_masquerade(p2->owner, p1->owner->bridge)) { + ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p2->owner->name, p1->owner->bridge->name); + return -1; + } + } else if (p2->owner->bridge) { + ast_moh_stop(p2->owner->bridge); + ast_moh_stop(p2->owner); + ast_moh_stop(p1->owner); + if (ast_channel_masquerade(p1->owner, p2->owner->bridge)) { + ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p1->owner->name, p2->owner->bridge->name); + return -1; + } + } else { + ast_log(LOG_NOTICE, "Transfer attempted with no bridged calls to transfer\n"); + return -1; + } + return 0; +} + static int handle_request(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin) { struct sip_request resp; @@ -3048,16 +3149,23 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc transmit_response_with_allow(p, "404 Not Found", req); else if (res > 0) transmit_response_with_allow(p, "484 Address Incomplete", req); - else + else { transmit_response(p, "202 Accepted", req); - ast_log(LOG_DEBUG,"202 Accepted\n"); - c = p->owner; - if (c) { - transfer_to = c->bridge; - if (transfer_to) - ast_async_goto(transfer_to,"", p->refer_to,1, 1); + if (p->refer_call) { + ast_log(LOG_DEBUG,"202 Accepted (supervised)\n"); + attempt_transfer(p, p->refer_call); + ast_pthread_mutex_unlock(&p->refer_call->lock); + p->refer_call = NULL; + } else { + ast_log(LOG_DEBUG,"202 Accepted (blind)\n"); + c = p->owner; + if (c) { + transfer_to = c->bridge; + if (transfer_to) + ast_async_goto(transfer_to,"", p->refer_to,1, 1); + } + } } - } else if (!strcasecmp(cmd, "CANCEL") || !strcasecmp(cmd, "BYE")) { copy_request(&p->initreq, req); p->alreadygone = 1; @@ -3140,7 +3248,7 @@ static int sipsock_read(int *id, int fd, short events, void *ignore) /* Must have at least two headers */ return 1; } - /* Process request, with iflock held */ + /* Process request, with netlock held */ ast_pthread_mutex_lock(&netlock); p = find_call(&req, &sin); if (p) { @@ -3495,6 +3603,8 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v) peer->expirey = expirey; } peer->capability = capability; + /* Assume can reinvite */ + peer->canreinvite = 1; while(v) { if (!strcasecmp(v->name, "secret")) strncpy(peer->secret, v->value, sizeof(peer->secret)-1); @@ -3619,6 +3729,14 @@ static int reload_config() strncpy(context, v->value, sizeof(context)-1); } else if (!strcasecmp(v->name, "language")) { strncpy(language, v->value, sizeof(language)-1); + } else if (!strcasecmp(v->name, "maxexpirey")) { + max_expirey = atoi(v->value); + if (max_expirey < 1) + max_expirey = DEFAULT_MAX_EXPIREY; + } else if (!strcasecmp(v->name, "defaultexpirey")) { + default_expirey = atoi(v->value); + if (default_expirey < 1) + default_expirey = DEFAULT_DEFAULT_EXPIREY; } else if (!strcasecmp(v->name, "bindaddr")) { if (!(hp = gethostbyname(v->value))) { ast_log(LOG_WARNING, "Invalid address: %s\n", v->value); @@ -3743,6 +3861,31 @@ static int reload_config() return 0; } +static struct ast_rtp *sip_get_rtp_peer(struct ast_channel *chan) +{ + struct sip_pvt *p; + p = chan->pvt->pvt; + if (p && p->rtp && p->canreinvite) + return p->rtp; + return NULL; +} + +static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp) +{ + struct sip_pvt *p; + p = chan->pvt->pvt; + if (p) { + transmit_reinvite_with_sdp(p, rtp); + return 0; + } + return -1; +} + +static struct ast_rtp_protocol sip_rtp = { + get_rtp_info: sip_get_rtp_peer, + set_rtp_peer: sip_set_rtp_peer, +}; + int load_module() { int res; @@ -3761,6 +3904,8 @@ int load_module() ast_cli_register(&cli_show_registry); ast_cli_register(&cli_debug); ast_cli_register(&cli_no_debug); + sip_rtp.type = type; + ast_rtp_proto_register(&sip_rtp); sched = sched_context_create(); if (!sched) { ast_log(LOG_WARNING, "Unable to create schedule context\n"); |