This mod via bug 7531
[asterisk/asterisk.git] / main / channel.c
index c1e3c0a..ace4a41 100644 (file)
@@ -29,6 +29,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <string.h>
 #include <sys/time.h>
 #include <signal.h>
@@ -100,7 +101,7 @@ static int uniqueint = 0;
 
 unsigned long global_fin = 0, global_fout = 0;
 
-AST_THREADSTORAGE(state2str_threadbuf, state2str_threadbuf_init);
+AST_THREADSTORAGE(state2str_threadbuf);
 #define STATE2STR_BUFSIZE   32
 
 /* XXX 100ms ... this won't work with wideband support */
@@ -289,19 +290,19 @@ static char *complete_channeltypes(const char *line, const char *word, int pos,
 }
 
 static char show_channeltypes_usage[] =
-"Usage: channeltype list\n"
+"Usage: core show channeltypes\n"
 "       Lists available channel types registered in your Asterisk server.\n";
 
 static char show_channeltype_usage[] =
-"Usage: channeltype show <name>\n"
+"Usage: core show channeltype <name>\n"
 "      Show details about the specified channel type, <name>.\n";
 
 static struct ast_cli_entry cli_channel[] = {
-       { { "channeltype", "list", NULL },
+       { { "core", "show", "channeltypes", NULL },
        show_channeltypes, "List available channel types",
        show_channeltypes_usage },
 
-       { { "channeltype", "show", NULL },
+       { { "core", "show", "channeltype", NULL },
        show_channeltype, "Give more details on that channel type",
        show_channeltype_usage, complete_channeltypes },
 };
@@ -330,6 +331,21 @@ static int ast_check_hangup_locked(struct ast_channel *chan)
        return res;
 }
 
+/*! \brief printf the string into a correctly sized mallocd buffer, and return the buffer */
+char *ast_safe_string_alloc(const char *fmt, ...)
+{
+       char *b2,buf[1];
+       int len;
+
+       va_list args;
+       va_start(args, fmt);
+       len = vsnprintf(buf, 1, fmt, args);
+       b2 = ast_malloc(len+1);
+       vsnprintf(b2, len+1,  fmt, args);
+       va_end(args);
+       return b2;
+}
+
 /*! \brief Initiate system shutdown */
 void ast_begin_shutdown(int hangup)
 {
@@ -608,12 +624,13 @@ static const struct ast_channel_tech null_tech = {
 };
 
 /*! \brief Create a new channel structure */
-struct ast_channel *ast_channel_alloc(int needqueue)
+struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *name_fmt, ...)
 {
        struct ast_channel *tmp;
        int x;
        int flags;
        struct varshead *headp;
+       va_list ap1, ap2;
 
        /* If shutting down, don't allocate any new channels */
        if (shutting_down) {
@@ -654,7 +671,7 @@ struct ast_channel *ast_channel_alloc(int needqueue)
        if (needqueue) {
                if (pipe(tmp->alertpipe)) {
                        ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
-                       ast_string_field_free_all(tmp);
+                       ast_string_field_free_pools(tmp);
                        free(tmp);
                        return NULL;
                } else {
@@ -671,10 +688,10 @@ struct ast_channel *ast_channel_alloc(int needqueue)
        /* And timing pipe */
        tmp->fds[AST_TIMING_FD] = tmp->timingfd;
        ast_string_field_set(tmp, name, "**Unknown**");
-       
+
        /* Initial state */
-       tmp->_state = AST_STATE_DOWN;
-       
+       tmp->_state = state;
+
        tmp->streamid = -1;
        
        tmp->fin = global_fin;
@@ -688,6 +705,37 @@ struct ast_channel *ast_channel_alloc(int needqueue)
                        (long) time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1));
        }
 
+       if (!ast_strlen_zero(name_fmt)) {
+               /* Almost every channel is calling this function, and setting the name via the ast_string_field_build() call.
+                * And they all use slightly different formats for their name string.
+                * This means, to set the name here, we have to accept variable args, and call the string_field_build from here.
+                * This means, that the stringfields must have a routine that takes the va_lists directly, and 
+                * uses them to build the string, instead of forming the va_lists internally from the vararg ... list.
+                * This new function was written so this can be accomplished.
+                */
+               va_start(ap1, name_fmt);
+               va_start(ap2, name_fmt);
+               ast_string_field_build_va(tmp, name, name_fmt, ap1, ap2);
+               va_end(ap1);
+               va_end(ap2);
+
+               /* and now, since the channel structure is built, and has its name, let's call the
+                * manager event generator with this Newchannel event. This is the proper and correct
+                * place to make this call, but you sure do have to pass a lot of data into this func
+                * to do it here!
+                */
+               manager_event(EVENT_FLAG_CALL, "Newchannel",
+                             "Channel: %s\r\n"
+                             "State: %s\r\n"
+                             "CallerIDNum: %s\r\n"
+                             "CallerIDName: %s\r\n"
+                             "Uniqueid: %s\r\n",
+                             tmp->name, ast_state2str(state),
+                             S_OR(cid_num, "<unknown>"),
+                             S_OR(cid_name, "<unknown>"),
+                             tmp->uniqueid);
+       }
+       
        headp = &tmp->varshead;
        AST_LIST_HEAD_INIT_NOLOCK(headp);
        
@@ -1055,7 +1103,7 @@ void ast_channel_free(struct ast_channel *chan)
        /* Destroy the jitterbuffer */
        ast_jb_destroy(chan);
 
-       ast_string_field_free_all(chan);
+       ast_string_field_free_pools(chan);
        free(chan);
        AST_LIST_UNLOCK(&channels);
 
@@ -2615,7 +2663,10 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                res = 0;
                break;
        default:
-               res = chan->tech->write(chan, f);
+               /* At this point, fr is the incoming frame and f is NULL.  Channels do
+                * not expect to get NULL as a frame pointer and will segfault.  Hence,
+                * we output the original frame passed in. */
+               res = chan->tech->write(chan, fr);
                break;
        }
 
@@ -2855,19 +2906,8 @@ struct ast_channel *ast_request(const char *type, int format, void *data, int *c
                
                if (!(c = chan->tech->requester(type, capabilities | videoformat, data, cause)))
                        return NULL;
-
-               if (c->_state == AST_STATE_DOWN) {
-                       manager_event(EVENT_FLAG_CALL, "Newchannel",
-                                     "Channel: %s\r\n"
-                                     "State: %s\r\n"
-                                     "CallerIDNum: %s\r\n"
-                                     "CallerIDName: %s\r\n"
-                                     "Uniqueid: %s\r\n",
-                                     c->name, ast_state2str(c->_state),
-                                     S_OR(c->cid.cid_num, "<unknown>"),
-                                     S_OR(c->cid.cid_name, "<unknown>"),
-                                     c->uniqueid);
-               }
+               
+               /* no need to generate a Newchannel event here; it is done in the channel_alloc call */
                return c;
        }
 
@@ -3215,6 +3255,9 @@ int ast_do_masquerade(struct ast_channel *original)
                ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
                        clone->name, clone->_state, original->name, original->_state);
 
+       manager_event(EVENT_FLAG_CALL, "Masquerade", "Clone: %s\r\nCloneState: %s\r\nOriginal: %s\r\nOriginalState: %s\r\n",
+                     clone->name, ast_state2str(clone->_state), original->name, ast_state2str(original->_state));
+
        /* XXX This is a seriously wacked out operation.  We're essentially putting the guts of
           the clone channel into the original channel.  Start by killing off the original
           channel's backend.   I'm not sure we're going to keep this function, because
@@ -3512,8 +3555,9 @@ int ast_setstate(struct ast_channel *chan, enum ast_channel_state state)
 
        chan->_state = state;
        ast_device_state_changed_literal(chan->name);
+       /* setstate used to conditionally report Newchannel; this is no more */
        manager_event(EVENT_FLAG_CALL,
-                     (oldstate == AST_STATE_DOWN) ? "Newchannel" : "Newstate",
+                     "Newstate",
                      "Channel: %s\r\n"
                      "State: %s\r\n"
                      "CallerIDNum: %s\r\n"
@@ -3838,7 +3882,11 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                                bridge_playfile(c1, c0, config->warning_sound, t);
                                }
                                if (config->warning_freq) {
-                                       nexteventts = ast_tvadd(nexteventts, ast_samp2tv(config->warning_freq, 1000));
+
+                                       if (time_left_ms > (config->warning_freq + 5000)) {
+                                               nexteventts = ast_tvadd(nexteventts, ast_samp2tv(config->warning_freq, 1000));
+                                       }
+                                                               
                                } else
                                        nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
                        }
@@ -4493,17 +4541,9 @@ int ast_channel_unlock(struct ast_channel *chan)
        res = ast_mutex_unlock(&chan->lock);
 
        if (option_debug > 2) {
-               /* Try to find counter if possible on your platform 
-                       I've only found out how to do this on Linux
-                       DEBUG_THREADS changes the lock structure
-               */
-#ifdef __linux__
-               int count = 0;
 #ifdef DEBUG_THREADS
-               if ((count = chan->lock.mutex.__data.__count))
-#else
-               if ((count = chan->lock.__data.__count))
-#endif
+               int count = 0;
+               if ((count = chan->lock.reentrancy))
                        if (option_debug)
                                ast_log(LOG_DEBUG, ":::=== Still have %d locks (recursive)\n", count);
 #endif
@@ -4536,13 +4576,9 @@ int ast_channel_lock(struct ast_channel *chan)
        res = ast_mutex_lock(&chan->lock);
 
        if (option_debug > 3) {
-#ifdef __linux__
-               int count = 0;
 #ifdef DEBUG_THREADS
-               if ((count = chan->lock.mutex.__data.__count))
-#else
-               if ((count = chan->lock.__data.__count))
-#endif
+               int count = 0;
+               if ((count = chan->lock.reentrancy))
                        if (option_debug)
                                ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
 #endif
@@ -4574,13 +4610,9 @@ int ast_channel_trylock(struct ast_channel *chan)
        res = ast_mutex_trylock(&chan->lock);
 
        if (option_debug > 2) {
-#ifdef __linux__
-               int count = 0;
 #ifdef DEBUG_THREADS
-               if ((count = chan->lock.mutex.__data.__count))
-#else
-               if ((count = chan->lock.__data.__count))
-#endif
+               int count = 0;
+               if ((count = chan->lock.reentrancy))
                        if (option_debug)
                                ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
 #endif