Newer
Older
ast_udptl_get_peer(pvt->udptl, &p->udptlredirip);
flag =1;
} else {
memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
}
if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
if (!p->pendinginvite) {
if (option_debug > 2) {
if (flag)
Russell Bryant
committed
ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
Russell Bryant
committed
ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip));
}
transmit_reinvite_with_t38_sdp(p);
} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
if (option_debug > 2) {
if (flag)
Russell Bryant
committed
ast_log(LOG_DEBUG, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
Russell Bryant
committed
ast_log(LOG_DEBUG, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip));
16021
16022
16023
16024
16025
16026
16027
16028
16029
16030
16031
16032
16033
16034
16035
16036
16037
}
ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
}
}
/* Reset lastrtprx timer */
p->lastrtprx = p->lastrtptx = time(NULL);
ast_mutex_unlock(&p->lock);
return 0;
} else { /* If we are handling sending 200 OK to the other side of the bridge */
if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE) && ast_test_flag(&pvt->flags[0], SIP_CAN_REINVITE)) {
ast_udptl_get_peer(pvt->udptl, &p->udptlredirip);
flag = 1;
} else {
memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
}
if (option_debug > 2) {
if (flag)
Russell Bryant
committed
ast_log(LOG_DEBUG, "Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
Russell Bryant
committed
ast_log(LOG_DEBUG, "Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip));
}
pvt->t38.state = T38_ENABLED;
p->t38.state = T38_ENABLED;
if (option_debug > 1) {
ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", pvt->t38.state, pvt->owner ? pvt->owner->name : "<none>");
ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", p->t38.state, chan ? chan->name : "<none>");
}
transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
p->lastrtprx = p->lastrtptx = time(NULL);
ast_mutex_unlock(&p->lock);
return 0;
}
}
/*! \brief Returns null if we can't reinvite audio (part of RTP interface) */
Joshua Colp
committed
static enum ast_rtp_get_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
Joshua Colp
committed
struct sip_pvt *p = NULL;
enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
if (!(p = chan->tech_pvt))
return AST_RTP_GET_FAILED;
Joshua Colp
committed
if (!(p->rtp)) {
ast_mutex_unlock(&p->lock);
return AST_RTP_GET_FAILED;
}
*rtp = p->rtp;
if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE))
res = AST_RTP_TRY_NATIVE;
Joshua Colp
committed
return res;
/*! \brief Returns null if we can't reinvite video (part of RTP interface) */
Joshua Colp
committed
static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
Joshua Colp
committed
struct sip_pvt *p = NULL;
enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
if (!(p = chan->tech_pvt))
return AST_RTP_GET_FAILED;
ast_mutex_lock(&p->lock);
Joshua Colp
committed
if (!(p->rtp)) {
ast_mutex_unlock(&p->lock);
return AST_RTP_GET_FAILED;
}
*rtp = p->vrtp;
if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE))
res = AST_RTP_TRY_NATIVE;
Joshua Colp
committed
return res;
}
/*! \brief Set the RTP peer for this call */
Kevin P. Fleming
committed
static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
int changed = 0;
p = chan->tech_pvt;
if (!p)
return -1;
ast_mutex_lock(&p->lock);
if (ast_test_flag(&p->flags[0], SIP_ALREADYGONE)) {
/* If we're destroyed, don't bother */
ast_mutex_unlock(&p->lock);
return 0;
}
Kevin P. Fleming
committed
/* if this peer cannot handle reinvites of the media stream to devices
that are known to be behind a NAT, then stop the process now
*/
if (nat_active && !ast_test_flag(&p->flags[0], SIP_CAN_REINVITE_NAT)) {
ast_mutex_unlock(&p->lock);
return 0;
}
if (rtp)
changed |= ast_rtp_get_peer(rtp, &p->redirip);
else
memset(&p->redirip, 0, sizeof(p->redirip));
if (vrtp)
changed |= ast_rtp_get_peer(vrtp, &p->vredirip);
else
memset(&p->vredirip, 0, sizeof(p->vredirip));
Olle Johansson
committed
if (codecs && (p->redircodecs != codecs)) {
p->redircodecs = codecs;
changed = 1;
}
if (changed && !ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
if (chan->_state != AST_STATE_UP) { /* We are in early state */
if (recordhistory)
append_history(p, "ExtInv", "Initial invite sent with remote bridge proposal.");
if (option_debug)
Russell Bryant
committed
ast_log(LOG_DEBUG, "Early remote bridge setting SIP '%s' - Sending media to %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip));
} else if (!p->pendinginvite) { /* We are up, and have no outstanding invite */
if (option_debug > 2) {
Russell Bryant
committed
ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's audio soon redirected to IP %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip));
}
} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
if (option_debug > 2) {
Russell Bryant
committed
ast_log(LOG_DEBUG, "Deferring reinvite on SIP '%s' - It's audio will be redirected to IP %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip));
}
/* We have a pending Invite. Send re-invite when we're done with the invite */
ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
p->lastrtprx = p->lastrtptx = time(NULL);
ast_mutex_unlock(&p->lock);
return 0;
static char *synopsis_dtmfmode = "Change the dtmfmode for a SIP call";
static char *descrip_dtmfmode = "SIPDtmfMode(inband|info|rfc2833): Changes the dtmfmode for a SIP call\n";
Olle Johansson
committed
static char *app_sipaddheader = "SIPAddHeader";
static char *synopsis_sipaddheader = "Add a SIP header to the outbound call";
static char *descrip_sipaddheader = ""
" SIPAddHeader(Header: Content)\n"
"Adds a header to a SIP call placed with DIAL.\n"
"Remember to user the X-header if you are adding non-standard SIP\n"
"headers, like \"X-Asterisk-Accountcode:\". Use this with care.\n"
"Adding the wrong headers may jeopardize the SIP dialog.\n"
"Always returns 0\n";
/*! \brief Set the DTMFmode for an outbound SIP call (application) */
static int sip_dtmfmode(struct ast_channel *chan, void *data)
{
struct sip_pvt *p;
char *mode;
if (data)
mode = (char *)data;
else {
ast_log(LOG_WARNING, "This application requires the argument: info, inband, rfc2833\n");
if (chan->tech != &sip_tech) {
ast_log(LOG_WARNING, "Call this application only on SIP incoming calls\n");
return 0;
}
p = chan->tech_pvt;
return 0;
}
ast_mutex_lock(&p->lock);
if (!strcasecmp(mode,"info")) {
ast_clear_flag(&p->flags[0], SIP_DTMF);
ast_set_flag(&p->flags[0], SIP_DTMF_INFO);
} else if (!strcasecmp(mode,"rfc2833")) {
ast_clear_flag(&p->flags[0], SIP_DTMF);
ast_set_flag(&p->flags[0], SIP_DTMF_RFC2833);
} else if (!strcasecmp(mode,"inband")) {
ast_clear_flag(&p->flags[0], SIP_DTMF);
ast_set_flag(&p->flags[0], SIP_DTMF_INBAND);
} else
ast_log(LOG_WARNING, "I don't know about this dtmf mode: %s\n",mode);
if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) {
if (!p->vad) {
p->vad = ast_dsp_new();
ast_dsp_set_features(p->vad, DSP_FEATURE_DTMF_DETECT);
} else {
if (p->vad) {
ast_dsp_free(p->vad);
p->vad = NULL;
}
/*! \brief Add a SIP header to an outbound INVITE */
Olle Johansson
committed
static int sip_addheader(struct ast_channel *chan, void *data)
{
int no = 0;
Olle Johansson
committed
char varbuf[30];
char *inbuf = (char *) data;
if (ast_strlen_zero(inbuf)) {
ast_log(LOG_WARNING, "This application requires the argument: Header\n");
return 0;
}
Olle Johansson
committed
/* Check for headers */
while (!ok && no <= 50) {
no++;
snprintf(varbuf, sizeof(varbuf), "_SIPADDHEADER%.2d", no);
if( (pbx_builtin_getvar_helper(chan, (const char *) varbuf) == (const char *) NULL) )
Olle Johansson
committed
}
if (ok) {
pbx_builtin_setvar_helper (chan, varbuf, inbuf);
if (sipdebug)
ast_log(LOG_DEBUG,"SIP Header added \"%s\" as %s\n", inbuf, varbuf);
} else {
ast_log(LOG_WARNING, "Too many SIP headers added, max 50\n");
}
Olle Johansson
committed
return 0;
}
/*! \brief Transfer call before connect with a 302 redirect
\note Called by the transfer() dialplan application through the sip_transfer()
pbx interface function if the call is in ringing state
\todo Fix this function so that we wait for reply to the REFER and
react to errors, denials or other issues the other end might have.
Mark Spencer
committed
static int sip_sipredirect(struct sip_pvt *p, const char *dest)
{
char *cdest;
char *extension, *host, *port;
char tmp[80];
Russell Bryant
committed
cdest = ast_strdupa(dest);
extension = strsep(&cdest, "@");
host = strsep(&cdest, ":");
port = strsep(&cdest, ":");
if (!extension) {
ast_log(LOG_ERROR, "Missing mandatory argument: extension\n");
return 0;
}
/* we'll issue the redirect message here */
if (!host) {
char *localtmp;
Kevin P. Fleming
committed
ast_copy_string(tmp, get_header(&p->initreq, "To"), sizeof(tmp));
Russell Bryant
committed
if (ast_strlen_zero(tmp)) {
ast_log(LOG_ERROR, "Cannot retrieve the 'To' header from the original SIP request!\n");
return 0;
}
if ((localtmp = strstr(tmp, "sip:")) && (localtmp = strchr(localtmp, '@'))) {
Russell Bryant
committed
char lhost[80], lport[80];
memset(lhost, 0, sizeof(lhost));
memset(lport, 0, sizeof(lport));
/* This is okey because lhost and lport are as big as tmp */
sscanf(localtmp, "%[^<>:; ]:%[^<>:; ]", lhost, lport);
Russell Bryant
committed
if (ast_strlen_zero(lhost)) {
ast_log(LOG_ERROR, "Can't find the host address\n");
return 0;
}
Russell Bryant
committed
host = ast_strdupa(lhost);
Russell Bryant
committed
if (!ast_strlen_zero(lport)) {
Russell Bryant
committed
port = ast_strdupa(lport);
Russell Bryant
committed
}
ast_string_field_build(p, our_contact, "Transfer <sip:%s@%s%s%s>", extension, host, port ? ":" : "", port ? port : "");
transmit_response_reliable(p, "302 Moved Temporarily", &p->initreq);
/* this is all that we want to send to that SIP device */
ast_set_flag(&p->flags[0], SIP_ALREADYGONE);
/* hangup here */
return -1;
}
/*! \brief Return SIP UA's codec (part of the RTP interface) */
static int sip_get_codec(struct ast_channel *chan)
{
struct sip_pvt *p = chan->tech_pvt;
return p->peercapability;
/*! \brief Send a poke to all known peers
Space them out 100 ms apart
XXX We might have a cool algorithm for this or use random - any suggestions?
*/
static void sip_poke_all_peers(void)
{
int ms = 0;
if (!speerobjs) /* No peers, just give up */
return;
ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
ASTOBJ_WRLOCK(iterator);
if (iterator->pokeexpire > -1)
ast_sched_del(sched, iterator->pokeexpire);
ms += 100;
iterator->pokeexpire = ast_sched_add(sched, ms, sip_poke_peer_s, iterator);
ASTOBJ_UNLOCK(iterator);
} while (0)
);
}
/*! \brief Send all known registrations */
static void sip_send_all_registers(void)
{
int regspacing;
if (!regobjs)
return;
regspacing = default_expiry * 1000/regobjs;
if (regspacing > 100)
regspacing = 100;
ms = regspacing;
ASTOBJ_CONTAINER_TRAVERSE(®l, 1, do {
ASTOBJ_WRLOCK(iterator);
if (iterator->expire > -1)
ast_sched_del(sched, iterator->expire);
ms += regspacing;
iterator->expire = ast_sched_add(sched, ms, sip_reregister, iterator);
ASTOBJ_UNLOCK(iterator);
} while (0)
);
static int sip_do_reload(enum channelreloadreason reason)
Olle Johansson
committed
if (option_debug > 3)
ast_log(LOG_DEBUG, "--------------- SIP reload started\n");
clear_realm_authentication(authl);
clear_sip_domains();
/* First, destroy all outstanding registry calls */
/* This is needed, since otherwise active registry entries will not be destroyed */
ASTOBJ_CONTAINER_TRAVERSE(®l, 1, do {
ASTOBJ_RDLOCK(iterator);
if (iterator->call) {
if (option_debug > 2)
ast_log(LOG_DEBUG, "Destroying active SIP dialog for registry %s@%s\n", iterator->username, iterator->hostname);
/* This will also remove references to the registry */
sip_destroy(iterator->call);
}
ASTOBJ_UNLOCK(iterator);
} while(0));
Olle Johansson
committed
/* Then, actually destroy users and registry */
ASTOBJ_CONTAINER_DESTROYALL(&userl, sip_destroy_user);
Olle Johansson
committed
if (option_debug > 3)
ast_log(LOG_DEBUG, "--------------- Done destroying user list\n");
ASTOBJ_CONTAINER_DESTROYALL(®l, sip_registry_destroy);
Olle Johansson
committed
if (option_debug > 3)
ast_log(LOG_DEBUG, "--------------- Done destroying registry list\n");
ASTOBJ_CONTAINER_MARKALL(&peerl);
reload_config(reason);
Olle Johansson
committed
/* Prune peers who still are supposed to be deleted */
ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, sip_destroy_peer);
Olle Johansson
committed
if (option_debug > 3)
ast_log(LOG_DEBUG, "--------------- Done destroying pruned peers\n");
Olle Johansson
committed
/* Send qualify (OPTIONS) to all peers */
Olle Johansson
committed
/* Register with all services */
sip_send_all_registers();
Olle Johansson
committed
if (option_debug > 3)
ast_log(LOG_DEBUG, "--------------- SIP reload done\n");
/*! \brief Force reload of module from cli */
static int sip_reload(int fd, int argc, char *argv[])
{
ast_mutex_lock(&sip_reload_lock);
if (sip_reloading) {
ast_verbose("Previous SIP reload not yet done\n");
} else {
if (fd)
sip_reloadreason = CHANNEL_CLI_RELOAD;
else
sip_reloadreason = CHANNEL_MODULE_RELOAD;
}
ast_mutex_unlock(&sip_reload_lock);
restart_monitor();
return 0;
}
/*! \brief reload: Part of Asterisk module interface */
static int reload(void)
{
return sip_reload(0, 0, NULL);
}
Kevin P. Fleming
committed
static struct ast_cli_entry my_clis[] = {
{ { "sip", "notify", NULL }, sip_notify, "Send a notify packet to a SIP peer", notify_usage, complete_sipnotify },
{ { "sip", "show", "objects", NULL }, sip_show_objects, "Show all SIP object allocations", show_objects_usage },
{ { "sip", "show", "users", NULL }, sip_show_users, "Show defined SIP users", show_users_usage },
{ { "sip", "show", "user", NULL }, sip_show_user, "Show details on specific SIP user", show_user_usage, complete_sip_show_user },
{ { "sip", "show", "subscriptions", NULL }, sip_show_subscriptions, "Show active SIP subscriptions", show_subscriptions_usage},
{ { "sip", "show", "channels", NULL }, sip_show_channels, "Show active SIP channels", show_channels_usage},
{ { "sip", "show", "channel", NULL }, sip_show_channel, "Show detailed SIP channel info", show_channel_usage, complete_sipch },
{ { "sip", "show", "history", NULL }, sip_show_history, "Show SIP dialog history", show_history_usage, complete_sipch },
{ { "sip", "show", "domains", NULL }, sip_show_domains, "List our local SIP domains.", show_domains_usage },
{ { "sip", "show", "settings", NULL }, sip_show_settings, "Show SIP global settings", show_settings_usage },
Kevin P. Fleming
committed
{ { "sip", "debug", NULL }, sip_do_debug, "Enable SIP debugging", debug_usage },
Kevin P. Fleming
committed
16463
16464
16465
16466
16467
16468
16469
16470
16471
16472
16473
16474
16475
16476
16477
16478
16479
{ { "sip", "debug", "ip", NULL }, sip_do_debug, "Enable SIP debugging on IP", debug_usage },
{ { "sip", "debug", "peer", NULL }, sip_do_debug, "Enable SIP debugging on Peername", debug_usage, complete_sip_debug_peer },
{ { "sip", "show", "peer", NULL }, sip_show_peer, "Show details on specific SIP peer", show_peer_usage, complete_sip_show_peer },
{ { "sip", "show", "peers", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage },
{ { "sip", "prune", "realtime", NULL }, sip_prune_realtime,
"Prune cached Realtime object(s)", prune_realtime_usage },
{ { "sip", "prune", "realtime", "peer", NULL }, sip_prune_realtime,
"Prune cached Realtime peer(s)", prune_realtime_usage, complete_sip_prune_realtime_peer },
{ { "sip", "prune", "realtime", "user", NULL }, sip_prune_realtime,
"Prune cached Realtime user(s)", prune_realtime_usage, complete_sip_prune_realtime_user },
{ { "sip", "show", "inuse", NULL }, sip_show_inuse, "List all inuse/limits", show_inuse_usage },
{ { "sip", "show", "registry", NULL }, sip_show_registry, "Show SIP registration status", show_reg_usage },
{ { "sip", "history", NULL }, sip_do_history, "Enable SIP history", history_usage },
{ { "sip", "no", "history", NULL }, sip_no_history, "Disable SIP history", no_history_usage },
{ { "sip", "no", "debug", NULL }, sip_no_debug, "Disable SIP debugging", no_debug_usage },
{ { "sip", "reload", NULL }, sip_reload, "Reload SIP configuration", sip_reload_usage },
};
/*! \brief load_module: PBX load module - initialization */
static int load_module(void)
ASTOBJ_CONTAINER_INIT(&userl); /* User object list */
ASTOBJ_CONTAINER_INIT(&peerl); /* Peer object list */
ASTOBJ_CONTAINER_INIT(®l); /* Registry object list */
sched = sched_context_create();
if (!sched) {
ast_log(LOG_WARNING, "Unable to create schedule context\n");
}
io = io_context_create();
if (!io) {
ast_log(LOG_WARNING, "Unable to create I/O context\n");
}
sip_reloadreason = CHANNEL_MODULE_LOAD;
reload_config(sip_reloadreason); /* Load the configuration from sip.conf */
/* Make sure we can register our sip channel type */
if (ast_channel_register(&sip_tech)) {
ast_log(LOG_ERROR, "Unable to register channel type 'SIP'\n");
/* Register all CLI functions for SIP */
Kevin P. Fleming
committed
ast_cli_register_multiple(my_clis, sizeof(my_clis)/ sizeof(my_clis[0]));
Kevin P. Fleming
committed
/* Tell the RTP subdriver that we're here */
ast_rtp_proto_register(&sip_rtp);
Kevin P. Fleming
committed
/* Tell the UDPTL subdriver that we're here */
ast_udptl_proto_register(&sip_udptl);
/* Register dialplan applications */
ast_register_application(app_dtmfmode, sip_dtmfmode, synopsis_dtmfmode, descrip_dtmfmode);
Olle Johansson
committed
ast_register_application(app_sipaddheader, sip_addheader, synopsis_sipaddheader, descrip_sipaddheader);
/* Register dialplan functions */
ast_custom_function_register(&sip_header_function);
ast_custom_function_register(&sippeer_function);
Kevin P. Fleming
committed
ast_custom_function_register(&sipchaninfo_function);
ast_custom_function_register(&checksipdomain_function);
/* Register manager commands */
ast_manager_register2("SIPpeers", EVENT_FLAG_SYSTEM, manager_sip_show_peers,
"List SIP peers (text format)", mandescr_show_peers);
ast_manager_register2("SIPshowpeer", EVENT_FLAG_SYSTEM, manager_sip_show_peer,
"Show SIP peer (text format)", mandescr_show_peer);
Kevin P. Fleming
committed
sip_poke_all_peers();
sip_send_all_registers();
/* And start the monitor for the first time */
restart_monitor();
return 0;
static int unload_module(void)
/* First, take us out of the channel type list */
ast_channel_unregister(&sip_tech);
Kevin P. Fleming
committed
ast_custom_function_unregister(&sipchaninfo_function);
ast_custom_function_unregister(&sippeer_function);
Kevin P. Fleming
committed
ast_custom_function_unregister(&sip_header_function);
ast_custom_function_unregister(&checksipdomain_function);
Kevin P. Fleming
committed
Olle Johansson
committed
ast_unregister_application(app_sipaddheader);
ast_cli_unregister_multiple(my_clis, sizeof(my_clis) / sizeof(my_clis[0]));
ast_rtp_proto_unregister(&sip_rtp);
ast_udptl_proto_unregister(&sip_udptl);
ast_manager_unregister("SIPpeers");
ast_manager_unregister("SIPshowpeer");
ast_mutex_lock(&iflock);
/* Hangup all interfaces if they have an owner */
for (p = iflist; p ; p = p->next) {
if (p->owner)
ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
ast_mutex_unlock(&iflock);
ast_mutex_lock(&monlock);
if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
pthread_cancel(monitor_thread);
pthread_kill(monitor_thread, SIGURG);
pthread_join(monitor_thread, NULL);
monitor_thread = AST_PTHREADT_STOP;
ast_mutex_unlock(&monlock);
ast_mutex_lock(&iflock);
/* Destroy all the interfaces and free their memory */
p = iflist;
while (p) {
pl = p;
p = p->next;
/* Free associated memory */
ast_mutex_destroy(&pl->lock);
if (pl->chanvars) {
ast_variables_destroy(pl->chanvars);
pl->chanvars = NULL;
}
free(pl);
}
iflist = NULL;
ast_mutex_unlock(&iflock);
Mark Spencer
committed
/* Free memory for local network address mask */
ASTOBJ_CONTAINER_DESTROYALL(&userl, sip_destroy_user);
ASTOBJ_CONTAINER_DESTROY(&userl);
ASTOBJ_CONTAINER_DESTROYALL(&peerl, sip_destroy_peer);
ASTOBJ_CONTAINER_DESTROY(&peerl);
ASTOBJ_CONTAINER_DESTROYALL(®l, sip_registry_destroy);
ASTOBJ_CONTAINER_DESTROY(®l);
clear_realm_authentication(authl);
clear_sip_domains();
close(sipsock);
sched_context_destroy(sched);
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Session Initiation Protocol (SIP)",
.load = load_module,
.unload = unload_module,
.reload = reload,
);