[Freeswitch-svn] [commit] r3495 - freeswitch/trunk/src/mod/applications/mod_enum
Freeswitch SVN
anthm at freeswitch.org
Thu Nov 30 17:02:49 EST 2006
Author: anthm
Date: Thu Nov 30 17:02:49 2006
New Revision: 3495
Added:
freeswitch/trunk/src/mod/applications/mod_enum/
freeswitch/trunk/src/mod/applications/mod_enum/Makefile
freeswitch/trunk/src/mod/applications/mod_enum/mod_enum.c
Log:
mod_enum
Added: freeswitch/trunk/src/mod/applications/mod_enum/Makefile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_enum/Makefile Thu Nov 30 17:02:49 2006
@@ -0,0 +1,21 @@
+CFLAGS += -I$(BASE)/libs/udns
+LDFLAGS += -L$(BASE)/libs/udns -ludns
+LINKER=$(CC)
+
+all: depends $(MODNAME).$(DYNAMIC_LIB_EXTEN)
+
+depends:
+ MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) udns
+
+%.o: %.c
+ $(CC) -fPIC $(CFLAGS) -c -o $@ $<
+
+$(MODNAME).$(DYNAMIC_LIB_EXTEN): $(MODNAME).c
+ $(CC) $(CFLAGS) -fPIC -c $(MODNAME).c -o $(MODNAME).o
+ $(LINKER) $(SOLINK) -o $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(MODNAME).o $(LDFLAGS)
+
+clean:
+ rm -fr *.$(DYNAMIC_LIB_EXTEN) *.o *~
+
+install:
+ cp -f $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(PREFIX)/mod
Added: freeswitch/trunk/src/mod/applications/mod_enum/mod_enum.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_enum/mod_enum.c Thu Nov 30 17:02:49 2006
@@ -0,0 +1,708 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct at yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct at yahoo.com>
+ *
+ * mod_enum.c -- ENUM
+ *
+ */
+
+#include <switch.h>
+#include <udns.h>
+
+static const char modname[] = "mod_enum";
+
+struct enum_record {
+ int order;
+ int preference;
+ char *service;
+ char *route;
+ struct enum_record *next;
+};
+typedef struct enum_record enum_record_t;
+
+struct query {
+ const char *name; /* original query string */
+ char *number;
+ unsigned char dn[DNS_MAXDN];
+ enum dns_type qtyp; /* type of the query */
+ enum_record_t *results;
+};
+typedef struct query enum_query_t;
+
+struct route {
+ char *service;
+ char *regex;
+ char *replace;
+ struct route *next;
+};
+typedef struct route enum_route_t;
+
+static enum dns_class qcls = DNS_C_IN;
+
+
+static struct {
+ char *root;
+ switch_hash_t *routes;
+ enum_route_t *route_order;
+ switch_memory_pool_t *pool;
+} globals;
+
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_root, globals.root)
+
+
+static void add_route(char *service, char *regex, char *replace)
+{
+ enum_route_t *route, *rp;
+
+ if (!(route = malloc(sizeof(*route)))) {
+ return;
+ }
+
+ memset(route, 0, sizeof(*route));
+
+ route->service = strdup(service);
+ route->regex = strdup(regex);
+ route->replace = strdup(replace);
+
+ if (!globals.route_order) {
+ globals.route_order = route;
+ } else {
+ for (rp = globals.route_order; rp && rp->next; rp = rp->next);
+ rp->next = route;
+ }
+
+ if (!(rp = switch_core_hash_find(globals.routes, service))) {
+ switch_core_hash_insert(globals.routes, route->service, route);
+ }
+}
+
+
+static switch_status_t load_config(void)
+{
+ char *cf = "enum.conf";
+ switch_xml_t cfg, xml = NULL, param, settings, route, routes;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+ memset(&globals, 0, sizeof(globals));
+ if (switch_core_new_memory_pool(&globals.pool) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
+ status = SWITCH_STATUS_TERM;
+ goto done;
+ }
+
+ switch_core_hash_init(&globals.routes, globals.pool);
+
+ if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
+ status = SWITCH_STATUS_FALSE;
+ goto done;
+ }
+
+ if ((settings = switch_xml_child(cfg, "settings"))) {
+ for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+ if (!strcasecmp(var, "default-root")) {
+ set_global_root(val);
+ } else if (!strcasecmp(var, "log-level-trace")) {
+
+ }
+ }
+ }
+
+ if ((routes = switch_xml_child(cfg, "routes"))) {
+ for (route = switch_xml_child(routes, "route"); route; route = route->next) {
+ char *service = (char *) switch_xml_attr_soft(route, "service");
+ char *regex = (char *) switch_xml_attr_soft(route, "regex");
+ char *replace = (char *) switch_xml_attr_soft(route, "replace");
+
+ if (service && regex && replace) {
+ add_route(service, regex, replace);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Route!\n");
+ }
+ }
+ }
+
+ done:
+
+ if (xml) {
+ switch_xml_free(xml);
+ }
+
+ if (!globals.root) {
+ set_global_root("e164.org");
+ }
+
+ return status;
+
+}
+
+
+static char *reverse_number(char *in, char *root)
+{
+ switch_size_t len;
+ char *out = NULL;
+ char *y,*z;
+
+ if (!(in && root)) {
+ return NULL;
+ }
+
+ len = (strlen(in) * 2) + strlen(root) + 1;
+ if ((out = malloc(len))) {
+ memset(out, 0, len);
+
+ z = out;
+ for(y = in + (strlen(in) - 1); y; y--) {
+ if (*y > 47 && *y < 58) {
+ *z++ = *y;
+ *z++ = '.';
+ }
+ if (y == in) {
+ break;
+ }
+ }
+ strcat(z, root);
+ }
+
+ return out;
+}
+
+static void dnserror(enum_query_t *q, int errnum) {
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unable to lookup %s record for %s: %s\n",
+ dns_typename(q->qtyp), dns_dntosp(q->dn), dns_strerror(errnum));
+}
+
+
+static void add_result(enum_query_t *q, int order, int preference, char *service, char *route)
+{
+ enum_record_t *new_result, *rp, *prev = NULL;
+
+
+ if (!(new_result = malloc(sizeof(*new_result)))) {
+ return;
+ }
+
+ memset(new_result, 0, sizeof(*new_result));
+
+ new_result->order = order;
+ new_result->preference = preference;
+ new_result->service = strdup(service);
+ new_result->route = strdup(route);
+
+
+ if (!q->results) {
+ q->results = new_result;
+ return;
+ }
+
+ rp = q->results;
+
+ while(rp && strcmp(rp->service, new_result->service)) {
+ prev = rp;
+ rp = rp->next;
+ }
+
+ while(rp && !strcmp(rp->service, new_result->service) && new_result->order > rp->order) {
+ prev = rp;
+ rp = rp->next;
+ }
+
+ while (rp && !strcmp(rp->service, new_result->service) && new_result->preference > rp->preference) {
+ prev = rp;
+ rp = rp->next;
+ }
+
+ if (prev) {
+ new_result->next = rp;
+ prev->next = new_result;
+ } else {
+ new_result->next = rp;
+ q->results = new_result;
+ }
+}
+
+
+static void free_results(enum_record_t **results)
+{
+ enum_record_t *fp, *rp;
+
+ for(rp = *results; rp;) {
+ fp = rp;
+ switch_safe_free(fp->service);
+ switch_safe_free(fp->route);
+ switch_safe_free(fp);
+ rp = rp->next;
+ }
+ *results = NULL;
+}
+
+static void parse_rr(const struct dns_parse *p, enum_query_t *q, struct dns_rr *rr) {
+ const unsigned char *pkt = p->dnsp_pkt;
+ const unsigned char *end = p->dnsp_end;
+ const unsigned char *dptr = rr->dnsrr_dptr;
+ const unsigned char *dend = rr->dnsrr_dend;
+ unsigned char *dn = rr->dnsrr_dn;
+ const unsigned char *c;
+ char *ptr;
+ char flags;
+ int order;
+ int preference;
+ char *nme;
+ char *service = NULL;
+ char *regex = NULL;
+ char *replace = NULL;
+ int argc = 0;
+ char *argv[4] = {0};
+ int leap;
+
+ switch(rr->dnsrr_typ) {
+
+ case DNS_T_NAPTR: /* prio weight port targetDN */
+ c = dptr;
+ c += 2 + 2 + 2;
+ if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
+ c = dptr;
+
+ leap = *dn;
+ nme = (char *)dn+1;
+
+ order = dns_get16(c+0);
+ preference = dns_get16(c+2);
+ flags = (char) dns_get16(c+4);
+
+ if ((ptr = nme+leap)) {
+ service = nme;
+ *ptr++ = '\0';
+ argc = switch_separate_string(ptr, '!', argv, (sizeof(argv) / sizeof(argv[0])));
+ regex = argv[1];
+ replace = argv[2];
+ }
+
+ for(ptr = replace; ptr && *ptr; ptr++) {
+ if (*ptr == '\\') {
+ *ptr = '$';
+ }
+ }
+
+ if (flags && service && regex && replace) {
+ pcre *re = NULL;
+ int proceed = 0, ovector[30];
+ char substituted[1024] = "";
+ char rbuf[1024] = "";
+ char *uri;
+ enum_route_t *route;
+
+ switch_clean_re(re);
+
+ if ((proceed = switch_perform_regex(q->number, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
+ if (strchr(regex, '(')) {
+ switch_perform_substitution(re, proceed, replace, q->number, substituted, sizeof(substituted), ovector);
+ uri = substituted;
+ } else {
+ uri = replace;
+ }
+
+ if ((route = (enum_route_t *) switch_core_hash_find(globals.routes, service))){
+ switch_clean_re(re);
+ if ((proceed = switch_perform_regex(uri, route->regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
+ if (strchr(route->regex, '(')) {
+ switch_perform_substitution(re, proceed, route->replace, uri, rbuf, sizeof(rbuf), ovector);
+ uri = rbuf;
+ } else {
+ uri = route->replace;
+ }
+ }
+ }
+
+ add_result(q, order, preference, service, uri);
+ }
+
+ switch_clean_re(re);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+
+ xperr:
+ //printf("<parse error>\n");
+ return;
+}
+
+static void dnscb(struct dns_ctx *ctx, void *result, void *data) {
+ int r = dns_status(ctx);
+ enum_query_t *q = data;
+ struct dns_parse p;
+ struct dns_rr rr;
+ unsigned nrr;
+ unsigned char dn[DNS_MAXDN];
+ const unsigned char *pkt, *cur, *end, *qdn;
+ if (!result) {
+ dnserror(q, r);
+ return;
+ }
+ pkt = result; end = pkt + r; cur = dns_payload(pkt);
+ dns_getdn(pkt, &cur, end, dn, sizeof(dn));
+ dns_initparse(&p, NULL, pkt, cur, end);
+ p.dnsp_qcls = p.dnsp_qtyp = 0;
+ qdn = dn;
+ nrr = 0;
+ while((r = dns_nextrr(&p, &rr)) > 0) {
+ if (!dns_dnequal(qdn, rr.dnsrr_dn)) continue;
+ if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) &&
+ (q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ))
+ ++nrr;
+ else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) {
+ if (dns_getdn(pkt, &rr.dnsrr_dptr, end,
+ p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 ||
+ rr.dnsrr_dptr != rr.dnsrr_dend) {
+ r = DNS_E_PROTOCOL;
+ break;
+ }
+ else {
+ qdn = p.dnsp_dnbuf;
+ }
+ }
+ }
+ if (!r && !nrr)
+ r = DNS_E_NODATA;
+ if (r < 0) {
+ dnserror(q, r);
+ free(result);
+ return;
+ }
+
+ dns_rewind(&p, NULL);
+ p.dnsp_qtyp = q->qtyp;
+ p.dnsp_qcls = qcls;
+ while(dns_nextrr(&p, &rr)) {
+ parse_rr(&p, q, &rr);
+ }
+
+ free(result);
+}
+
+
+static switch_status_t enum_lookup(char *root, char *in, enum_record_t **results)
+{
+ switch_status_t sstatus = SWITCH_STATUS_SUCCESS;
+ char *name = NULL;
+ enum_query_t query = {0};
+ enum dns_type l_qtyp = DNS_T_NAPTR;
+ int i = 0, fd = -1, abs = 0;
+ fd_set fds;
+ struct timeval tv = {0};
+ time_t now = 0;
+ struct dns_ctx *nctx = NULL;
+ char *num, *mnum = NULL;
+
+ if (*in != '+') {
+ mnum = switch_mprintf("+%s", in);
+ num = mnum;
+ } else {
+ num = in;
+ }
+
+ if (!(name = reverse_number(num, root))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parse Error!\n");
+ sstatus = SWITCH_STATUS_FALSE;
+ goto done;
+ }
+
+ if (!(nctx = dns_new(NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Memory Error!\n");
+ sstatus = SWITCH_STATUS_MEMERR;
+ goto done;
+ }
+
+ fd = dns_open(nctx);
+
+ if (fd < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FD Error!\n");
+ sstatus = SWITCH_STATUS_FALSE;
+ goto done;
+ }
+
+ dns_ptodn(name, strlen(name), query.dn, sizeof(query.dn), &abs);
+ query.name = name;
+ query.number = num;
+ query.qtyp = l_qtyp;
+
+ if (abs) {
+ abs = DNS_NOSRCH;
+ }
+
+ if (!dns_submit_dn(nctx, query.dn, qcls, l_qtyp, abs, 0, dnscb, &query)) {
+ dnserror(&query, dns_status(nctx));
+ }
+
+ FD_ZERO(&fds);
+ now = 0;
+
+ while((i = dns_timeouts(nctx, -1, now)) > 0) {
+ FD_SET(fd, &fds);
+ tv.tv_sec = i;
+ tv.tv_usec = 0;
+ i = select(fd+1, &fds, 0, 0, &tv);
+ now = time(NULL);
+ if (i > 0) dns_ioevent(nctx, now);
+ }
+
+ if (!query.results) {
+ sstatus = SWITCH_STATUS_FALSE;
+ }
+
+ *results = query.results;
+ query.results = NULL;
+
+ done:
+
+ if (fd > -1) {
+ close(fd);
+ fd = -1;
+ }
+
+ if (nctx) {
+ dns_free(nctx);
+ }
+
+ switch_safe_free(name);
+ switch_safe_free(mnum);
+
+ return sstatus;
+}
+
+
+static switch_caller_extension_t *enum_dialplan_hunt(switch_core_session_t *session)
+{
+ switch_caller_extension_t *extension = NULL;
+ switch_caller_profile_t *caller_profile;
+ enum_record_t *results, *rp;
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ enum_route_t *rtp;
+
+ assert(channel != NULL);
+
+ caller_profile = switch_channel_get_caller_profile(channel);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "ENUM Lookup on %s\n", caller_profile->destination_number);
+
+ if (enum_lookup(globals.root, caller_profile->destination_number, &results) == SWITCH_STATUS_SUCCESS) {
+ if ((extension = switch_caller_extension_new(session, caller_profile->destination_number, caller_profile->destination_number)) == 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "memory error!\n");
+ free_results(&results);
+ return NULL;
+ }
+ switch_channel_set_variable(channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE, "true");
+
+ for(rtp = globals.route_order; rtp; rtp = rtp->next) {
+ for(rp = results; rp; rp = rp->next) {
+ if (!strcmp(rtp->service, rp->service)) {
+ switch_caller_extension_add_application(session, extension, "bridge", rp->route);
+ }
+ }
+ }
+
+ free_results(&results);
+ }
+
+ if (extension) {
+ switch_channel_set_state(channel, CS_EXECUTE);
+ } else {
+ switch_channel_hangup(channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION);
+ }
+
+
+ return extension;
+
+}
+
+static void enum_app_function(switch_core_session_t *session, char *data)
+{
+ int argc = 0;
+ char *argv[4] = {0};
+ char *mydata = NULL;
+ char *dest = NULL, *root = NULL;
+ enum_record_t *results, *rp;
+ enum_route_t *rtp;
+ char rbuf[1024] = "";
+ char vbuf[1024] = "";
+ char *rbp = rbuf;
+ switch_size_t l = 0, rbl = sizeof(rbuf);
+ uint32_t cnt = 0;
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ assert(channel != NULL);
+
+ if (!(mydata = switch_core_session_strdup(session, data))) {
+ return;
+ }
+
+ if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
+ dest = argv[0];
+ root = argv[1] ? argv[1] : globals.root;
+ if (enum_lookup(root, data, &results) == SWITCH_STATUS_SUCCESS) {
+ for(rtp = globals.route_order; rtp; rtp = rtp->next) {
+ for(rp = results; rp; rp = rp->next) {
+ if (!strcmp(rtp->service, rp->service)) {
+ snprintf(vbuf, sizeof(vbuf), "enum_route_%d", ++cnt);
+ switch_channel_set_variable(channel, vbuf, rp->route);
+
+ snprintf(rbp, rbl, "%s|", rp->route);
+ l = strlen(rp->route) + 1;
+ rbp += l;
+ rbl -= l;
+ }
+ }
+ }
+ *(rbuf+strlen(rbuf)-1) = '\0';
+ switch_channel_set_variable(channel, "enum_auto_route", rbuf);
+ free_results(&results);
+ }
+ }
+
+}
+
+static switch_status_t enum_function(char *data, switch_core_session_t *session, switch_stream_handle_t *stream)
+{
+
+ int argc = 0;
+ char *argv[4] = {0};
+ enum_record_t *results, *rp;
+ char *mydata = NULL;
+ char *dest = NULL, *root = NULL;
+ enum_route_t *rtp;
+
+ if (session) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This function cannot be called from the dialplan.\n");
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!(mydata = strdup(data))) {
+ stream->write_function(stream, "Error!\n");
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
+ dest = argv[0];
+ root = argv[1] ? argv[1] : globals.root;
+
+ if (!enum_lookup(root, data, &results) == SWITCH_STATUS_SUCCESS) {
+ stream->write_function(stream, "No Match!\n");
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ stream->write_function(stream,
+ "\nOffered Routes:\n"
+ "Order\tPref\tService \tRoute\n"
+ "==============================================================================\n");
+
+ for(rp = results; rp; rp = rp->next) {
+ stream->write_function(stream, "%d\t%d\t%-10s\t%s\n", rp->order, rp->preference, rp->service, rp->route);
+ }
+
+
+ stream->write_function(stream,
+ "\nSupported Routes:\n"
+ "Order\tPref\tService \tRoute\n"
+ "==============================================================================\n");
+
+ for(rtp = globals.route_order; rtp; rtp = rtp->next) {
+ for(rp = results; rp; rp = rp->next) {
+ if (!strcmp(rtp->service, rp->service)) {
+ stream->write_function(stream, "%d\t%d\t%-10s\t%s\n", rp->order, rp->preference, rp->service, rp->route);
+ }
+ }
+ }
+
+ free_results(&results);
+ } else {
+ stream->write_function(stream, "Invalid Input!\n");
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+static const switch_dialplan_interface_t enum_dialplan_interface = {
+ /*.interface_name = */ "enum",
+ /*.hunt_function = */ enum_dialplan_hunt
+ /*.next = NULL */
+};
+
+static const switch_application_interface_t enum_application_interface = {
+ /*.interface_name */ "enum",
+ /*.application_function */ enum_app_function,
+ /* long_desc */ "Perform an ENUM lookup",
+ /* short_desc */ "Perform an ENUM lookup",
+ /* syntax */ "<number> [<root>]",
+ /*.next */ NULL
+};
+
+static switch_api_interface_t enum_api_interface = {
+ /*.interface_name */ "enum",
+ /*.desc */ "ENUM",
+ /*.function */ enum_function,
+ /*.syntax */ "",
+ /*.next */ NULL
+};
+
+static switch_loadable_module_interface_t enum_module_interface = {
+ /*.module_name */ modname,
+ /*.endpoint_interface */ NULL,
+ /*.timer_interface */ NULL,
+ /*.dialplan_interface */ &enum_dialplan_interface,
+ /*.codec_interface */ NULL,
+ /*.application_interface */ &enum_application_interface,
+ /*.api_interface */ &enum_api_interface,
+ /*.file_interface */ NULL,
+ /*.speech_interface */ NULL,
+ /*.directory_interface */ NULL
+};
+
+SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
+{
+
+ if (dns_init(0) < 0) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ load_config();
+
+ /* connect my internal structure to the blank pointer passed to me */
+ *module_interface = &enum_module_interface;
+
+ /* indicate that the module should continue to be loaded */
+ return SWITCH_STATUS_SUCCESS;
+}
+
More information about the Freeswitch-svn
mailing list