[Asterisk-cvs] asterisk/channels chan_sip.c,1.864,1.865

kpfleming kpfleming
Mon Sep 26 19:10:58 CDT 2005


Update of /usr/cvsroot/asterisk/channels
In directory mongoose.digium.com:/tmp/cvs-serv23511/channels

Modified Files:
	chan_sip.c 
Log Message:
add basic SIP domain support (issue #4466, with major mods)


Index: chan_sip.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v
retrieving revision 1.864
retrieving revision 1.865
diff -u -d -r1.864 -r1.865
--- chan_sip.c	26 Sep 2005 03:05:37 -0000	1.864
+++ chan_sip.c	26 Sep 2005 23:07:50 -0000	1.865
@@ -74,6 +74,8 @@
 #include "asterisk/astobj.h"
 #include "asterisk/dnsmgr.h"
 #include "asterisk/devicestate.h"
+#include "asterisk/linkedlists.h"
+
 #ifdef OSP_SUPPORT
 #include "asterisk/astosp.h"
 #endif
@@ -464,6 +466,22 @@
 	char hop[0];
 };
 
+enum domain_mode {
+	SIP_DOMAIN_AUTO,
+	SIP_DOMAIN_CONFIG,
+};
+
+struct domain {
+	char domain[MAXHOSTNAMELEN];
+	char context[AST_MAX_EXTENSION];
+	enum domain_mode mode;
+	AST_LIST_ENTRY(domain) list;
+};
+
+static AST_LIST_HEAD_STATIC(domain_list, domain);
+
+int allow_external_invites;
+
 /* sip_history: Structure for saving transactions within a SIP dialog */
 struct sip_history {
 	char event[80];
@@ -870,6 +888,7 @@
 static int clear_realm_authentication(struct sip_auth *authlist);                            /* Clear realm authentication list (at reload) */
 static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno);   /* Add realm authentication in list */
 static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, char *realm);         /* Find authentication for a specific realm */
+static int check_sip_domain(const char *domain, char *context, size_t len); /* Check if domain is one of our local domains */
 static void append_date(struct sip_request *req);	/* Append date to SIP packet */
 static int determine_firstline_parts(struct sip_request *req);
 static void sip_dump_history(struct sip_pvt *dialog);	/* Dump history to LOG_DEBUG at end of dialog, before destroying data */
@@ -6075,6 +6094,7 @@
 	char iabuf[INET_ADDRSTRLEN];
 	char *name, *c;
 	char *t;
+	char *domain;
 
 	/* Terminate URI */
 	t = uri;
@@ -6098,10 +6118,21 @@
 		name = c;
 		ast_log(LOG_NOTICE, "Invalid to address: '%s' from %s (missing sip:) trying to use anyway...\n", c, ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
 	}
+
 	/* Strip off the domain name */
-	c = strchr(name, '@');
-	if (c) 
-		*c = '\0';
+	if ((c = strchr(name, '@'))) {
+		*c++ = '\0';
+		domain = c;
+		if ((c = strchr(domain, ':')))	/* Remove :port */
+			*c = '\0';
+		if (!AST_LIST_EMPTY(&domain_list)) {
+			if (!check_sip_domain(domain, NULL, 0)) {
+				transmit_response(p, "404 Not found (unknown domain)", &p->initreq);
+				return -3;
+			}
+		}
+	}
+
 	ast_copy_string(p->exten, name, sizeof(p->exten));
 	build_contact(p);
 	peer = find_peer(name, NULL, 1);
@@ -6192,6 +6223,7 @@
 	}
 	if (peer)
 		ASTOBJ_UNREF(peer,sip_destroy_peer);
+
 	return res;
 }
 
@@ -6226,8 +6258,8 @@
 /*--- get_destination: Find out who the call is for --*/
 static int get_destination(struct sip_pvt *p, struct sip_request *oreq)
 {
-	char tmp[256] = "", *c, *a;
-	char tmpf[256], *fr;
+	char tmp[256] = "", *uri, *a;
+	char tmpf[256], *from;
 	struct sip_request *req;
 	
 	req = oreq;
@@ -6235,60 +6267,84 @@
 		req = &p->initreq;
 	if (req->rlPart2)
 		ast_copy_string(tmp, req->rlPart2, sizeof(tmp));
+	uri = get_in_brackets(tmp);
 	
 	ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf));
 
-	if (pedanticsipchecking) {
-		ast_uri_decode(tmp);
-		ast_uri_decode(tmpf);
-	}
-
-	fr = get_in_brackets(tmpf);
-	c = get_in_brackets(tmp);
+	from = get_in_brackets(tmpf);
 	
-	if (strncmp(c, "sip:", 4)) {
-		ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
+	if (strncmp(uri, "sip:", 4)) {
+		ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", uri);
 		return -1;
 	}
-	c += 4;
-	if (!ast_strlen_zero(fr)) {
-		if (strncmp(fr, "sip:", 4)) {
-			ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", fr);
+	uri += 4;
+	if (!ast_strlen_zero(from)) {
+		if (strncmp(from, "sip:", 4)) {
+			ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", from);
 			return -1;
 		}
-		fr += 4;
+		from += 4;
 	} else
-		fr = NULL;
-	if ((a = strchr(c, '@'))) {
+		from = NULL;
+
+	if (pedanticsipchecking) {
+		ast_uri_decode(uri);
+		ast_uri_decode(from);
+	}
+
+	/* Get the target domain */
+	if ((a = strchr(uri, '@'))) {
+		char *colon;
 		*a = '\0';
 		a++;
+		colon = strchr(a, ':'); /* Remove :port */
+		if (colon)
+			*colon = '\0';
 		ast_copy_string(p->domain, a, sizeof(p->domain));
 	}
-	if ((a = strchr(c, ';'))) {
+	/* Skip any options */
+	if ((a = strchr(uri, ';'))) {
 		*a = '\0';
 	}
-	if (fr) {
-		if ((a = strchr(fr, ';')))
+
+	if (!AST_LIST_EMPTY(&domain_list)) {
+		char domain_context[AST_MAX_EXTENSION];
+
+		domain_context[0] = '\0';
+		if (!check_sip_domain(p->domain, domain_context, sizeof(domain_context))) {
+			if (allow_external_invites && (req->method == SIP_INVITE || req->method == SIP_REFER)) {
+				ast_log(LOG_DEBUG, "Got SIP %s to non-local domain '%s'; refusing request.\n", sip_methods[req->method].text, p->domain);
+				return -2;
+			}
+		}
+		/* If we have a context defined, overwrite the original context */
+		if (!ast_strlen_zero(domain_context))
+			ast_copy_string(p->context, domain_context, sizeof(p->context));
+	}
+
+	if (from) {
+		if ((a = strchr(from, ';')))
 			*a = '\0';
-		if ((a = strchr(fr, '@'))) {
+		if ((a = strchr(from, '@'))) {
 			*a = '\0';
 			ast_copy_string(p->fromdomain, a + 1, sizeof(p->fromdomain));
 		} else
-			ast_copy_string(p->fromdomain, fr, sizeof(p->fromdomain));
+			ast_copy_string(p->fromdomain, from, sizeof(p->fromdomain));
 	}
-	if (pedanticsipchecking)
-		ast_uri_decode(c);
 	if (sip_debug_test_pvt(p))
-		ast_verbose("Looking for %s in %s\n", c, p->context);
-	if (ast_exists_extension(NULL, p->context, c, 1, fr) ||
-		!strcmp(c, ast_pickup_ext())) {
+		ast_verbose("Looking for %s in %s (domain %s)\n", uri, p->context, p->domain);
+
+	/* Return 0 if we have a matching extension */
+	if (ast_exists_extension(NULL, p->context, uri, 1, from) ||
+		!strcmp(uri, ast_pickup_ext())) {
 		if (!oreq)
-			ast_copy_string(p->exten, c, sizeof(p->exten));
+			ast_copy_string(p->exten, uri, sizeof(p->exten));
 		return 0;
 	}
 
-	if (ast_canmatch_extension(NULL, p->context, c, 1, fr) ||
-	    !strncmp(c, ast_pickup_ext(),strlen(c))) {
+	/* Return 1 for overlap dialling support */
+	if (ast_canmatch_extension(NULL, p->context, uri, 1, from) ||
+	    !strncmp(uri, ast_pickup_ext(),strlen(uri))) {
 		return 1;
 	}
 	
@@ -7472,6 +7528,39 @@
 		ast_cli(fd, "none");
 }
 
+static const char *domain_mode_to_text(const enum domain_mode mode)
+{
+	switch (mode) {
+	case SIP_DOMAIN_AUTO:
+		return "[Automatic]";
+	case SIP_DOMAIN_CONFIG:
+		return "[Configured]";
+	}
+
+	return "";
+}
+
+/*--- sip_show_domains: CLI command to list local domains */
+#define FORMAT "%-40.40s %-20.20s %-16.16s\n"
+static int sip_show_domains(int fd, int argc, char *argv[])
+{
+	struct domain *d;
+
+	if (AST_LIST_EMPTY(&domain_list)) {
+		ast_cli(fd, "SIP Domain support not enabled.\n\n");
+		return RESULT_SUCCESS;
+	} else {
+		ast_cli(fd, FORMAT, "Our local SIP domains:", "Context", "Set by");
+		AST_LIST_LOCK(&domain_list);
+		AST_LIST_TRAVERSE(&domain_list, d, list)
+			ast_cli(fd, FORMAT, d->domain, ast_strlen_zero(d->context) ? "(default)": d->context,
+				domain_mode_to_text(d->mode));
+		AST_LIST_UNLOCK(&domain_list);
+		ast_cli(fd, "\n");
+		return RESULT_SUCCESS;
+	}
+}
+#undef FORMAT
 
 static char mandescr_show_peer[] = 
 "Description: Show one SIP peer with details on current status.\n"
@@ -7806,6 +7895,8 @@
 	ast_cli(fd, "  AutoCreatePeer:         %s\n", autocreatepeer ? "Yes" : "No");
 	ast_cli(fd, "  Allow unknown access:   %s\n", global_allowguest ? "Yes" : "No");
 	ast_cli(fd, "  Promsic. redir:         %s\n", ast_test_flag(&global_flags, SIP_PROMISCREDIR) ? "Yes" : "No");
+	ast_cli(fd, "  SIP domain support:     %s\n", AST_LIST_EMPTY(&domain_list) ? "No" : "Yes");
+	ast_cli(fd, "  Call to non-local dom.: %s\n", allow_external_invites ? "Yes" : "No");
 	ast_cli(fd, "  URI user is phone no:   %s\n", ast_test_flag(&global_flags, SIP_USEREQPHONE) ? "Yes" : "No");
 	ast_cli(fd, "  Our auth realm          %s\n", global_realm);
 	ast_cli(fd, "  Realm. auth:            %s\n", authl ? "Yes": "No");
@@ -8682,7 +8773,10 @@
 	return 0;
 }
 	
-
+static char show_domains_usage[] = 
+"Usage: sip show domains\n"
+"       Lists all configured SIP local domains.\n"
+"       Asterisk only responds to SIP messages to local domains.\n";
 
 static char notify_usage[] =
 "Usage: sip notify <type> <peer> [<peer>...]\n"
@@ -8822,6 +8916,32 @@
 	.read = func_header_read,
 };
 
+/*--- function_check_sipdomain: Dial plan function to check if domain is local */
+static char *func_check_sipdomain(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
+{
+	if (!data || ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "CHECKSIPDOMAIN requires an argument - A domain name\n");
+		return buf;
+	}
+	if (check_sip_domain(data, NULL, 0))
+		ast_copy_string(buf, data, len);
+	else
+		buf[0] = '\0';
+	return buf;
+}
+
+static struct ast_custom_function checksipdomain_function = {
+	.name = "CHECKSIPDOMAIN",
+	.synopsis = "Checks if domain is a local domain",
+	.syntax = "CHECKSIPDOMAIN(<domain|IP>)",
+	.read = func_check_sipdomain,
+	.desc = "This function checks if the domain in the argument is configured\n"
+		"as a local SIP domain that this Asterisk server is configured to handle.\n"
+		"Returns the domain name if it is locally handled, otherwise an empty string.\n"
+		"Check the domain= configuration in sip.conf\n",
+};
+
+
 /*--- function_sippeer: ${SIPPEER()} Dialplan function - reads peer data */
 static char *function_sippeer(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
 {
@@ -8896,10 +9016,10 @@
 
 /* Structure to declare a dialplan function: SIPPEER */
 struct ast_custom_function sippeer_function = {
-    .name = "SIPPEER",
-    .synopsis = "Gets SIP peer information",
-    .syntax = "SIPPEER(<peername>[:item])",
-    .read = function_sippeer,
+	.name = "SIPPEER",
+	.synopsis = "Gets SIP peer information",
+	.syntax = "SIPPEER(<peername>[:item])",
+	.read = function_sippeer,
 	.desc = "Valid items are:\n"
 	"- ip (default)          The IP address.\n"
 	"- mailbox               The configured mailbox.\n"
@@ -9269,6 +9389,7 @@
 				if (sscanf(tmptmp + 8, "%d;", &expires) != 1)
 					expires = 0;
 			}
+
 		}
 		if (!expires) 
 			expires=atoi(get_header(req, "expires"));
@@ -9933,6 +10054,7 @@
 		}
 		/* Get destination right away */
 		gotdest = get_destination(p, NULL);
+
 		get_rdnis(p, NULL);
 		extract_uri(p, req);
 		build_contact(p);
@@ -10382,7 +10504,7 @@
 	copy_request(&p->initreq, req);
 	check_via(p, req);
 	if ((res = register_verify(p, sin, req, e, ignore)) < 0) 
-		ast_log(LOG_NOTICE, "Registration from '%s' failed for '%s' - %s\n", get_header(req, "To"), ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), (res == -1) ? "Wrong password" : "Username/auth name mismatch");
+		ast_log(LOG_NOTICE, "Registration from '%s' failed for '%s' - %s\n", get_header(req, "To"), ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), (res == -1) ? "Wrong password" : (res == -2 ? "Username/auth name mismatch" : "Not a local SIP domain"));
 	if (res < 1) {
 		/* Destroy the session, but keep us around for just a bit in case they don't
 		   get our 200 OK */
@@ -11171,6 +11293,73 @@
 	return res;
 }
 
+/*--- add_sip_domain: Add SIP domain to list of domains we are responsible for */
+static int add_sip_domain(const char *domain, const enum domain_mode mode, const char *context)
+{
+	struct domain *d;
+
+	if (!domain || ast_strlen_zero(domain)) {
+		ast_log(LOG_WARNING, "Zero length domain.\n");
+		return 1;
+	}
+
+	d = calloc(1, sizeof(*d));
+	if (!d) {
+		ast_log(LOG_ERROR, "Allocation of domain structure failed, Out of memory\n");
+		return 0;
+	}
+
+	ast_copy_string(d->domain, domain, sizeof(d->domain));
+
+	if (context && !ast_strlen_zero(context))
+		ast_copy_string(d->context, context, sizeof(d->context));
+
+	d->mode = mode;
+
+	AST_LIST_LOCK(&domain_list);
+	AST_LIST_INSERT_TAIL(&domain_list, d, list);
+	AST_LIST_UNLOCK(&domain_list);
+
+ 	if (sipdebug)	
+		ast_log(LOG_DEBUG, "Added local SIP domain '%s'\n", domain);
+
+	return 1;
+}
+
+/*--- check_sip_domain: Check if domain part of uri is local to our server */
+static int check_sip_domain(const char *domain, char *context, size_t len)
+{
+	struct domain *d;
+	int result = 0;
+
+	AST_LIST_LOCK(&domain_list);
+	AST_LIST_TRAVERSE(&domain_list, d, list) {
+		if (strcasecmp(d->domain, domain))
+			continue;
+
+		if (len && !ast_strlen_zero(d->context))
+			ast_copy_string(context, d->context, len);
+		
+		result = 1;
+		break;
+	}
+	AST_LIST_UNLOCK(&domain_list);
+
+	return result;
+}
+
+/*--- clear_sip_domains: Clear our domain list (at reload) */
+static void clear_sip_domains(void)
+{
+	struct domain *d;
+
+	AST_LIST_LOCK(&domain_list);
+	while ((d = AST_LIST_REMOVE_HEAD(&domain_list, list)))
+		free(d);
+	AST_LIST_UNLOCK(&domain_list);
+}
+
+
 /*--- add_realm_authentication: Add realm authentication in list ---*/
 static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno)
 {
@@ -11689,6 +11878,8 @@
 	int oldport = ntohs(bindaddr.sin_port);
 	char iabuf[INET_ADDRSTRLEN];
 	struct ast_flags dummy;
+	int auto_sip_domains = 0;
+
 	
 	cfg = ast_config_load(config);
 
@@ -11711,6 +11902,7 @@
 	default_language[0] = '\0';
 	default_fromdomain[0] = '\0';
 	default_qualify = 0;
+	allow_external_invites = 1;	/* Allow external invites */
 	externhost[0] = '\0';
 	externexpire = 0;
 	externrefresh = 10;
@@ -11897,6 +12089,23 @@
 			ast_parse_allow_disallow(&prefs, &global_capability, v->value, 1);
 		} else if (!strcasecmp(v->name, "disallow")) {
 			ast_parse_allow_disallow(&prefs, &global_capability, v->value, 0);
+		} else if (!strcasecmp(v->name, "allowexternalinvites")) {
+			allow_external_invites = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "autodomain")) {
+			auto_sip_domains = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "domain")) {
+			char *domain = ast_strdupa(v->value);
+			char *context = strchr(domain, ',');
+
+			if (context)
+				*context++ = '\0';
+
+			if (ast_strlen_zero(domain))
+				ast_log(LOG_WARNING, "Empty domain specified at line %d\n", v->lineno);
+			else if (context && ast_strlen_zero(context))
+				ast_log(LOG_WARNING, "Empty context specified at line %d for domain '%s'\n", v->lineno, domain);
+			else
+				add_sip_domain(ast_strip(domain), SIP_DOMAIN_CONFIG, context ? ast_strip(context) : "");
 		} else if (!strcasecmp(v->name, "register")) {
 			sip_register(v->value, v->lineno);
 		} else if (!strcasecmp(v->name, "tos")) {
@@ -11925,6 +12134,11 @@
 		 */
 		 v = v->next;
 	}
+
+	if (!allow_external_invites && AST_LIST_EMPTY(&domain_list)) {
+		ast_log(LOG_WARNING, "To disallow external INVITEs, you need to configure local SIP domains.\n");
+		allow_external_invites = 1;
+	}
 	
 	/* Build list of authentication to various SIP realms, i.e. service providers */
  	v = ast_variable_browse(cfg, "authentication");
@@ -11994,7 +12208,7 @@
 				sipsock = -1;
 			} else {
 				if (option_verbose > 1) { 
-						ast_verbose(VERBOSE_PREFIX_2 "SIP Listening on %s:%d\n", 
+					ast_verbose(VERBOSE_PREFIX_2 "SIP Listening on %s:%d\n", 
 					ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port));
 					ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos);
 				}
@@ -12005,6 +12219,36 @@
 	}
 	ast_mutex_unlock(&netlock);
 
+	/* Add default domains - host name, IP address and IP:port */
+	/* Only do this if user added any sip domain with "localdomains" */
+	/* In order to *not* break backwards compatibility */
+	/* 	Some phones address us at IP only, some with additional port number */
+	if (auto_sip_domains) {
+		char temp[MAXHOSTNAMELEN];
+
+		/* First our default IP address */
+		if (bindaddr.sin_addr.s_addr) {
+			ast_inet_ntoa(temp, sizeof(temp), bindaddr.sin_addr);
+			add_sip_domain(temp, SIP_DOMAIN_AUTO, NULL);
+		} else {
+			ast_log(LOG_NOTICE, "Can't add wildcard IP address to domain list, please add IP address to domain manually.\n");
+		}
+
+		/* Our extern IP address, if configured */
+		if (externip.sin_addr.s_addr) {
+			ast_inet_ntoa(temp, sizeof(temp), externip.sin_addr);
+			add_sip_domain(temp, SIP_DOMAIN_AUTO, NULL);
+		}
+
+		/* Extern host name (NAT traversal support) */
+		if (!ast_strlen_zero(externhost))
+			add_sip_domain(externhost, SIP_DOMAIN_AUTO, NULL);
+		
+		/* Our host name */
+		if (!gethostname(temp, sizeof(temp)))
+			add_sip_domain(temp, SIP_DOMAIN_AUTO, NULL);
+	}
+
 	/* Release configuration from memory */
 	ast_config_destroy(cfg);
 
@@ -12372,6 +12616,7 @@
 static int sip_do_reload(void)
 {
 	clear_realm_authentication(authl);
+	clear_sip_domains();
 	authl = NULL;
 
 	ASTOBJ_CONTAINER_DESTROYALL(&userl, sip_destroy_user);
@@ -12408,7 +12653,6 @@
 	return sip_reload(0, 0, NULL);
 }
 
-// static struct ast_cli_entry  cli_sip_reload =
 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 },
@@ -12418,6 +12662,7 @@
 	{ { "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  },
 	{ { "sip", "debug", NULL }, sip_do_debug, "Enable SIP debugging", debug_usage },
 	{ { "sip", "debug", "ip", NULL }, sip_do_debug, "Enable SIP debugging on IP", debug_usage },
@@ -12480,6 +12725,7 @@
 	ast_custom_function_register(&sip_header_function);
 	ast_custom_function_register(&sippeer_function);
 	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,
@@ -12506,12 +12752,13 @@
 	ast_custom_function_unregister(&sipchaninfo_function);
 	ast_custom_function_unregister(&sippeer_function);
 	ast_custom_function_unregister(&sip_header_function);
+	ast_custom_function_unregister(&checksipdomain_function);
 
 	ast_unregister_application(app_dtmfmode);
 	ast_unregister_application(app_sipaddheader);
 	ast_unregister_application(app_sipgetheader);
 
-	ast_cli_unregister_multiple(my_clis, sizeof(my_clis)/ sizeof(my_clis[0]));
+	ast_cli_unregister_multiple(my_clis, sizeof(my_clis) / sizeof(my_clis[0]));
 
 	ast_rtp_proto_unregister(&sip_rtp);
 
@@ -12578,6 +12825,7 @@
 	ASTOBJ_CONTAINER_DESTROY(&regl);
 
 	clear_realm_authentication(authl);
+	clear_sip_domains();
 	close(sipsock);
 		
 	return 0;




More information about the svn-commits mailing list