This mod via bug 7531
[asterisk/asterisk.git] / main / channel.c
index 605bb5b..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;
        }
 
@@ -3515,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"
@@ -3841,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));
                        }
@@ -4496,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
@@ -4539,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
@@ -4577,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