<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][16915] </title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=16915">16915</a></dd>
<dt>Author</dt> <dd>rupa</dd>
<dt>Date</dt> <dd>2010-03-05 10:51:03 -0600 (Fri, 05 Mar 2010)</dd>
</dl>

<h3>Log Message</h3>
<pre>mod_limit -&gt; switch_limit*,mod_hash,mod_db
branch: rupa_limit</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#freeswitchbranchesrupa_limitMakefileam">freeswitch/branches/rupa_limit/Makefile.am</a></li>
<li><a href="#freeswitchbranchesrupa_limitbuildmodulesconfin">freeswitch/branches/rupa_limit/build/modules.conf.in</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcincludeswitchh">freeswitch/branches/rupa_limit/src/include/switch.h</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcincludeswitch_loadable_moduleh">freeswitch/branches/rupa_limit/src/include/switch_loadable_module.h</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcincludeswitch_module_interfacesh">freeswitch/branches/rupa_limit/src/include/switch_module_interfaces.h</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcincludeswitch_typesh">freeswitch/branches/rupa_limit/src/include/switch_types.h</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_commandsmod_commandsc">freeswitch/branches/rupa_limit/src/mod/applications/mod_commands/mod_commands.c</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_dptoolsmod_dptoolsc">freeswitch/branches/rupa_limit/src/mod/applications/mod_dptools/mod_dptools.c</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcswitch_corec">freeswitch/branches/rupa_limit/src/switch_core.c</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcswitch_loadable_modulec">freeswitch/branches/rupa_limit/src/switch_loadable_module.c</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>freeswitch/branches/rupa_limit/src/mod/applications/mod_db/</li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbMakefile">freeswitch/branches/rupa_limit/src/mod/applications/mod_db/Makefile</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbmod_db2008vcproj">freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.2008.vcproj</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbmod_dbc">freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.c</a></li>
<li>freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/</li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashMakefile">freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/Makefile</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashmod_hash2008vcproj">freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.2008.vcproj</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashmod_hashc">freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.c</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li>freeswitch/branches/rupa_limit/src/mod/applications/mod_limit/</li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchbranchesrupa_limitMakefileam"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/Makefile.am (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/Makefile.am        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/Makefile.am        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -171,6 +171,7 @@
</span><span class="cx">         libs/libteletone/src/libteletone_detect.h \
</span><span class="cx">         libs/libteletone/src/libteletone_generate.h \
</span><span class="cx">         libs/libteletone/src/libteletone.h \
</span><ins>+        src/include/switch_limit.h \
</ins><span class="cx">         src/include/switch_odbc.h
</span><span class="cx"> 
</span><span class="cx"> nodist_libfreeswitch_la_SOURCES = \
</span><span class="lines">@@ -225,6 +226,7 @@
</span><span class="cx">         src/switch_config.c \
</span><span class="cx">         src/switch_time.c \
</span><span class="cx">         src/switch_odbc.c \
</span><ins>+        src/switch_limit.c \
</ins><span class="cx">         src/g711.c \
</span><span class="cx">         src/switch_pcm.c \
</span><span class="cx">         libs/stfu/stfu.c \
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitbuildmodulesconfin"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/build/modules.conf.in (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/build/modules.conf.in        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/build/modules.conf.in        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -9,10 +9,11 @@
</span><span class="cx"> applications/mod_fifo
</span><span class="cx"> #applications/mod_fax
</span><span class="cx"> #applications/mod_curl
</span><ins>+applications/mod_db
+applications/mod_hash
</ins><span class="cx"> applications/mod_voicemail
</span><span class="cx"> #applications/mod_directory
</span><span class="cx"> #applications/mod_lcr
</span><del>-applications/mod_limit
</del><span class="cx"> applications/mod_expr
</span><span class="cx"> applications/mod_esf
</span><span class="cx"> #applications/mod_easyroute
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcincludeswitchh"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/include/switch.h (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/include/switch.h        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/include/switch.h        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -131,6 +131,7 @@
</span><span class="cx"> #include &quot;switch_config.h&quot;
</span><span class="cx"> #include &quot;switch_nat.h&quot;
</span><span class="cx"> #include &quot;switch_odbc.h&quot;
</span><ins>+#include &quot;switch_limit.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> #include &lt;libteletone.h&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcincludeswitch_loadable_moduleh"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/include/switch_loadable_module.h (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/include/switch_loadable_module.h        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/include/switch_loadable_module.h        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -81,6 +81,8 @@
</span><span class="cx">         switch_asr_interface_t *asr_interface;
</span><span class="cx">         /*! the table of management interfaces the module has implmented */
</span><span class="cx">         switch_management_interface_t *management_interface;
</span><ins>+        /*! the table of limit interfaces the module has implmented */
+        switch_limit_interface_t *limit_interface;
</ins><span class="cx">         switch_thread_rwlock_t *rwlock;
</span><span class="cx">         int refs;
</span><span class="cx">         switch_memory_pool_t *pool;
</span><span class="lines">@@ -205,6 +207,13 @@
</span><span class="cx"> SWITCH_DECLARE(switch_management_interface_t *) switch_loadable_module_get_management_interface(const char *relative_oid);
</span><span class="cx"> 
</span><span class="cx"> /*!
</span><ins>+  \brief Retrieve the limit interface by it's registered name
+  \param name the name of the limit interface
+  \return the desired limit interface
+ */
+SWITCH_DECLARE(switch_limit_interface_t *) switch_loadable_module_get_limit_interface(const char *name);
+
+/*!
</ins><span class="cx">   \brief Retrieve the list of loaded codecs into an array
</span><span class="cx">   \param array the array to populate
</span><span class="cx">   \param arraylen the max size in elements of the array
</span><span class="lines">@@ -315,6 +324,18 @@
</span><span class="cx">         break; \
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+#define SWITCH_ADD_LIMIT(limit_int, int_name, incrptr, releaseptr, usageptr, resetptr, statusptr) \
+        for (;;) { \
+        limit_int = (switch_limit_interface_t *)switch_loadable_module_create_interface(*module_interface, SWITCH_LIMIT_INTERFACE); \
+        limit_int-&gt;incr = incrptr; \
+        limit_int-&gt;release = releaseptr; \
+        limit_int-&gt;usage = usageptr; \
+        limit_int-&gt;reset = resetptr; \
+        limit_int-&gt;status = statusptr; \
+        limit_int-&gt;interface_name = int_name; \
+        break; \
+        }
+
</ins><span class="cx"> SWITCH_DECLARE(uint32_t) switch_core_codec_next_id(void);
</span><span class="cx"> 
</span><span class="cx"> #define SWITCH_ADD_CODEC(codec_int, int_name) \
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcincludeswitch_module_interfacesh"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/include/switch_module_interfaces.h (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/include/switch_module_interfaces.h        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/include/switch_module_interfaces.h        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -512,6 +512,28 @@
</span><span class="cx">         struct switch_management_interface *next;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+/*! \brief Abstract interface to a limit module */
+struct switch_limit_interface {
+        /*! name of the interface */
+        const char *interface_name;
+        /*! increment */
+        switch_status_t (*incr) (switch_core_session_t *session, const char *realm, const char *resource, const int max, const int interval);
+        /*! release */
+        switch_status_t (*release) (switch_core_session_t *session, const char *realm, const char *resource);
+        /*! usage for resource */
+        int (*usage) (const char *realm, const char *resource);
+        /*! reset counters */
+        switch_status_t (*reset) (void);
+        /*! freform status */
+        char * (*status) (void);
+        /* internal */
+        switch_thread_rwlock_t *rwlock;
+        int refs;
+        switch_mutex_t *reflock;
+        switch_loadable_module_interface_t *parent;
+        struct switch_limit_interface *next;
+};
+
</ins><span class="cx"> /*! \brief Abstract interface to a directory module */
</span><span class="cx"> struct switch_directory_interface {
</span><span class="cx">         /*! the name of the interface */
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcincludeswitch_typesh"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/include/switch_types.h (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/include/switch_types.h        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/include/switch_types.h        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -264,7 +264,8 @@
</span><span class="cx">         SWITCH_CHAT_INTERFACE,
</span><span class="cx">         SWITCH_SAY_INTERFACE,
</span><span class="cx">         SWITCH_ASR_INTERFACE,
</span><del>-        SWITCH_MANAGEMENT_INTERFACE
</del><ins>+        SWITCH_MANAGEMENT_INTERFACE,
+        SWITCH_LIMIT_INTERFACE
</ins><span class="cx"> } switch_module_interface_name_t;
</span><span class="cx"> 
</span><span class="cx"> typedef enum {
</span><span class="lines">@@ -1503,6 +1504,7 @@
</span><span class="cx"> typedef struct switch_management_interface switch_management_interface_t;
</span><span class="cx"> typedef struct switch_core_port_allocator switch_core_port_allocator_t;
</span><span class="cx"> typedef struct switch_media_bug switch_media_bug_t;
</span><ins>+typedef struct switch_limit_interface switch_limit_interface_t;
</ins><span class="cx"> 
</span><span class="cx"> struct switch_console_callback_match_node {
</span><span class="cx">         char *val;
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_commandsmod_commandsc"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/mod/applications/mod_commands/mod_commands.c (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_commands/mod_commands.c        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_commands/mod_commands.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -3201,7 +3201,7 @@
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#define SHOW_SYNTAX &quot;codec|endpoint|application|api|dialplan|file|timer|calls [count]|channels [count|like &lt;match string&gt;]|distinct_channels|aliases|complete|chat|management|modules|nat_map|say|interfaces|interface_types|tasks&quot;
</del><ins>+#define SHOW_SYNTAX &quot;codec|endpoint|application|api|dialplan|file|timer|calls [count]|channels [count|like &lt;match string&gt;]|distinct_channels|aliases|complete|chat|management|modules|nat_map|say|interfaces|interface_types|tasks|limits&quot;
</ins><span class="cx"> SWITCH_STANDARD_API(show_function)
</span><span class="cx"> {
</span><span class="cx">         char sql[1024];
</span><span class="lines">@@ -3259,6 +3259,7 @@
</span><span class="cx">                            !strncasecmp(command, &quot;file&quot;, 4) ||
</span><span class="cx">                            !strncasecmp(command, &quot;timer&quot;, 5) ||
</span><span class="cx">                            !strncasecmp(command, &quot;chat&quot;, 4) ||
</span><ins>+                           !strncasecmp(command, &quot;limit&quot;, 5) ||
</ins><span class="cx">                            !strncasecmp(command, &quot;say&quot;, 3) || !strncasecmp(command, &quot;management&quot;, 10) || !strncasecmp(command, &quot;endpoint&quot;, 8)) {
</span><span class="cx">                 if (end_of(command) == 's') {
</span><span class="cx">                         end_of(command) = '\0';
</span><span class="lines">@@ -4048,6 +4049,95 @@
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* LIMIT Stuff */
+#define LIMIT_USAGE_USAGE &quot;&lt;backend&gt; &lt;realm&gt; &lt;id&gt;&quot;
+SWITCH_STANDARD_API(limit_usage_function)
+{
+        int argc = 0;
+        char *argv[5] = { 0 };
+        char *mydata = NULL;
+        uint32_t count = 0;
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc &lt; 3) {
+                stream-&gt;write_function(stream, &quot;USAGE: limit_usage %s\n&quot;, LIMIT_USAGE_USAGE);
+                goto end;
+        }
+        
+        count = switch_limit_usage(argv[0], argv[1], argv[2]);
+
+        stream-&gt;write_function(stream, &quot;%d&quot;, count);
+
+end:
+        switch_safe_free(mydata);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+#define LIMIT_STATUS_USAGE &quot;&lt;backend&gt;&quot;
+SWITCH_STANDARD_API(limit_status_function)
+{
+        int argc = 0;
+        char *argv[2] = { 0 };
+        char *mydata = NULL;
+        char *ret = NULL;
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc &lt; 1) {
+                stream-&gt;write_function(stream, &quot;USAGE: limit_status %s\n&quot;, LIMIT_STATUS_USAGE);
+                goto end;
+        }
+        
+        ret = switch_limit_status(argv[0]);
+
+        stream-&gt;write_function(stream, &quot;%s&quot;, ret);
+
+end:
+        switch_safe_free(mydata);
+        switch_safe_free(ret);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+#define LIMIT_RESET_USAGE &quot;&lt;backend&gt;&quot;
+SWITCH_STANDARD_API(limit_reset_function)
+{
+        int argc = 0;
+        char *argv[2] = { 0 };
+        char *mydata = NULL;
+        switch_status_t ret = SWITCH_STATUS_SUCCESS;
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc &lt; 1) {
+                stream-&gt;write_function(stream, &quot;USAGE: limit_reset %s\n&quot;, LIMIT_RESET_USAGE);
+                goto end;
+        }
+        
+        ret = switch_limit_reset(argv[0]);
+
+        stream-&gt;write_function(stream, &quot;%s&quot;, (ret == SWITCH_STATUS_SUCCESS) ? &quot;+OK&quot; : &quot;-ERR&quot;);
+
+end:
+        switch_safe_free(mydata);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
</ins><span class="cx"> SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_commands_shutdown)
</span><span class="cx"> {
</span><span class="cx">         int x;
</span><span class="lines">@@ -4108,6 +4198,9 @@
</span><span class="cx">         SWITCH_ADD_API(commands_api_interface, &quot;hupall&quot;, &quot;hupall&quot;, hupall_api_function, &quot;&lt;cause&gt; [&lt;var&gt; &lt;value&gt;]&quot;);
</span><span class="cx">         SWITCH_ADD_API(commands_api_interface, &quot;in_group&quot;, &quot;determine if a user is in a group&quot;, in_group_function, &quot;&lt;user&gt;[@&lt;domain&gt;] &lt;group_name&gt;&quot;);
</span><span class="cx">         SWITCH_ADD_API(commands_api_interface, &quot;is_lan_addr&quot;, &quot;see if an ip is a lan addr&quot;, lan_addr_function, &quot;&lt;ip&gt;&quot;);
</span><ins>+        SWITCH_ADD_API(commands_api_interface, &quot;limit_usage&quot;, &quot;Gets the usage count of a limited resource&quot;, limit_usage_function, &quot;&lt;backend&gt; &lt;realm&gt; &lt;id&gt;&quot;);
+        SWITCH_ADD_API(commands_api_interface, &quot;limit_status&quot;, &quot;Gets the status of a limit backend&quot;, limit_status_function, &quot;&lt;backend&gt;&quot;);
+        SWITCH_ADD_API(commands_api_interface, &quot;limit_reset&quot;, &quot;Reset the counters of a limit backend&quot;, limit_reset_function, &quot;&lt;backend&gt;&quot;);
</ins><span class="cx">         SWITCH_ADD_API(commands_api_interface, &quot;load&quot;, &quot;Load Module&quot;, load_function, LOAD_SYNTAX);
</span><span class="cx">         SWITCH_ADD_API(commands_api_interface, &quot;md5&quot;, &quot;md5&quot;, md5_function, &quot;&lt;data&gt;&quot;);
</span><span class="cx">         SWITCH_ADD_API(commands_api_interface, &quot;module_exists&quot;, &quot;check if module exists&quot;, module_exists_function, &quot;&lt;module&gt;&quot;);
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbMakefile"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_db/Makefile (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_db/Makefile                                (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_db/Makefile        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+BASE=../../../..
+include $(BASE)/build/modmake.rules
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbmod_db2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.2008.vcproj (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.2008.vcproj                                (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.2008.vcproj        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,283 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;Windows-1252&quot;?&gt;
+&lt;VisualStudioProject
+        ProjectType=&quot;Visual C++&quot;
+        Version=&quot;9.00&quot;
+        Name=&quot;mod_db&quot;
+        ProjectGUID=&quot;{F6A33240-8F29-48BD-98F0-826995911799}&quot;
+        RootNamespace=&quot;mod_db&quot;
+        Keyword=&quot;Win32Proj&quot;
+        TargetFrameworkVersion=&quot;131072&quot;
+        &gt;
+        &lt;Platforms&gt;
+                &lt;Platform
+                        Name=&quot;Win32&quot;
+                /&gt;
+                &lt;Platform
+                        Name=&quot;x64&quot;
+                /&gt;
+        &lt;/Platforms&gt;
+        &lt;ToolFiles&gt;
+        &lt;/ToolFiles&gt;
+        &lt;Configurations&gt;
+                &lt;Configuration
+                        Name=&quot;Debug|Win32&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_debug.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+                &lt;Configuration
+                        Name=&quot;Debug|x64&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_debug.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                                TargetEnvironment=&quot;3&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                OutputFile=&quot;$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                                TargetMachine=&quot;17&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+                &lt;Configuration
+                        Name=&quot;Release|Win32&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_release.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+                &lt;Configuration
+                        Name=&quot;Release|x64&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_release.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                                TargetEnvironment=&quot;3&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                OutputFile=&quot;$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                                TargetMachine=&quot;17&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+        &lt;/Configurations&gt;
+        &lt;References&gt;
+        &lt;/References&gt;
+        &lt;Files&gt;
+                &lt;File
+                        RelativePath=&quot;.\mod_db.c&quot;
+                        &gt;
+                &lt;/File&gt;
+        &lt;/Files&gt;
+        &lt;Globals&gt;
+        &lt;/Globals&gt;
+&lt;/VisualStudioProject&gt;
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbmod_dbc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.c (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.c                                (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,657 @@
</span><ins>+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2010, Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the &quot;License&quot;); 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 &quot;AS IS&quot; 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 &lt;anthm@freeswitch.org&gt;
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ * Ken Rice &lt;krice at suspicious dot org
+ * Mathieu Rene &lt;mathieu.rene@gmail.com&gt;
+ * Bret McDanel &lt;trixter AT 0xdecafbad.com&gt;
+ * Rupa Schomaker &lt;rupa@rupa.com&gt;
+ *
+ * mod_db.c -- Implements simple db API, group support, and limit db backend
+ *
+ */
+
+#include &lt;switch.h&gt;
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_db_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_db_shutdown);
+SWITCH_MODULE_DEFINITION(mod_db, mod_db_load, mod_db_shutdown, NULL);
+
+static struct {
+        switch_memory_pool_t *pool;
+        char hostname[256];
+        char *dbname;
+        char *odbc_dsn;
+        char *odbc_user;
+        char *odbc_pass;
+        switch_mutex_t *mutex;
+        switch_mutex_t *db_hash_mutex;
+        switch_hash_t *db_hash;
+} globals;
+
+typedef struct {
+        uint32_t total_usage;
+        uint32_t rate_usage;
+        time_t last_check;
+} limit_hash_item_t;
+
+struct callback {
+        char *buf;
+        size_t len;
+        int matches;
+};
+
+typedef struct callback callback_t;
+
+static int sql2str_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+        callback_t *cbt = (callback_t *) pArg;
+
+        switch_copy_string(cbt-&gt;buf, argv[0], cbt-&gt;len);
+        cbt-&gt;matches++;
+        return 0;
+}
+
+static char limit_sql[] =
+        &quot;CREATE TABLE limit_data (\n&quot;
+        &quot;   hostname   VARCHAR(255),\n&quot; &quot;   realm      VARCHAR(255),\n&quot; &quot;   id         VARCHAR(255),\n&quot; &quot;   uuid       VARCHAR(255)\n&quot; &quot;);\n&quot;;
+
+static char db_sql[] =
+        &quot;CREATE TABLE db_data (\n&quot;
+        &quot;   hostname   VARCHAR(255),\n&quot; &quot;   realm      VARCHAR(255),\n&quot; &quot;   data_key   VARCHAR(255),\n&quot; &quot;   data       VARCHAR(255)\n&quot; &quot;);\n&quot;;
+
+static char group_sql[] =
+        &quot;CREATE TABLE group_data (\n&quot; &quot;   hostname   VARCHAR(255),\n&quot; &quot;   groupname  VARCHAR(255),\n&quot; &quot;   url        VARCHAR(255)\n&quot; &quot;);\n&quot;;
+
+
+switch_cache_db_handle_t *limit_get_db_handle(void)
+{
+        switch_cache_db_connection_options_t options = { {0} };
+        switch_cache_db_handle_t *dbh = NULL;
+
+        if (!zstr(globals.odbc_dsn)) {
+                options.odbc_options.dsn = globals.odbc_dsn;
+                options.odbc_options.user = globals.odbc_user;
+                options.odbc_options.pass = globals.odbc_pass;
+
+                if (switch_cache_db_get_db_handle(&amp;dbh, SCDB_TYPE_ODBC, &amp;options) != SWITCH_STATUS_SUCCESS)
+                        dbh = NULL;
+                return dbh;
+        } else {
+                options.core_db_options.db_path = globals.dbname;
+                if (switch_cache_db_get_db_handle(&amp;dbh, SCDB_TYPE_CORE_DB, &amp;options) != SWITCH_STATUS_SUCCESS)
+                        dbh = NULL;
+                return dbh;
+        }
+}
+
+
+static switch_status_t limit_execute_sql(char *sql)
+{
+        switch_cache_db_handle_t *dbh = NULL;
+        switch_status_t status = SWITCH_STATUS_FALSE;
+
+        if (!(dbh = limit_get_db_handle())) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB\n&quot;);
+                goto end;
+        }
+
+        status = switch_cache_db_execute_sql(dbh, sql, NULL);
+
+  end:
+
+        switch_cache_db_release_db_handle(&amp;dbh);
+
+        return status;
+}
+
+
+static switch_bool_t limit_execute_sql_callback(char *sql, switch_core_db_callback_func_t callback, void *pdata)
+{
+        switch_bool_t ret = SWITCH_FALSE;
+        char *errmsg = NULL;
+        switch_cache_db_handle_t *dbh = NULL;
+
+        if (!(dbh = limit_get_db_handle())) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB\n&quot;);
+                goto end;
+        }
+
+        switch_cache_db_execute_sql_callback(dbh, sql, callback, pdata, &amp;errmsg);
+
+        if (errmsg) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;SQL ERR: [%s] %s\n&quot;, sql, errmsg);
+                free(errmsg);
+        }
+
+  end:
+
+        switch_cache_db_release_db_handle(&amp;dbh);
+
+        return ret;
+}
+
+static char * limit_execute_sql2str(char *sql, char *str, size_t len)
+{
+        callback_t cbt = { 0 };
+
+        cbt.buf = str;
+        cbt.len = len;
+
+        limit_execute_sql_callback(sql, sql2str_callback, &amp;cbt);
+        
+        return cbt.buf;
+}
+
+/* \brief Enforces limit restrictions
+ * \param session current session
+ * \param realm limit realm
+ * \param id limit id
+ * \param max maximum count
+ * \return SWITCH_STATUS_SUCCESS if the access is allowed
+ */
+SWITCH_LIMIT_INCR(limit_incr_sql)
+{
+        switch_channel_t *channel = switch_core_session_get_channel(session);
+        int got = 0;
+        char *sql = NULL;
+        char gotstr[128];
+        switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+        // check max! WTF
+        
+        switch_mutex_lock(globals.mutex);
+
+        switch_channel_set_variable(channel, &quot;limit_realm&quot;, realm);
+        switch_channel_set_variable(channel, &quot;limit_id&quot;, resource);
+        switch_channel_set_variable(channel, &quot;limit_max&quot;, switch_core_session_sprintf(session, &quot;%d&quot;, max));
+
+        sql = switch_mprintf(&quot;select count(hostname) from limit_data where realm='%q' and id='%q';&quot;, realm, resource);
+        limit_execute_sql2str(sql, gotstr, 128);
+        switch_safe_free(sql);
+        got = atoi(gotstr);
+
+        if (max &lt; 0) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, &quot;Usage for %s_%s is now %d\n&quot;, realm, resource, got + 1);
+        } else {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, &quot;Usage for %s_%s is now %d/%d\n&quot;, realm, resource, got + 1, max);
+        }
+
+        if (max &gt;= 0 &amp;&amp; got + 1 &gt; max) {
+                status = SWITCH_STATUS_GENERR;
+                goto done;
+        }
+
+        sql =
+                switch_mprintf(&quot;insert into limit_data (hostname, realm, id, uuid) values('%q','%q','%q','%q');&quot;, globals.hostname, realm, resource,
+                                           switch_core_session_get_uuid(session));
+        limit_execute_sql(sql);
+        switch_safe_free(sql);
+
+        {
+                const char *susage = switch_core_session_sprintf(session, &quot;%d&quot;, ++got);
+
+                switch_channel_set_variable(channel, &quot;limit_usage&quot;, susage);
+                switch_channel_set_variable(channel, switch_core_session_sprintf(session, &quot;limit_usage_%s_%s&quot;, realm, resource), susage);
+        }
+        switch_limit_fire_event(&quot;sql&quot;, realm, resource, got, 0, max, 0);
+
+  done:
+        switch_mutex_unlock(globals.mutex);
+        return status;
+}
+
+SWITCH_LIMIT_RELEASE(limit_release_sql)
+{
+        char *sql = NULL;
+
+        if (realm == NULL &amp;&amp; resource == NULL) {
+                sql = switch_mprintf(&quot;delete from limit_data where uuid='%q'&quot;, switch_core_session_get_uuid(session));
+        } else {
+                sql = switch_mprintf(&quot;delete from limit_data where uuid='%q' and realm='%q' and id = '%q'&quot;, switch_core_session_get_uuid(session), realm, resource);
+        }
+        limit_execute_sql(sql);
+        switch_safe_free(sql);
+        
+        return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_LIMIT_USAGE(limit_usage_sql)
+{
+        char usagestr[128] = &quot;&quot;;
+        int usage = 0;
+        char *sql = NULL;
+        
+        sql = switch_mprintf(&quot;select count(hostname) from limit_data where realm='%q' and id='%q'&quot;, realm, resource);
+        limit_execute_sql2str(sql, usagestr, sizeof(usagestr));
+        switch_safe_free(sql);
+        usage = atoi(usagestr);
+        
+        return usage;
+}
+
+SWITCH_LIMIT_RESET(limit_reset_sql)
+{
+        char *sql = NULL;
+        sql = switch_mprintf(&quot;delete from limit_data where hostname='%q';&quot;, globals.hostname);
+        limit_execute_sql(sql);
+        switch_safe_free(sql);
+        
+        return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_LIMIT_STATUS(limit_status_sql)
+{
+        char count[128] = &quot;&quot;;
+        char *ret = NULL;
+        char *sql = NULL;
+        
+        sql = switch_mprintf(&quot;select count(hostname) from limit_data where hostname='%q'&quot;, globals.hostname);
+        limit_execute_sql2str(sql, count, sizeof(count));
+        switch_safe_free(sql);
+        ret = switch_mprintf(&quot;Tracking %s resources for hostname %s.&quot;, count, globals.hostname);
+        return ret;
+}
+
+/* INIT / Config */
+
+static switch_xml_config_string_options_t limit_config_dsn = { NULL, 0, &quot;[^:]+:[^:]+:.+&quot; };
+
+static switch_xml_config_item_t config_settings[] = {
+        SWITCH_CONFIG_ITEM(&quot;odbc-dsn&quot;, SWITCH_CONFIG_STRING, 0, &amp;globals.odbc_dsn, NULL, &amp;limit_config_dsn,
+                                           &quot;dsn:username:password&quot;, &quot;If set, the ODBC DSN used by the limit and db applications&quot;),
+        SWITCH_CONFIG_ITEM_END()
+};
+
+static switch_status_t do_config()
+{
+        switch_cache_db_handle_t *dbh = NULL;
+        switch_status_t status = SWITCH_STATUS_SUCCESS;
+        char *sql = NULL;
+
+        limit_config_dsn.pool = globals.pool;
+
+        if (switch_xml_config_parse_module_settings(&quot;db.conf&quot;, SWITCH_FALSE, config_settings) != SWITCH_STATUS_SUCCESS) {
+                return SWITCH_STATUS_TERM;
+        }
+
+        if (globals.odbc_dsn) {
+                if ((globals.odbc_user = strchr(globals.odbc_dsn, ':'))) {
+                        *globals.odbc_user++ = '\0';
+                        if ((globals.odbc_pass = strchr(globals.odbc_user, ':'))) {
+                                *globals.odbc_pass++ = '\0';
+                        }
+                }
+
+                if (!(dbh = limit_get_db_handle())) {
+                        globals.odbc_dsn = globals.odbc_user = globals.odbc_pass;
+                }
+        }
+
+
+        if (zstr(globals.odbc_dsn)) {
+                globals.dbname = &quot;call_limit&quot;;
+                dbh = limit_get_db_handle();
+        }
+
+
+        if (dbh) {
+                int x = 0;
+                char *indexes[] = {
+                        &quot;create index ld_hostname on limit_data (hostname)&quot;,
+                        &quot;create index ld_uuid on limit_data (uuid)&quot;,
+                        &quot;create index ld_realm on limit_data (realm)&quot;,
+                        &quot;create index ld_id on limit_data (id)&quot;,
+                        &quot;create index dd_realm on db_data (realm)&quot;,
+                        &quot;create index dd_data_key on db_data (data_key)&quot;,
+                        &quot;create index gd_groupname on group_data (groupname)&quot;,
+                        &quot;create index gd_url on group_data (url)&quot;,
+                        NULL
+                };
+
+
+
+                switch_cache_db_test_reactive(dbh, &quot;select * from limit_data&quot;, NULL, limit_sql);
+                switch_cache_db_test_reactive(dbh, &quot;select * from db_data&quot;, NULL, db_sql);
+                switch_cache_db_test_reactive(dbh, &quot;select * from group_data&quot;, NULL, group_sql);
+
+                for (x = 0; indexes[x]; x++) {
+                        switch_cache_db_execute_sql(dbh, indexes[x], NULL);
+                }
+
+                switch_cache_db_release_db_handle(&amp;dbh);
+
+                sql = switch_mprintf(&quot;delete from limit_data where hostname='%q';&quot;, globals.hostname);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+        }
+
+        return status;
+}
+
+/* APP/API STUFF */
+
+/* CORE DB STUFF */
+
+SWITCH_STANDARD_API(db_api_function)
+{
+        int argc = 0;
+        char *argv[4] = { 0 };
+        char *mydata = NULL;
+        char *sql;
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc &lt; 1 || !argv[0]) {
+                goto error;
+        }
+
+        if (!strcasecmp(argv[0], &quot;insert&quot;)) {
+                if (argc &lt; 4) {
+                        goto error;
+                }
+                sql = switch_mprintf(&quot;delete from db_data where realm='%q' and data_key='%q'&quot;, argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                sql =
+                        switch_mprintf(&quot;insert into db_data (hostname, realm, data_key, data) values('%q','%q','%q','%q');&quot;, globals.hostname, argv[1], argv[2],
+                                                   argv[3]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                stream-&gt;write_function(stream, &quot;+OK&quot;);
+                goto done;
+        } else if (!strcasecmp(argv[0], &quot;delete&quot;)) {
+                if (argc &lt; 2) {
+                        goto error;
+                }
+                sql = switch_mprintf(&quot;delete from db_data where realm='%q' and data_key='%q'&quot;, argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                stream-&gt;write_function(stream, &quot;+OK&quot;);
+                goto done;
+        } else if (!strcasecmp(argv[0], &quot;select&quot;)) {
+                char buf[256] = &quot;&quot;;
+                if (argc &lt; 3) {
+                        goto error;
+                }
+                sql = switch_mprintf(&quot;select data from db_data where realm='%q' and data_key='%q'&quot;, argv[1], argv[2]);
+                limit_execute_sql2str(sql, buf, sizeof(buf));
+                switch_safe_free(sql);
+                stream-&gt;write_function(stream, &quot;%s&quot;, buf);
+                goto done;
+        }
+
+  error:
+        stream-&gt;write_function(stream, &quot;!err!&quot;);
+
+  done:
+
+        switch_safe_free(mydata);
+        return SWITCH_STATUS_SUCCESS;
+}
+
+#define DB_USAGE &quot;[insert|delete]/&lt;realm&gt;/&lt;key&gt;/&lt;val&gt;&quot;
+#define DB_DESC &quot;save data&quot;
+
+SWITCH_STANDARD_APP(db_function)
+{
+        int argc = 0;
+        char *argv[4] = { 0 };
+        char *mydata = NULL;
+        char *sql = NULL;
+
+        if (!zstr(data)) {
+                mydata = switch_core_session_strdup(session, data);
+                argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc &lt; 3 || !argv[0]) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, &quot;USAGE: db %s\n&quot;, DB_USAGE);
+                return;
+        }
+
+        if (!strcasecmp(argv[0], &quot;insert&quot;)) {
+                if (argc &lt; 4) {
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, &quot;USAGE: db %s\n&quot;, DB_USAGE);
+                        return;
+                }
+                sql = switch_mprintf(&quot;delete from db_data where realm='%q' and data_key='%q'&quot;, argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+
+                sql =
+                        switch_mprintf(&quot;insert into db_data (hostname, realm, data_key, data) values('%q','%q','%q','%q');&quot;, globals.hostname, argv[1], argv[2],
+                                                   argv[3]);
+        } else if (!strcasecmp(argv[0], &quot;delete&quot;)) {
+                sql = switch_mprintf(&quot;delete from db_data where realm='%q' and data_key='%q'&quot;, argv[1], argv[2]);
+        } else {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, &quot;USAGE: db %s\n&quot;, DB_USAGE);
+                return;
+        }
+
+        if (sql) {
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+        }
+}
+
+/* GROUP STUFF */
+
+static int group_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+        callback_t *cbt = (callback_t *) pArg;
+        switch_snprintf(cbt-&gt;buf + strlen(cbt-&gt;buf), cbt-&gt;len - strlen(cbt-&gt;buf), &quot;%s%c&quot;, argv[0], *argv[1]);
+        cbt-&gt;matches++;
+        return 0;
+}
+
+SWITCH_STANDARD_API(group_api_function)
+{
+        int argc = 0;
+        char *argv[4] = { 0 };
+        char *mydata = NULL;
+        char *sql;
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                argc = switch_separate_string(mydata, ':', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc &lt; 2 || !argv[0]) {
+                goto error;
+        }
+
+        if (!strcasecmp(argv[0], &quot;insert&quot;)) {
+                if (argc &lt; 3) {
+                        goto error;
+                }
+                sql = switch_mprintf(&quot;delete from group_data where groupname='%q' and url='%q';&quot;, argv[1], argv[2]);
+                switch_assert(sql);
+
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                sql = switch_mprintf(&quot;insert into group_data (hostname, groupname, url) values('%q','%q','%q');&quot;, globals.hostname, argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                stream-&gt;write_function(stream, &quot;+OK&quot;);
+                goto done;
+        } else if (!strcasecmp(argv[0], &quot;delete&quot;)) {
+                if (argc &lt; 3) {
+                        goto error;
+                }
+                if (!strcmp(argv[2], &quot;*&quot;)) {
+                        sql = switch_mprintf(&quot;delete from group_data where groupname='%q';&quot;, argv[1]);
+                } else {
+                        sql = switch_mprintf(&quot;delete from group_data where groupname='%q' and url='%q';&quot;, argv[1], argv[2]);
+                }
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                stream-&gt;write_function(stream, &quot;+OK&quot;);
+                goto done;
+        } else if (!strcasecmp(argv[0], &quot;call&quot;)) {
+                char buf[4096] = &quot;&quot;;
+                char *how = &quot;,&quot;;
+                callback_t cbt = { 0 };
+                cbt.buf = buf;
+                cbt.len = sizeof(buf);
+
+                if (argc &gt; 2) {
+                        if (!strcasecmp(argv[2], &quot;order&quot;)) {
+                                how = &quot;|&quot;;
+                        }
+                }
+
+                sql = switch_mprintf(&quot;select url,'%q' from group_data where groupname='%q'&quot;, how, argv[1]);
+                switch_assert(sql);
+
+                limit_execute_sql_callback(sql, group_callback, &amp;cbt);
+                switch_safe_free(sql);
+
+                *(buf + (strlen(buf) - 1)) = '\0';
+                stream-&gt;write_function(stream, &quot;%s&quot;, buf);
+
+                goto done;
+        }
+
+  error:
+        stream-&gt;write_function(stream, &quot;!err!&quot;);
+
+  done:
+
+        switch_safe_free(mydata);
+        return SWITCH_STATUS_SUCCESS;
+}
+
+#define GROUP_USAGE &quot;[insert|delete]:&lt;group name&gt;:&lt;val&gt;&quot;
+#define GROUP_DESC &quot;save data&quot;
+
+SWITCH_STANDARD_APP(group_function)
+{
+        int argc = 0;
+        char *argv[3] = { 0 };
+        char *mydata = NULL;
+        char *sql;
+
+        if (!zstr(data)) {
+                mydata = switch_core_session_strdup(session, data);
+                argc = switch_separate_string(mydata, ':', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc &lt; 3 || !argv[0]) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, &quot;USAGE: group %s\n&quot;, DB_USAGE);
+                return;
+        }
+
+        if (!strcasecmp(argv[0], &quot;insert&quot;)) {
+                sql = switch_mprintf(&quot;insert into group_data (hostname, groupname, url) values('%q','%q','%q');&quot;, globals.hostname, argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+        } else if (!strcasecmp(argv[0], &quot;delete&quot;)) {
+                sql = switch_mprintf(&quot;delete from group_data where groupname='%q' and url='%q';&quot;, argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+        }
+}
+
+/* INIT/DEINIT STUFF */
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_db_load)
+{
+        switch_status_t status;
+        switch_application_interface_t *app_interface;
+        switch_api_interface_t *commands_api_interface;
+        switch_limit_interface_t *limit_interface;
+
+        memset(&amp;globals, 0, sizeof(&amp;globals));
+        gethostname(globals.hostname, sizeof(globals.hostname));
+        globals.pool = pool;
+
+
+        if ((status = do_config() != SWITCH_STATUS_SUCCESS)) {
+                return status;
+        }
+
+        switch_mutex_init(&amp;globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
+        switch_mutex_init(&amp;globals.db_hash_mutex, SWITCH_MUTEX_NESTED, globals.pool);
+        switch_core_hash_init(&amp;globals.db_hash, pool);
+
+        /* connect my internal structure to the blank pointer passed to me */
+        *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+        /* register limit interfaces */
+        SWITCH_ADD_LIMIT(limit_interface, &quot;sql&quot;, limit_incr_sql, limit_release_sql, limit_usage_sql, limit_reset_sql, limit_status_sql);
+
+        SWITCH_ADD_APP(app_interface, &quot;db&quot;, &quot;Insert to the db&quot;, DB_DESC, db_function, DB_USAGE, SAF_SUPPORT_NOMEDIA);
+        SWITCH_ADD_APP(app_interface, &quot;group&quot;, &quot;Manage a group&quot;, GROUP_DESC, group_function, GROUP_USAGE, SAF_SUPPORT_NOMEDIA);
+        SWITCH_ADD_API(commands_api_interface, &quot;db&quot;, &quot;db get/set&quot;, db_api_function, &quot;[insert|delete|select]/&lt;realm&gt;/&lt;key&gt;/&lt;value&gt;&quot;);
+        switch_console_set_complete(&quot;add db insert&quot;);
+        switch_console_set_complete(&quot;add db delete&quot;);
+        switch_console_set_complete(&quot;add db select&quot;);
+        SWITCH_ADD_API(commands_api_interface, &quot;group&quot;, &quot;group [insert|delete|call]&quot;, group_api_function, &quot;[insert|delete|call]:&lt;group name&gt;:&lt;url&gt;&quot;);
+        switch_console_set_complete(&quot;add group insert&quot;);
+        switch_console_set_complete(&quot;add group delete&quot;);
+        switch_console_set_complete(&quot;add group call&quot;);
+
+        /* indicate that the module should continue to be loaded */
+        return SWITCH_STATUS_SUCCESS;
+        
+}
+
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_db_shutdown)
+{
+
+        switch_xml_config_cleanup(config_settings);
+
+        switch_mutex_destroy(globals.mutex);
+        switch_mutex_destroy(globals.db_hash_mutex);
+
+        switch_core_hash_destroy(&amp;globals.db_hash);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_dptoolsmod_dptoolsc"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/mod/applications/mod_dptools/mod_dptools.c (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_dptools/mod_dptools.c        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_dptools/mod_dptools.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -2977,6 +2977,140 @@
</span><span class="cx">         }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* LIMIT STUFF */
+#define LIMIT_USAGE &quot;&lt;backend&gt; &lt;realm&gt; &lt;id&gt; [&lt;max&gt;[/interval]] [number [dialplan [context]]]&quot;
+#define LIMIT_DESC &quot;limit access to a resource and transfer to an extension if the limit is exceeded&quot;
+SWITCH_STANDARD_APP(limit_function)
+{
+        int argc = 0;
+        char *argv[7] = { 0 };
+        char *mydata = NULL;
+        char *backend = NULL;
+        char *realm = NULL;
+        char *id = NULL;
+        char *xfer_exten = NULL;
+        int max = -1;
+        int interval = 0;
+        switch_channel_t *channel = switch_core_session_get_channel(session);
+
+        /* Parse application data  */
+        if (!zstr(data)) {
+                mydata = switch_core_session_strdup(session, data);
+                argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc &lt; 3) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, &quot;USAGE: limit %s\n&quot;, LIMIT_USAGE);
+                return;
+        }
+
+        backend = argv[0];
+        realm = argv[1];
+        id = argv[2];
+
+        /* If max is omitted or negative, only act as a counter and skip maximum checks */
+        if (argc &gt; 3) {
+                if (argv[3][0] == '-') {
+                        max = -1;
+                } else {
+                        char *szinterval = NULL;
+                        if ((szinterval = strchr(argv[2], '/'))) {
+                                *szinterval++ = '\0';
+                                interval = atoi(szinterval);
+                        }
+
+                        max = atoi(argv[3]);
+
+                        if (max &lt; 0) {
+                                max = 0;
+                        }
+                }
+        }
+
+        if (argc &gt; 4) {
+                xfer_exten = argv[4];
+        } else {
+                xfer_exten = LIMIT_DEF_XFER_EXTEN;
+        }
+
+        if (switch_limit_incr(backend, session, realm, id, max, interval) != SWITCH_STATUS_SUCCESS) {
+                /* Limit exceeded */
+                if (*xfer_exten == '!') {
+                        switch_channel_hangup(channel, switch_channel_str2cause(xfer_exten + 1));
+                } else {
+                        switch_ivr_session_transfer(session, xfer_exten, argv[5], argv[6]);
+                }
+        }
+}
+
+
+#define LIMITEXECUTE_USAGE &quot;&lt;backend&gt; &lt;realm&gt; &lt;id&gt; [&lt;max&gt;[/interval]] [application] [application arguments]&quot;
+#define LIMITEXECUTE_DESC &quot;limit access to a resource. the specified application will only be executed if the resource is available&quot;
+SWITCH_STANDARD_APP(limit_execute_function)
+{
+        int argc = 0;
+        char *argv[6] = { 0 };
+        char *mydata = NULL;
+        char *backend = NULL;
+        char *realm = NULL;
+        char *id = NULL;
+        char *app = NULL;
+        char *app_arg = NULL;
+        int max = -1;
+        int interval = 0;
+
+        /* Parse application data  */
+        if (!zstr(data)) {
+                mydata = switch_core_session_strdup(session, data);
+                argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc &lt; 6) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, &quot;USAGE: limit_execute %s\n&quot;, LIMITEXECUTE_USAGE);
+                return;
+        }
+
+        backend = argv[0];
+        realm = argv[1];
+        id = argv[2];
+
+        /* Accept '-' as unlimited (act as counter) */
+        if (argv[3][0] == '-') {
+                max = -1;
+        } else {
+                char *szinterval = NULL;
+
+                if ((szinterval = strchr(argv[3], '/'))) {
+                        *szinterval++ = '\0';
+                        interval = atoi(szinterval);
+                }
+
+                max = atoi(argv[3]);
+
+                if (max &lt; 0) {
+                        max = 0;
+                }
+        }
+
+        app = argv[4];
+        app_arg = argv[5];
+
+        if (zstr(app)) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, &quot;Missing application\n&quot;);
+                return;
+        }
+
+        if (switch_limit_incr(backend, session, realm, id, max, interval) == SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, &quot;Executing\n&quot;);
+                switch_core_session_execute_application(session, app, app_arg);
+                /* Only release the resource if we are still in CS_EXECUTE */
+                if (switch_channel_get_state(switch_core_session_get_channel(session)) == CS_EXECUTE) {
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, &quot;immediately releasing\n&quot;);
+                        switch_limit_release(backend, session, realm, id);                        
+                }
+        }
+}
+
</ins><span class="cx"> #define SPEAK_DESC &quot;Speak text to a channel via the tts interface&quot;
</span><span class="cx"> #define DISPLACE_DESC &quot;Displace audio from a file to the channels input&quot;
</span><span class="cx"> #define SESS_REC_DESC &quot;Starts a background recording of the entire session&quot;
</span><span class="lines">@@ -3144,6 +3278,8 @@
</span><span class="cx">                                    SAF_NONE);
</span><span class="cx">         SWITCH_ADD_APP(app_interface, &quot;session_loglevel&quot;, &quot;session_loglevel&quot;, &quot;session_loglevel&quot;, session_loglevel_function, SESSION_LOGLEVEL_SYNTAX,
</span><span class="cx">                                    SAF_SUPPORT_NOMEDIA);
</span><ins>+        SWITCH_ADD_APP(app_interface, &quot;limit&quot;, &quot;Limit&quot;, LIMIT_DESC, limit_function, LIMIT_USAGE, SAF_SUPPORT_NOMEDIA);
+        SWITCH_ADD_APP(app_interface, &quot;limit_execute&quot;, &quot;Limit&quot;, LIMITEXECUTE_USAGE, limit_execute_function, LIMITEXECUTE_USAGE, SAF_SUPPORT_NOMEDIA);
</ins><span class="cx"> 
</span><span class="cx">         SWITCH_ADD_DIALPLAN(dp_interface, &quot;inline&quot;, inline_dialplan_hunt);
</span><span class="cx"> 
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashMakefile"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/Makefile (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/Makefile                                (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/Makefile        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+BASE=../../../..
+include $(BASE)/build/modmake.rules
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashmod_hash2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.2008.vcproj (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.2008.vcproj                                (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.2008.vcproj        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,283 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;Windows-1252&quot;?&gt;
+&lt;VisualStudioProject
+        ProjectType=&quot;Visual C++&quot;
+        Version=&quot;9.00&quot;
+        Name=&quot;mod_hash&quot;
+        ProjectGUID=&quot;{F6A33240-8F29-48BD-98F0-826995911799}&quot;
+        RootNamespace=&quot;mod_hash&quot;
+        Keyword=&quot;Win32Proj&quot;
+        TargetFrameworkVersion=&quot;131072&quot;
+        &gt;
+        &lt;Platforms&gt;
+                &lt;Platform
+                        Name=&quot;Win32&quot;
+                /&gt;
+                &lt;Platform
+                        Name=&quot;x64&quot;
+                /&gt;
+        &lt;/Platforms&gt;
+        &lt;ToolFiles&gt;
+        &lt;/ToolFiles&gt;
+        &lt;Configurations&gt;
+                &lt;Configuration
+                        Name=&quot;Debug|Win32&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_debug.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+                &lt;Configuration
+                        Name=&quot;Debug|x64&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_debug.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                                TargetEnvironment=&quot;3&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                OutputFile=&quot;$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                                TargetMachine=&quot;17&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+                &lt;Configuration
+                        Name=&quot;Release|Win32&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_release.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+                &lt;Configuration
+                        Name=&quot;Release|x64&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_release.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                                TargetEnvironment=&quot;3&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                OutputFile=&quot;$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                                TargetMachine=&quot;17&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+        &lt;/Configurations&gt;
+        &lt;References&gt;
+        &lt;/References&gt;
+        &lt;Files&gt;
+                &lt;File
+                        RelativePath=&quot;.\mod_hash.c&quot;
+                        &gt;
+                &lt;/File&gt;
+        &lt;/Files&gt;
+        &lt;Globals&gt;
+        &lt;/Globals&gt;
+&lt;/VisualStudioProject&gt;
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashmod_hashc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.c (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.c                                (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,457 @@
</span><ins>+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2010, Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the &quot;License&quot;); 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 &quot;AS IS&quot; 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 &lt;anthm@freeswitch.org&gt;
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ * Ken Rice &lt;krice at suspicious dot org
+ * Mathieu Rene &lt;mathieu.rene@gmail.com&gt;
+ * Bret McDanel &lt;trixter AT 0xdecafbad.com&gt;
+ * Rupa Schomaker &lt;rupa@rupa.com&gt;
+ *
+ * mod_hash.c -- Hash api, hash backend for limit
+ *
+ */
+
+#include &lt;switch.h&gt;
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_hash_shutdown);
+SWITCH_MODULE_DEFINITION(mod_hash, mod_hash_load, mod_hash_shutdown, NULL);
+
+/* CORE STUFF */
+static struct {
+        switch_memory_pool_t *pool;
+        switch_mutex_t *mutex;
+        switch_mutex_t *limit_hash_mutex;
+        switch_hash_t *limit_hash;
+        switch_mutex_t *db_hash_mutex;
+        switch_hash_t *db_hash;
+} globals;
+
+typedef struct {
+        uint32_t total_usage;
+        uint32_t rate_usage;
+        time_t last_check;
+} limit_hash_item_t;
+
+struct callback {
+        char *buf;
+        size_t len;
+        int matches;
+};
+
+typedef struct callback callback_t;
+
+/* HASH STUFF */
+typedef struct {
+        switch_hash_t *hash;
+} limit_hash_private_t;
+
+/* \brief Enforces limit_hash restrictions
+ * \param session current session
+ * \param realm limit realm
+ * \param id limit id
+ * \param max maximum count
+ * \param interval interval for rate limiting
+ * \return SWITCH_TRUE if the access is allowed, SWITCH_FALSE if it isnt
+ */
+SWITCH_LIMIT_INCR(limit_incr_hash)
+{
+        switch_channel_t *channel = switch_core_session_get_channel(session);
+        char *hashkey = NULL;
+        switch_bool_t status = SWITCH_STATUS_SUCCESS;
+        limit_hash_item_t *item = NULL;
+        time_t now = switch_epoch_time_now(NULL);
+        limit_hash_private_t *pvt = NULL;
+        uint8_t increment = 1;
+
+        hashkey = switch_core_session_sprintf(session, &quot;%s_%s&quot;, realm, resource);
+
+        switch_mutex_lock(globals.limit_hash_mutex);
+        /* Check if that realm+resource has ever been checked */
+        if (!(item = (limit_hash_item_t *) switch_core_hash_find(globals.limit_hash, hashkey))) {
+                /* No, create an empty structure and add it, then continue like as if it existed */
+                item = (limit_hash_item_t *) malloc(sizeof(limit_hash_item_t));
+                switch_assert(item);
+                memset(item, 0, sizeof(limit_hash_item_t));
+                switch_core_hash_insert(globals.limit_hash, hashkey, item);
+        }
+
+        /* Did we already run on this channel before? */
+        if ((pvt = switch_channel_get_private(channel, &quot;limit_hash&quot;))) {
+                /* Yes, but check if we did that realm+resource
+                   If we didnt, allow incrementing the counter.
+                   If we did, dont touch it but do the validation anyways
+                 */
+                increment = !switch_core_hash_find(pvt-&gt;hash, hashkey);
+        } else {
+                /* This is the first limit check on this channel, create a hashtable, set our prviate data and add a state handler */
+                pvt = (limit_hash_private_t *) switch_core_session_alloc(session, sizeof(limit_hash_private_t));
+                memset(pvt, 0, sizeof(limit_hash_private_t));
+                switch_core_hash_init(&amp;pvt-&gt;hash, switch_core_session_get_pool(session));
+                switch_channel_set_private(channel, &quot;limit_hash&quot;, pvt);
+        }
+
+        if (interval &gt; 0) {
+                if (item-&gt;last_check &lt;= (now - interval)) {
+                        item-&gt;rate_usage = 1;
+                        item-&gt;last_check = now;
+                } else {
+                        /* Always increment rate when its checked as it doesnt depend on the channel */
+                        item-&gt;rate_usage++;
+
+                        if ((max &gt;= 0) &amp;&amp; (item-&gt;rate_usage &gt; (uint32_t) max)) {
+                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, &quot;Usage for %s exceeds maximum rate of %d/%ds, now at %d\n&quot;,
+                                                                  hashkey, max, interval, item-&gt;rate_usage);
+                                status = SWITCH_STATUS_GENERR;
+                                goto end;
+                        }
+                }
+        } else if ((max &gt;= 0) &amp;&amp; (item-&gt;total_usage + increment &gt; (uint32_t) max)) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, &quot;Usage for %s is already at max value (%d)\n&quot;, hashkey, item-&gt;total_usage);
+                status = SWITCH_STATUS_GENERR;
+                goto end;
+        }
+
+        if (increment) {
+                item-&gt;total_usage++;
+
+                switch_core_hash_insert(pvt-&gt;hash, hashkey, item);
+
+                if (max == -1) {
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, &quot;Usage for %s is now %d\n&quot;, hashkey, item-&gt;total_usage);
+                } else if (interval == 0) {
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, &quot;Usage for %s is now %d/%d\n&quot;, hashkey, item-&gt;total_usage, max);
+                } else {
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, &quot;Usage for %s is now %d/%d for the last %d seconds\n&quot;, hashkey,
+                                                          item-&gt;rate_usage, max, interval);
+                }
+
+                switch_limit_fire_event(&quot;hash&quot;, realm, resource, item-&gt;total_usage, item-&gt;rate_usage, max, max &gt;= 0 ? (uint32_t) max : 0);
+        }
+
+        /* Save current usage &amp; rate into channel variables so it can be used later in the dialplan, or added to CDR records */
+        {
+                const char *susage = switch_core_session_sprintf(session, &quot;%d&quot;, item-&gt;total_usage);
+                const char *srate = switch_core_session_sprintf(session, &quot;%d&quot;, item-&gt;rate_usage);
+
+                switch_channel_set_variable(channel, &quot;limit_usage&quot;, susage);
+                switch_channel_set_variable(channel, switch_core_session_sprintf(session, &quot;limit_usage_%s&quot;, hashkey), susage);
+
+                switch_channel_set_variable(channel, &quot;limit_rate&quot;, srate);
+                switch_channel_set_variable(channel, switch_core_session_sprintf(session, &quot;limit_rate_%s&quot;, hashkey), srate);
+        }
+
+  end:
+        switch_mutex_unlock(globals.limit_hash_mutex);
+        return status;
+}
+
+/* !\brief Releases usage of a limit_hash-controlled ressource  */
+SWITCH_LIMIT_RELEASE(limit_release_hash)
+{
+        switch_channel_t *channel = switch_core_session_get_channel(session);
+        limit_hash_private_t *pvt = switch_channel_get_private(channel, &quot;limit_hash&quot;);
+        limit_hash_item_t *item = NULL;
+        switch_hash_index_t *hi;
+        char *hashkey = NULL;
+
+        if (!pvt || !pvt-&gt;hash) {
+                return SWITCH_STATUS_SUCCESS;
+        }
+
+        switch_mutex_lock(globals.limit_hash_mutex);
+
+        /* clear for uuid */
+        if (realm == NULL &amp;&amp; resource == NULL) {
+                /* Loop through the channel's hashtable which contains mapping to all the limit_hash_item_t referenced by that channel */
+                while ((hi = switch_hash_first(NULL, pvt-&gt;hash))) {
+                        void *val = NULL;
+                        const void *key;
+                        switch_ssize_t keylen;
+                        limit_hash_item_t *item = NULL;
+
+                        switch_hash_this(hi, &amp;key, &amp;keylen, &amp;val);
+
+                        item = (limit_hash_item_t *) val;
+                        item-&gt;total_usage--;
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, &quot;Usage for %s is now %d\n&quot;, (const char *) key, item-&gt;total_usage);
+
+                        if (item-&gt;total_usage == 0) {
+                                /* Noone is using this item anymore */
+                                switch_core_hash_delete(globals.limit_hash, (const char *) key);
+                                free(item);
+                        }
+
+                        switch_core_hash_delete(pvt-&gt;hash, (const char *) key);
+                }
+        } else {
+                hashkey = switch_core_session_sprintf(session, &quot;%s_%s&quot;, realm, resource);
+
+                if ((item = (limit_hash_item_t *) switch_core_hash_find(pvt-&gt;hash, hashkey))) {
+                        item-&gt;total_usage--;
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, &quot;Usage for %s is now %d\n&quot;, (const char *) hashkey, item-&gt;total_usage);
+
+                        switch_core_hash_delete(pvt-&gt;hash, hashkey);
+
+                        if (item-&gt;total_usage == 0) {
+                                /* Noone is using this item anymore */
+                                switch_core_hash_delete(globals.limit_hash, (const char *) hashkey);
+                                free(item);
+                        }
+                }
+        }
+
+        switch_mutex_unlock(globals.limit_hash_mutex);
+        
+        return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_LIMIT_USAGE(limit_usage_hash)
+{
+        char *hash_key = NULL;
+        limit_hash_item_t *item = NULL;
+        int count = 0;
+
+        switch_mutex_lock(globals.limit_hash_mutex);
+
+        hash_key = switch_mprintf(&quot;%s_%s&quot;, realm, resource);
+
+        if ((item = switch_core_hash_find(globals.limit_hash, hash_key))) {
+                count = item-&gt;total_usage;
+        }
+
+         switch_safe_free(hash_key);
+        switch_mutex_unlock(globals.limit_hash_mutex);
+
+        return count;
+}
+
+SWITCH_LIMIT_RESET(limit_reset_hash)
+{
+        return SWITCH_STATUS_GENERR;
+}
+
+SWITCH_LIMIT_STATUS(limit_status_hash)
+{
+        switch_hash_index_t *hi = NULL;
+        int count = 0;
+        char *ret = NULL;
+        
+        switch_mutex_lock(globals.limit_hash_mutex);
+        
+        while ((hi = switch_hash_first(NULL, globals.limit_hash))) {
+                count++;
+        }
+        switch_mutex_unlock(globals.limit_hash_mutex);
+        
+        ret = switch_mprintf(&quot;There are %d elements being tracked.&quot;, count);
+        return ret;
+}
+
+/* APP/API STUFF */
+
+/* CORE HASH STUFF */
+
+#define HASH_USAGE &quot;[insert|delete]/&lt;realm&gt;/&lt;key&gt;/&lt;val&gt;&quot;
+#define HASH_DESC &quot;save data&quot;
+
+SWITCH_STANDARD_APP(hash_function)
+{
+        int argc = 0;
+        char *argv[4] = { 0 };
+        char *mydata = NULL;
+        char *hash_key = NULL;
+        char *value = NULL;
+
+        switch_mutex_lock(globals.db_hash_mutex);
+
+        if (!zstr(data)) {
+                mydata = strdup(data);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc &lt; 3 || !argv[0]) {
+                goto usage;
+        }
+
+        hash_key = switch_mprintf(&quot;%s_%s&quot;, argv[1], argv[2]);
+
+        if (!strcasecmp(argv[0], &quot;insert&quot;)) {
+                if (argc &lt; 4) {
+                        goto usage;
+                }
+                if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
+                        free(value);
+                        switch_core_hash_delete(globals.db_hash, hash_key);
+                }
+                value = strdup(argv[3]);
+                switch_assert(value);
+                switch_core_hash_insert(globals.db_hash, hash_key, value);
+        } else if (!strcasecmp(argv[0], &quot;delete&quot;)) {
+                if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
+                        switch_safe_free(value);
+                        switch_core_hash_delete(globals.db_hash, hash_key);
+                }
+        } else {
+                goto usage;
+        }
+
+        goto done;
+
+  usage:
+        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, &quot;USAGE: hash %s\n&quot;, HASH_USAGE);
+
+  done:
+        switch_mutex_unlock(globals.db_hash_mutex);
+        switch_safe_free(mydata);
+        switch_safe_free(hash_key);
+}
+
+#define HASH_API_USAGE &quot;insert|select|delete/realm/key[/value]&quot;
+SWITCH_STANDARD_API(hash_api_function)
+{
+        int argc = 0;
+        char *argv[4] = { 0 };
+        char *mydata = NULL;
+        char *value = NULL;
+        char *hash_key = NULL;
+
+        switch_mutex_lock(globals.db_hash_mutex);
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc &lt; 3 || !argv[0]) {
+                goto usage;
+        }
+
+        hash_key = switch_mprintf(&quot;%s_%s&quot;, argv[1], argv[2]);
+
+        if (!strcasecmp(argv[0], &quot;insert&quot;)) {
+                if (argc &lt; 4) {
+                        goto usage;
+                }
+                if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
+                        switch_safe_free(value);
+                        switch_core_hash_delete(globals.db_hash, hash_key);
+                }
+                value = strdup(argv[3]);
+                switch_assert(value);
+                switch_core_hash_insert(globals.db_hash, hash_key, value);
+                stream-&gt;write_function(stream, &quot;+OK\n&quot;);
+        } else if (!strcasecmp(argv[0], &quot;delete&quot;)) {
+                if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
+                        switch_safe_free(value);
+                        switch_core_hash_delete(globals.db_hash, hash_key);
+                        stream-&gt;write_function(stream, &quot;+OK\n&quot;);
+                } else {
+                        stream-&gt;write_function(stream, &quot;-ERR Not found\n&quot;);
+                }
+        } else if (!strcasecmp(argv[0], &quot;select&quot;)) {
+                if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
+                        stream-&gt;write_function(stream, &quot;%s&quot;, value);
+                }
+        } else {
+                goto usage;
+        }
+
+        goto done;
+
+  usage:
+        stream-&gt;write_function(stream, &quot;-ERR Usage: hash %s\n&quot;, HASH_API_USAGE);
+
+  done:
+        switch_mutex_unlock(globals.db_hash_mutex);
+        switch_safe_free(mydata);
+        switch_safe_free(hash_key);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+/* INIT/DEINIT STUFF */
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load)
+{
+        switch_application_interface_t *app_interface;
+        switch_api_interface_t *commands_api_interface;
+        switch_limit_interface_t *limit_interface;
+
+        memset(&amp;globals, 0, sizeof(&amp;globals));
+        globals.pool = pool;
+
+        if (switch_event_reserve_subclass(LIMIT_EVENT_USAGE) != SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldnt register event subclass \&quot;%s\&quot;&quot;, LIMIT_EVENT_USAGE);
+                return SWITCH_STATUS_FALSE;
+        }
+
+        switch_mutex_init(&amp;globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
+        switch_mutex_init(&amp;globals.limit_hash_mutex, SWITCH_MUTEX_NESTED, globals.pool);
+        switch_mutex_init(&amp;globals.db_hash_mutex, SWITCH_MUTEX_NESTED, globals.pool);
+        switch_core_hash_init(&amp;globals.limit_hash, pool);
+        switch_core_hash_init(&amp;globals.db_hash, pool);
+
+        /* connect my internal structure to the blank pointer passed to me */
+        *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+        /* register limit interfaces */
+        SWITCH_ADD_LIMIT(limit_interface, &quot;hash&quot;, limit_incr_hash, limit_release_hash, limit_usage_hash, limit_reset_hash, limit_status_hash);
+
+        SWITCH_ADD_APP(app_interface, &quot;hash&quot;, &quot;Insert into the hashtable&quot;, HASH_DESC, hash_function, HASH_USAGE, SAF_SUPPORT_NOMEDIA)
+        SWITCH_ADD_API(commands_api_interface, &quot;hash&quot;, &quot;hash get/set&quot;, hash_api_function, &quot;[insert|delete|select]/&lt;realm&gt;/&lt;key&gt;/&lt;value&gt;&quot;);
+        switch_console_set_complete(&quot;add hash insert&quot;);
+        switch_console_set_complete(&quot;add hash delete&quot;);
+        switch_console_set_complete(&quot;add hash select&quot;);
+
+        /* indicate that the module should continue to be loaded */
+        return SWITCH_STATUS_SUCCESS;
+        
+}
+
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_hash_shutdown)
+{
+
+        switch_mutex_destroy(globals.mutex);
+        switch_mutex_destroy(globals.limit_hash_mutex);
+
+        switch_core_hash_destroy(&amp;globals.limit_hash);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcswitch_corec"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/switch_core.c (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/switch_core.c        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/switch_core.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -1290,7 +1290,6 @@
</span><span class="cx">         runtime.timer_affinity = -1;
</span><span class="cx">         switch_load_core_config(&quot;switch.conf&quot;);
</span><span class="cx"> 
</span><del>-
</del><span class="cx">         switch_core_state_machine_init(runtime.memory_pool);
</span><span class="cx"> 
</span><span class="cx">         if (switch_core_sqldb_start(runtime.memory_pool, switch_test_flag((&amp;runtime), SCF_USE_SQL) ? SWITCH_TRUE : SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
</span><span class="lines">@@ -1301,6 +1300,8 @@
</span><span class="cx"> 
</span><span class="cx">         switch_rtp_init(runtime.memory_pool);
</span><span class="cx"> 
</span><ins>+        switch_nat_init(runtime.memory_pool);
+
</ins><span class="cx">         runtime.running = 1;
</span><span class="cx">         runtime.initiated = switch_time_now();
</span><span class="cx">         
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcswitch_loadable_modulec"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/switch_loadable_module.c (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/switch_loadable_module.c        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/switch_loadable_module.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -71,6 +71,7 @@
</span><span class="cx">         switch_hash_t *chat_hash;
</span><span class="cx">         switch_hash_t *say_hash;
</span><span class="cx">         switch_hash_t *management_hash;
</span><ins>+        switch_hash_t *limit_hash;
</ins><span class="cx">         switch_mutex_t *mutex;
</span><span class="cx">         switch_memory_pool_t *pool;
</span><span class="cx"> };
</span><span class="lines">@@ -433,7 +434,33 @@
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">         }
</span><ins>+        if (new_module-&gt;module_interface-&gt;limit_interface) {
+                const switch_limit_interface_t *ptr;
</ins><span class="cx"> 
</span><ins>+                for (ptr = new_module-&gt;module_interface-&gt;limit_interface; ptr; ptr = ptr-&gt;next) {
+                        if (!ptr-&gt;interface_name) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Failed to load limit interface from %s due to no interface name.\n&quot;, key);
+                        } else {
+                                if (switch_core_hash_find(loadable_modules.limit_hash, ptr-&gt;interface_name)) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
+                                                                          &quot;Failed to load limit interface %s. Name %s already exists\n&quot;, key, ptr-&gt;interface_name);
+                                } else {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
+                                                                          &quot;Adding Limit interface '%s'\n&quot;, ptr-&gt;interface_name);
+                                        switch_core_hash_insert(loadable_modules.limit_hash, ptr-&gt;interface_name, (const void *) ptr);
+                                        if (switch_event_create(&amp;event, SWITCH_EVENT_MODULE_LOAD) == SWITCH_STATUS_SUCCESS) {
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;type&quot;, &quot;limit&quot;);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;name&quot;, ptr-&gt;interface_name);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;key&quot;, new_module-&gt;key);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;filename&quot;, new_module-&gt;filename);
+                                                switch_event_fire(&amp;event);
+                                        }
+                                }
+
+                        }
+                }
+        }
+
</ins><span class="cx">         switch_mutex_unlock(loadable_modules.mutex);
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> 
</span><span class="lines">@@ -768,6 +795,23 @@
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        if (old_module-&gt;module_interface-&gt;limit_interface) {
+                const switch_limit_interface_t *ptr;
+
+                for (ptr = old_module-&gt;module_interface-&gt;limit_interface; ptr; ptr = ptr-&gt;next) {
+                        if (ptr-&gt;interface_name) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
+                                                                  &quot;Deleting Limit interface '%s'\n&quot;, ptr-&gt;interface_name);
+                                switch_core_hash_delete(loadable_modules.limit_hash, ptr-&gt;interface_name);
+                                if (switch_event_create(&amp;event, SWITCH_EVENT_MODULE_UNLOAD) == SWITCH_STATUS_SUCCESS) {
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;type&quot;, &quot;limit&quot;);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;name&quot;, ptr-&gt;interface_name);
+                                        switch_event_fire(&amp;event);
+                                }
+                        }
+                }
+        }
+
</ins><span class="cx">         switch_mutex_unlock(loadable_modules.mutex);
</span><span class="cx"> 
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="lines">@@ -1164,6 +1208,7 @@
</span><span class="cx">         switch_core_hash_init_nocase(&amp;loadable_modules.chat_hash, loadable_modules.pool);
</span><span class="cx">         switch_core_hash_init_nocase(&amp;loadable_modules.say_hash, loadable_modules.pool);
</span><span class="cx">         switch_core_hash_init_nocase(&amp;loadable_modules.management_hash, loadable_modules.pool);
</span><ins>+        switch_core_hash_init_nocase(&amp;loadable_modules.limit_hash, loadable_modules.pool);
</ins><span class="cx">         switch_core_hash_init_nocase(&amp;loadable_modules.dialplan_hash, loadable_modules.pool);
</span><span class="cx">         switch_mutex_init(&amp;loadable_modules.mutex, SWITCH_MUTEX_NESTED, loadable_modules.pool);
</span><span class="cx"> 
</span><span class="lines">@@ -1347,6 +1392,7 @@
</span><span class="cx">         switch_core_hash_destroy(&amp;loadable_modules.chat_hash);
</span><span class="cx">         switch_core_hash_destroy(&amp;loadable_modules.say_hash);
</span><span class="cx">         switch_core_hash_destroy(&amp;loadable_modules.management_hash);
</span><ins>+        switch_core_hash_destroy(&amp;loadable_modules.limit_hash);
</ins><span class="cx">         switch_core_hash_destroy(&amp;loadable_modules.dialplan_hash);
</span><span class="cx"> 
</span><span class="cx"> }
</span><span class="lines">@@ -1403,17 +1449,18 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx"> HASH_FUNC(dialplan)
</span><del>-        HASH_FUNC(timer)
-        HASH_FUNC(application)
-        HASH_FUNC(api)
-        HASH_FUNC(file)
-        HASH_FUNC(speech)
-        HASH_FUNC(asr)
-        HASH_FUNC(directory)
-        HASH_FUNC(chat)
</del><ins>+HASH_FUNC(timer)
+HASH_FUNC(application)
+HASH_FUNC(api)
+HASH_FUNC(file)
+HASH_FUNC(speech)
+HASH_FUNC(asr)
+HASH_FUNC(directory)
+HASH_FUNC(chat)
+HASH_FUNC(limit)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-        SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interface(const char *name)
</del><ins>+SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interface(const char *name)
</ins><span class="cx"> {
</span><span class="cx">         return switch_core_hash_find_locked(loadable_modules.say_hash, name, loadable_modules.mutex);
</span><span class="cx"> }
</span><span class="lines">@@ -1683,6 +1730,9 @@
</span><span class="cx">         case SWITCH_MANAGEMENT_INTERFACE:
</span><span class="cx">                 ALLOC_INTERFACE(management)
</span><span class="cx"> 
</span><ins>+        case SWITCH_LIMIT_INTERFACE:
+                ALLOC_INTERFACE(limit)
+
</ins><span class="cx">         default:
</span><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Invalid Module Type!\n&quot;);
</span><span class="cx">                 return NULL;
</span></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>

</body>
</html>