Modify TIMEOUT() to be accurate down to the millisecond.
authorTilghman Lesher <tilghman@meg.abyt.es>
Thu, 1 May 2008 23:06:23 +0000 (23:06 +0000)
committerTilghman Lesher <tilghman@meg.abyt.es>
Thu, 1 May 2008 23:06:23 +0000 (23:06 +0000)
(closes issue #10540)
 Reported by: spendergrass
 Patches:
       20080417__bug10540.diff.txt uploaded by Corydon76 (license 14)
 Tested by: blitzrage

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@115076 65c4cc65-6c06-0410-ace0-fbb531ad65f3

19 files changed:
CHANGES
apps/app_dial.c
apps/app_disa.c
apps/app_dumpchan.c
apps/app_queue.c
apps/app_read.c
apps/app_readexten.c
apps/app_rpt.c
apps/app_speech_utils.c
funcs/func_timeout.c
include/asterisk/channel.h
include/asterisk/pbx.h
main/app.c
main/channel.c
main/cli.c
main/dial.c
main/manager.c
main/pbx.c
res/res_agi.c

diff --git a/CHANGES b/CHANGES
index e2a8602..5a75d51 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -88,6 +88,10 @@ DNS manager changes
   * Addresses managed by DNS manager now can check to see if there is a DNS
     SRV record for a given domain and will use that hostname/port if present.
 
+Dialplan function changes
+-------------------------
+ * TIMEOUT() has been modified to be accurate down to the millisecond.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 1.4.X to Asterisk 1.6.0  -------------
 ------------------------------------------------------------------------------
index 5730d99..d72a854 100644 (file)
@@ -1472,7 +1472,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
 
                tc->appl = "AppDial";
                tc->data = "(Outgoing Line)";
-               tc->whentohangup = 0;
+               memset(&tc->whentohangup, 0, sizeof(tc->whentohangup));
 
                S_REPLACE(tc->cid.cid_num, ast_strdup(chan->cid.cid_num));
                S_REPLACE(tc->cid.cid_name, ast_strdup(chan->cid.cid_name));
@@ -1839,7 +1839,8 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
 
                if (!res) {
                        if (calldurationlimit > 0) {
-                               peer->whentohangup = time(NULL) + calldurationlimit;
+                               struct timeval whentohangup = { calldurationlimit, 0 };
+                               peer->whentohangup = ast_tvadd(ast_tvnow(), whentohangup);
                        }
                        if (!ast_strlen_zero(dtmfcalled)) {
                                ast_verb(3, "Sending DTMF '%s' to the called party.\n", dtmfcalled);
@@ -1967,7 +1968,7 @@ out:
 
        if ((ast_test_flag64(peerflags, OPT_GO_ON)) && !ast_check_hangup(chan) && (res != AST_PBX_KEEPALIVE) && (res != AST_PBX_INCOMPLETE)) {
                if (calldurationlimit)
-                       chan->whentohangup = 0;
+                       memset(&chan->whentohangup, 0, sizeof(chan->whentohangup));
                res = 0;
        }
 
index 16c2675..53bcc2c 100644 (file)
@@ -116,8 +116,8 @@ static void play_dialtone(struct ast_channel *chan, char *mailbox)
 static int disa_exec(struct ast_channel *chan, void *data)
 {
        int i = 0, j, k = 0, did_ignore = 0, special_noanswer = 0;
-       int firstdigittimeout = (chan->pbx ? chan->pbx->rtimeout * 1000 : 20000);
-       int digittimeout = (chan->pbx ? chan->pbx->dtimeout * 1000 : 10000);
+       int firstdigittimeout = (chan->pbx ? chan->pbx->rtimeoutms : 20000);
+       int digittimeout = (chan->pbx ? chan->pbx->dtimeoutms : 10000);
        struct ast_flags flags;
        char *tmp, exten[AST_MAX_EXTENSION] = "", acctcode[20]="";
        char pwline[256];
index d01ea7a..7742633 100644 (file)
@@ -115,7 +115,7 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
                        ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->rawwriteformat),
                        ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->rawreadformat),
                        c->fds[0], c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
-                       c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", (long)c->whentohangup,
+                       c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", (long)c->whentohangup.tv_sec,
                        hour,
                        min,
                        sec,
index ad87ad5..63f84b2 100644 (file)
@@ -2228,7 +2228,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
        
        tmp->chan->appl = "AppQueue";
        tmp->chan->data = "(Outgoing Line)";
-       tmp->chan->whentohangup = 0;
+       memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
        if (tmp->chan->cid.cid_num)
                ast_free(tmp->chan->cid.cid_num);
        tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
index a7fdf62..9174210 100644 (file)
@@ -162,7 +162,7 @@ static int read_exec(struct ast_channel *chan, void *data)
                        ast_stopstream(chan);
                        if (ts && ts->data[0]) {
                                if (!to)
-                                       to = chan->pbx ? chan->pbx->rtimeout * 1000 : 6000;
+                                       to = chan->pbx ? chan->pbx->rtimeoutms : 6000;
                                res = ast_playtones_start(chan, 0, ts->data, 0);
                                for (x = 0; x < maxdigits; ) {
                                        res = ast_waitfordigit(chan, to);
index cb4fd8c..93ca4e6 100644 (file)
@@ -121,10 +121,10 @@ static int readexten_exec(struct ast_channel *chan, void *data)
        }
 
        if (timeout <= 0)
-               timeout = chan->pbx ? chan->pbx->rtimeout * 1000 : 10000;
+               timeout = chan->pbx ? chan->pbx->rtimeoutms : 10000;
 
        if (digit_timeout <= 0)
-               digit_timeout = chan->pbx ? chan->pbx->dtimeout * 1000 : 5000;
+               digit_timeout = chan->pbx ? chan->pbx->dtimeoutms : 5000;
 
        if (ast_test_flag(&flags, OPT_INDICATION) && !ast_strlen_zero(arglist.filename))
                ts = ast_get_indication_tone(chan->zone, arglist.filename);
index d91b45f..cf64d12 100644 (file)
@@ -298,6 +298,8 @@ static char *remote_rig_rbi = "rbi";
 
 static  pthread_t rpt_master_thread;
 
+struct timeval cancel_atimeout = { 0, 0 };
+
 struct rpt;
 
 struct rpt_link
@@ -2930,7 +2932,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
                if (l->chan) {
                        ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
                        ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
-                       l->chan->whentohangup = 0;
+                       ast_channel_setwhentohangup_tv(l->chan, cancel_atimeout);
                        l->chan->appl = "Apprpt";
                        l->chan->data = "(Remote Rx)";
                        ast_verb(3, "rpt (remote) initiating call to %s/%s on %s\n",
@@ -3041,7 +3043,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
                if (l->chan) {
                        ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
                        ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
-                       l->chan->whentohangup = 0;
+                       ast_channel_setwhentohangup_tv(l->chan, cancel_atimeout);
                        l->chan->appl = "Apprpt";
                        l->chan->data = "(Remote Rx)";
                        ast_verb(3, "rpt (remote) initiating call to %s/%s on %s\n",
@@ -5462,7 +5464,7 @@ static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
        if (l->chan) {
                ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
                ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
-               l->chan->whentohangup = 0;
+               ast_channel_setwhentohangup_tv(l->chan, cancel_atimeout);
                l->chan->appl = "Apprpt";
                l->chan->data = "(Remote Rx)";
                ast_verb(3, "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
@@ -5699,7 +5701,7 @@ static void *rpt(void *this)
                }
                ast_set_read_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
                ast_set_write_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
-               myrpt->rxchannel->whentohangup = 0;
+               ast_channel_setwhentohangup_tv(myrpt->rxchannel, cancel_atimeout);
                myrpt->rxchannel->appl = "Apprpt";
                myrpt->rxchannel->data = "(Repeater Rx)";
                ast_verb(3, "rpt (Rx) initiating call to %s/%s on %s\n",
@@ -5740,7 +5742,7 @@ static void *rpt(void *this)
                        }                       
                        ast_set_read_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
                        ast_set_write_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
-                       myrpt->txchannel->whentohangup = 0;
+                       ast_channel_setwhentohangup_tv(myrpt->txchannel, cancel_atimeout);
                        myrpt->txchannel->appl = "Apprpt";
                        myrpt->txchannel->data = "(Repeater Tx)";
                        ast_verb(3, "rpt (Tx) initiating call to %s/%s on %s\n",
@@ -7109,7 +7111,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
        if (myrpt->rxchannel) {
                ast_set_read_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
                ast_set_write_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
-               myrpt->rxchannel->whentohangup = 0;
+               ast_channel_setwhentohangup_tv(myrpt->rxchannel, cancel_atimeout);
                myrpt->rxchannel->appl = "Apprpt";
                myrpt->rxchannel->data = "(Link Rx)";
                ast_verb(3, "rpt (Rx) initiating call to %s/%s on %s\n",
@@ -7136,7 +7138,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
                if (myrpt->txchannel) {
                        ast_set_read_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
                        ast_set_write_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
-                       myrpt->txchannel->whentohangup = 0;
+                       ast_channel_setwhentohangup_tv(myrpt->txchannel, cancel_atimeout);
                        myrpt->txchannel->appl = "Apprpt";
                        myrpt->txchannel->data = "(Link Tx)";
                        ast_verb(3, "rpt (Tx) initiating call to %s/%s on %s\n",
index 4677c33..5082478 100644 (file)
@@ -513,7 +513,7 @@ static int speech_background(struct ast_channel *chan, void *data)
        struct ast_frame *f = NULL;
        int oldreadformat = AST_FORMAT_SLINEAR;
        char dtmf[AST_MAX_EXTENSION] = "";
-       time_t start, current;
+       struct timeval start = { 0, 0 }, current;
        struct ast_datastore *datastore = NULL;
        char *parse, *filename_tmp = NULL, *filename = NULL, tmp[2] = "", dtmf_terminator = '#';
        const char *tmp2 = NULL;
@@ -552,7 +552,7 @@ static int speech_background(struct ast_channel *chan, void *data)
                /* Yay sound file */
                filename_tmp = ast_strdupa(args.soundfile);
                if (!ast_strlen_zero(args.timeout)) {
-                       if ((timeout = atoi(args.timeout)) == 0)
+                       if ((timeout = atof(args.timeout) * 1000.0) == 0)
                                timeout = -1;
                } else
                        timeout = 0;
@@ -612,8 +612,8 @@ static int speech_background(struct ast_channel *chan, void *data)
 
                /* Do timeout check (shared between audio/dtmf) */
                if ((!quieted || strlen(dtmf)) && started == 1) {
-                       time(&current);
-                       if ((current-start) >= timeout) {
+                       current = ast_tvnow();
+                       if ((ast_tvdiff_ms(start, current)) >= timeout) {
                                done = 1;
                                if (f)
                                        ast_frfree(f);
@@ -642,7 +642,7 @@ static int speech_background(struct ast_channel *chan, void *data)
                                                ast_frfree(f);
                                        break;
                                }
-                               time(&start);
+                               start = ast_tvnow();
                                started = 1;
                        }
                        /* Write audio frame out to speech engine if no DTMF has been received */
@@ -701,10 +701,10 @@ static int speech_background(struct ast_channel *chan, void *data)
                                        }
                                        if (!started) {
                                                /* Change timeout to be 5 seconds for DTMF input */
-                                               timeout = (chan->pbx && chan->pbx->dtimeout) ? chan->pbx->dtimeout : 5;
+                                               timeout = (chan->pbx && chan->pbx->dtimeoutms) ? chan->pbx->dtimeoutms : 5000;
                                                started = 1;
                                        }
-                                       time(&start);
+                                       start = ast_tvnow();
                                        snprintf(tmp, sizeof(tmp), "%c", f->subclass);
                                        strncat(dtmf, tmp, sizeof(dtmf) - strlen(dtmf) - 1);
                                        /* If the maximum length of the DTMF has been reached, stop now */
index a42718a..2f282b3 100644 (file)
@@ -37,7 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 static int timeout_read(struct ast_channel *chan, const char *cmd, char *data,
                        char *buf, size_t len)
 {
-       time_t myt;
+       struct timeval myt;
 
        if (!chan)
                return -1;
@@ -50,25 +50,25 @@ static int timeout_read(struct ast_channel *chan, const char *cmd, char *data,
        switch (*data) {
        case 'a':
        case 'A':
-               if (chan->whentohangup == 0) {
+               if (ast_tvzero(chan->whentohangup)) {
                        ast_copy_string(buf, "0", len);
                } else {
-                       time(&myt);
-                       snprintf(buf, len, "%d", (int) (chan->whentohangup - myt));
+                       myt = ast_tvnow();
+                       snprintf(buf, len, "%.3f", ast_tvdiff_ms(myt, chan->whentohangup) / 1000.0);
                }
                break;
 
        case 'r':
        case 'R':
                if (chan->pbx) {
-                       snprintf(buf, len, "%d", chan->pbx->rtimeout);
+                       snprintf(buf, len, "%.3f", chan->pbx->rtimeoutms / 1000.0);
                }
                break;
 
        case 'd':
        case 'D':
                if (chan->pbx) {
-                       snprintf(buf, len, "%d", chan->pbx->dtimeout);
+                       snprintf(buf, len, "%.3f", chan->pbx->dtimeoutms / 1000.0);
                }
                break;
 
@@ -83,9 +83,10 @@ static int timeout_read(struct ast_channel *chan, const char *cmd, char *data,
 static int timeout_write(struct ast_channel *chan, const char *cmd, char *data,
                         const char *value)
 {
-       int x;
+       double x;
        char timestr[64];
        struct ast_tm myt;
+       struct timeval tv;
 
        if (!chan)
                return -1;
@@ -98,17 +99,18 @@ static int timeout_write(struct ast_channel *chan, const char *cmd, char *data,
        if (!value)
                return -1;
 
-       x = atoi(value);
-       if (x < 0)
-               x = 0;
+       if ((sscanf(value, "%ld%lf", (long *)&tv.tv_sec, &x) == 0) || tv.tv_sec < 0)
+               tv.tv_sec = 0;
+       else
+               tv.tv_usec = x * 1000000;
 
        switch (*data) {
        case 'a':
        case 'A':
-               ast_channel_setwhentohangup(chan, x);
+               ast_channel_setwhentohangup_tv(chan, tv);
                if (VERBOSITY_ATLEAST(3)) {
-                       if (chan->whentohangup) {
-                               struct timeval tv = { chan->whentohangup, 0 };
+                       if (!ast_tvzero(chan->whentohangup)) {
+                               tv = ast_tvadd(tv, ast_tvnow());
                                ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S.%3q %Z",
                                        ast_localtime(&tv, &myt, NULL));
                                ast_verbose("Channel will hangup at %s.\n", timestr);
@@ -121,16 +123,16 @@ static int timeout_write(struct ast_channel *chan, const char *cmd, char *data,
        case 'r':
        case 'R':
                if (chan->pbx) {
-                       chan->pbx->rtimeout = x;
-                       ast_verb(3, "Response timeout set to %d\n", chan->pbx->rtimeout);
+                       chan->pbx->rtimeoutms = tv.tv_sec * 1000 + tv.tv_usec / 1000.0;
+                       ast_verb(3, "Response timeout set to %.3f\n", chan->pbx->rtimeoutms / 1000.0);
                }
                break;
 
        case 'd':
        case 'D':
                if (chan->pbx) {
-                       chan->pbx->dtimeout = x;
-                       ast_verb(3, "Digit timeout set to %d\n", chan->pbx->dtimeout);
+                       chan->pbx->dtimeoutms = tv.tv_sec * 1000 + tv.tv_usec / 1000.0;
+                       ast_verb(3, "Digit timeout set to %.3f\n", chan->pbx->dtimeoutms / 1000.0);
                }
                break;
 
index fcd1aa8..9fdc6de 100644 (file)
@@ -455,7 +455,7 @@ struct ast_channel {
 
        int _softhangup;                                /*!< Whether or not we have been hung up...  Do not set this value
                                                                directly, use ast_softhangup() */
-       time_t  whentohangup;                           /*!< Non-zero, set to actual time when channel is to be hung up */
+       struct timeval whentohangup;        /*!< Non-zero, set to actual time when channel is to be hung up */
        pthread_t blocker;                              /*!< If anyone is blocking, this is them */
        ast_mutex_t lock_dont_use;                      /*!< Lock a channel for some operations. See ast_channel_lock() */
        const char *blockproc;                          /*!< Procedure causing blocking */
@@ -920,19 +920,20 @@ int ast_check_hangup(struct ast_channel *chan);
 
 /*! \brief Compare a offset with the settings of when to hang a channel up 
  * \param chan channel on which to check for hang up
- * \param offset offset in seconds from current time
+ * \param offset offset in seconds and useconds from current time
  * \return 1, 0, or -1
  * This function compares a offset from current time with the absolute time 
  * out on a channel (when to hang up). If the absolute time out on a channel
  * is earlier than current time plus the offset, it returns 1, if the two
  * time values are equal, it return 0, otherwise, it return -1.
  */
-int ast_channel_cmpwhentohangup(struct ast_channel *chan, time_t offset);
+int ast_channel_cmpwhentohangup(struct ast_channel *chan, time_t offset) __attribute__ ((deprecated));
+int ast_channel_cmpwhentohangup_tv(struct ast_channel *chan, struct timeval offset);
 
 /*! \brief Set when to hang a channel up 
  *
  * \param chan channel on which to check for hang up
- * \param offset offset in seconds from current time of when to hang up
+ * \param offset offset in seconds and useconds relative to the current time of when to hang up
  *
  * This function sets the absolute time out on a channel (when to hang up).
  *
@@ -941,7 +942,8 @@ int ast_channel_cmpwhentohangup(struct ast_channel *chan, time_t offset);
  *
  * \return Nothing
  */
-void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset);
+void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset) __attribute__ ((deprecated));
+void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval offset);
 
 /*! 
  * \brief Answer a channel
index d38325b..3e3669a 100644 (file)
@@ -112,8 +112,8 @@ int ast_build_timing(struct ast_timing *i, const char *info);
 int ast_check_timing(const struct ast_timing *i);
 
 struct ast_pbx {
-       int dtimeout;                           /*!< Timeout between digits (seconds) */
-       int rtimeout;                           /*!< Timeout for response (seconds) */
+       int dtimeoutms;                         /*!< Timeout between digits (milliseconds) */
+       int rtimeoutms;                         /*!< Timeout for response (milliseconds) */
 };
 
 
index e5c7129..868f44d 100644 (file)
@@ -72,7 +72,7 @@ int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect,
                maxlen = size;
        
        if (!timeout && chan->pbx)
-               timeout = chan->pbx->dtimeout;
+               timeout = chan->pbx->dtimeoutms / 1000.0;
        else if (!timeout)
                timeout = 5;
 
@@ -130,8 +130,8 @@ int ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxl
                }
                if (ast_strlen_zero(filename)) {
                        /* set timeouts for the last prompt */
-                       fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
-                       to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
+                       fto = c->pbx ? c->pbx->rtimeoutms : 6000;
+                       to = c->pbx ? c->pbx->dtimeoutms : 2000;
 
                        if (timeout > 0) 
                                fto = to = timeout;
@@ -142,7 +142,7 @@ int ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxl
                           get rid of the long timeout between 
                           prompts, and make it 50ms */
                        fto = 50;
-                       to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
+                       to = c->pbx ? c->pbx->dtimeoutms : 2000;
                }
                res = ast_readstring(c, s, maxlen, to, fto, "#");
                if (!ast_strlen_zero(s))
@@ -1431,7 +1431,7 @@ static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option,
                        res = 0;
                return res;
        case AST_ACTION_WAITOPTION:
-               res = ast_waitfordigit(chan, 1000 * (chan->pbx ? chan->pbx->rtimeout : 10));
+               res = ast_waitfordigit(chan, chan->pbx ? chan->pbx->rtimeoutms : 10000);
                if (!res)
                        return 't';
                return res;
@@ -1484,7 +1484,7 @@ static int read_newoption(struct ast_channel *chan, struct ast_ivr_menu *menu, c
        int res = 0;
        int ms;
        while (option_matchmore(menu, exten)) {
-               ms = chan->pbx ? chan->pbx->dtimeout : 5000;
+               ms = chan->pbx ? chan->pbx->dtimeoutms : 5000;
                if (strlen(exten) >= maxexten - 1) 
                        break;
                res = ast_waitfordigit(chan, ms);
index 351d641..2cb2bc3 100644 (file)
@@ -464,9 +464,9 @@ int ast_check_hangup(struct ast_channel *chan)
                return 1;
        if (!chan->tech_pvt)            /* yes if no technology private data */
                return 1;
-       if (!chan->whentohangup)        /* no if no hangup scheduled */
+       if (ast_tvzero(chan->whentohangup))     /* no if no hangup scheduled */
                return 0;
-       if (chan->whentohangup > time(NULL))    /* no if hangup time has not come yet. */
+       if (ast_tvdiff_ms(chan->whentohangup, ast_tvnow()) > 0)         /* no if hangup time has not come yet. */
                return 0;
        chan->_softhangup |= AST_SOFTHANGUP_TIMEOUT;    /* record event */
        return 1;
@@ -519,32 +519,39 @@ int ast_shutting_down(void)
 }
 
 /*! \brief Set when to hangup channel */
-void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset)
+void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval offset)
 {
-       chan->whentohangup = offset ? time(NULL) + offset : 0;
+       chan->whentohangup = ast_tvzero(offset) ? offset : ast_tvadd(offset, ast_tvnow());
        ast_queue_frame(chan, &ast_null_frame);
        return;
 }
 
+void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset)
+{
+       struct timeval tv = { offset, };
+       ast_channel_setwhentohangup_tv(chan, tv);
+}
+
 /*! \brief Compare a offset with when to hangup channel */
-int ast_channel_cmpwhentohangup(struct ast_channel *chan, time_t offset)
+int ast_channel_cmpwhentohangup_tv(struct ast_channel *chan, struct timeval offset)
 {
-       time_t whentohangup;
+       struct timeval whentohangup;
 
-       if (!chan->whentohangup)
-               return (offset == 0) ? 0 : -1;
+       if (ast_tvzero(chan->whentohangup))
+               return ast_tvzero(offset) ? 0 : -1;
 
-       if (!offset) /* XXX why is this special? */
+       if (ast_tvzero(offset))
                return 1;
 
-       whentohangup = offset + time(NULL);
+       whentohangup = ast_tvadd(offset, ast_tvnow());
 
-       if (chan->whentohangup < whentohangup)
-               return 1;
-       else if (chan->whentohangup == whentohangup)
-               return 0;
-       else
-               return -1;
+       return ast_tvdiff_ms(whentohangup, chan->whentohangup);
+}
+
+int ast_channel_cmpwhentohangup(struct ast_channel *chan, time_t offset)
+{
+       struct timeval tv = { offset, };
+       return ast_channel_cmpwhentohangup_tv(chan, tv);
 }
 
 /*! \brief Register a new telephony channel in Asterisk */
@@ -1793,8 +1800,8 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
        long rms;
        int x, y, max;
        int sz;
-       time_t now = 0;
-       long whentohangup = 0, diff;
+       struct timeval now = { 0, 0 };
+       struct timeval whentohangup = { 0, 0 }, diff;
        struct ast_channel *winner = NULL;
        struct fdmap {
                int chan;
@@ -1820,25 +1827,25 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
                        ast_channel_unlock(c[x]);
                        return NULL;
                }
-               if (c[x]->whentohangup) {
-                       if (!whentohangup)
-                               time(&now);
-                       diff = c[x]->whentohangup - now;
-                       if (diff < 1) {
+               if (!ast_tvzero(c[x]->whentohangup)) {
+                       if (ast_tvzero(whentohangup))
+                               now = ast_tvnow();
+                       diff = ast_tvsub(c[x]->whentohangup, now);
+                       if (diff.tv_sec < 0 || ast_tvzero(diff)) {
                                /* Should already be hungup */
                                c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
                                ast_channel_unlock(c[x]);
                                return c[x];
                        }
-                       if (!whentohangup || (diff < whentohangup))
+                       if (ast_tvzero(whentohangup) || ast_tvcmp(diff, whentohangup) < 0)
                                whentohangup = diff;
                }
                ast_channel_unlock(c[x]);
        }
        /* Wait full interval */
        rms = *ms;
-       if (whentohangup) {
-               rms = whentohangup * 1000;              /* timeout in milliseconds */
+       if (!ast_tvzero(whentohangup)) {
+               rms = whentohangup.tv_sec * 1000 + whentohangup.tv_usec / 1000;              /* timeout in milliseconds */
                if (*ms >= 0 && *ms < rms)              /* original *ms still smaller */
                        rms =  *ms;
        }
@@ -1884,10 +1891,10 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
                        *ms = -1;
                return NULL;
        }
-       if (whentohangup) {   /* if we have a timeout, check who expired */
-               time(&now);
+       if (!ast_tvzero(whentohangup)) {   /* if we have a timeout, check who expired */
+               now = ast_tvnow();
                for (x = 0; x < n; x++) {
-                       if (c[x]->whentohangup && now >= c[x]->whentohangup) {
+                       if (!ast_tvzero(c[x]->whentohangup) && ast_tvcmp(c[x]->whentohangup, now) <= 0) {
                                c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
                                if (winner == NULL)
                                        winner = c[x];
@@ -1936,8 +1943,7 @@ static struct ast_channel *ast_waitfor_nandfds_simple(struct ast_channel *chan,
        struct timeval start = { 0 , 0 };
        int res = 0;
        struct epoll_event ev[1];
-       long whentohangup = 0, rms = *ms;
-       time_t now;
+       long diff, rms = *ms;
        struct ast_channel *winner = NULL;
        struct ast_epoll_data *aed = NULL;
 
@@ -1952,18 +1958,16 @@ static struct ast_channel *ast_waitfor_nandfds_simple(struct ast_channel *chan,
        }
 
        /* Figure out their timeout */
-       if (chan->whentohangup) {
-               time(&now);
-               if ((whentohangup = chan->whentohangup - now) < 1) {
+       if (!ast_tvzero(chan->whentohangup)) {
+               if ((diff = ast_tvdiff_ms(chan->whentohangup, ast_tvnow())) < 0) {
                        /* They should already be hungup! */
                        chan->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
                        ast_channel_unlock(chan);
                        return NULL;
                }
                /* If this value is smaller then the current one... make it priority */
-               whentohangup *= 1000;
-               if (rms > whentohangup)
-                       rms = whentohangup;
+               if (rms > diff)
+                       rms = diff;
        }
 
        ast_channel_unlock(chan);
@@ -1988,9 +1992,8 @@ static struct ast_channel *ast_waitfor_nandfds_simple(struct ast_channel *chan,
        }
 
        /* If this channel has a timeout see if it expired */
-       if (chan->whentohangup) {
-               time(&now);
-               if (now >= chan->whentohangup) {
+       if (!ast_tvzero(chan->whentohangup)) {
+               if (ast_tvdiff_ms(ast_tvnow(), chan->whentohangup) >= 0) {
                        chan->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
                        winner = chan;
                }
@@ -2024,8 +2027,8 @@ static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, i
        struct timeval start = { 0 , 0 };
        int res = 0, i;
        struct epoll_event ev[25] = { { 0, } };
-       long whentohangup = 0, diff, rms = *ms;
-       time_t now;
+       struct timeval now = { 0, 0 };
+       long whentohangup = 0, diff = 0, rms = *ms;
        struct ast_channel *winner = NULL;
 
        for (i = 0; i < n; i++) {
@@ -2036,15 +2039,15 @@ static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, i
                        ast_channel_unlock(c[i]);
                        return NULL;
                }
-               if (c[i]->whentohangup) {
-                       if (!whentohangup)
-                               time(&now);
-                       if ((diff = c[i]->whentohangup - now) < 1) {
+               if (!ast_tvzero(c[i]->whentohangup)) {
+                       if (whentohangup == 0)
+                               now = ast_tvnow();
+                       if ((diff = ast_tvdiff_ms(c[i]->whentohangup, now)) < 0) {
                                c[i]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
                                ast_channel_unlock(c[i]);
                                return c[i];
                        }
-                       if (!whentohangup || (diff < whentohangup))
+                       if (!whentohangup || whentohangup > diff)
                                whentohangup = diff;
                }
                ast_channel_unlock(c[i]);
@@ -2053,7 +2056,7 @@ static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, i
 
        rms = *ms;
        if (whentohangup) {
-               rms = whentohangup * 1000;
+               rms = whentohangup;
                if (*ms >= 0 && *ms < rms)
                        rms = *ms;
        }
@@ -2073,9 +2076,9 @@ static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, i
        }
 
        if (whentohangup) {
-               time(&now);
+               now = ast_tvnow();
                for (i = 0; i < n; i++) {
-                       if (c[i]->whentohangup && now >= c[i]->whentohangup) {
+                       if (!ast_tvzero(c[i]->whentohangup) && ast_tvdiff_ms(now, c[i]->whentohangup) >= 0) {
                                c[i]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
                                if (!winner)
                                        winner = c[i];
index 11d6671..4006780 100644 (file)
@@ -1064,7 +1064,7 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                c->fds[0],
                c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
                c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
-               (long)c->whentohangup,
+               (long)c->whentohangup.tv_sec,
                cdrtime, c->_bridge ? c->_bridge->name : "<none>", ast_bridged_channel(c) ? ast_bridged_channel(c)->name : "<none>", 
                c->context, c->exten, c->priority, c->callgroup, c->pickupgroup, ( c->appl ? c->appl : "(N/A)" ),
                ( c-> data ? S_OR(c->data, "(Empty)") : "(None)"),
index ae6ea55..377d73b 100644 (file)
@@ -266,7 +266,7 @@ static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_chann
 
        channel->owner->appl = "AppDial2";
        channel->owner->data = "(Outgoing Line)";
-       channel->owner->whentohangup = 0;
+       memset(&channel->owner->whentohangup, 0, sizeof(channel->owner->whentohangup));
 
        /* Inherit everything from he who spawned this dial */
        if (chan) {
index 82cf564..1067c3c 100644 (file)
@@ -2367,13 +2367,14 @@ static int action_timeout(struct mansession *s, const struct message *m)
 {
        struct ast_channel *c;
        const char *name = astman_get_header(m, "Channel");
-       int timeout = atoi(astman_get_header(m, "Timeout"));
+       double timeout = atof(astman_get_header(m, "Timeout"));
+       struct timeval tv = { timeout, 0 };
 
        if (ast_strlen_zero(name)) {
                astman_send_error(s, m, "No channel specified");
                return 0;
        }
-       if (!timeout) {
+       if (!timeout || timeout < 0) {
                astman_send_error(s, m, "No timeout specified");
                return 0;
        }
@@ -2382,7 +2383,9 @@ static int action_timeout(struct mansession *s, const struct message *m)
                astman_send_error(s, m, "No such channel");
                return 0;
        }
-       ast_channel_setwhentohangup(c, timeout);
+
+       tv.tv_usec = (timeout - tv.tv_sec) * 1000000.0;
+       ast_channel_setwhentohangup_tv(c, tv);
        ast_channel_unlock(c);
        astman_send_ack(s, m, "Timeout Set");
        return 0;
index 92588bd..dafd0cc 100644 (file)
@@ -3534,7 +3534,7 @@ static int collect_digits(struct ast_channel *c, int waittime, char *buf, int bu
                                buf[pos++] = digit;
                                buf[pos] = '\0';
                        }
-                       waittime = c->pbx->dtimeout;
+                       waittime = c->pbx->dtimeoutms;
                }
        }
        return 0;
@@ -3567,8 +3567,8 @@ static int __ast_pbx_run(struct ast_channel *c)
                }
        }
        /* Set reasonable defaults */
-       c->pbx->rtimeout = 10;
-       c->pbx->dtimeout = 5;
+       c->pbx->rtimeoutms = 10000;
+       c->pbx->dtimeoutms = 5000;
 
        autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);  /* save value to restore at the end */
        ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
@@ -3602,12 +3602,12 @@ static int __ast_pbx_run(struct ast_channel *c)
                        if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
                                set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
                                /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
-                               c->whentohangup = 0;
+                               memset(&c->whentohangup, 0, sizeof(c->whentohangup));
                                c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
                        } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
                                pbx_builtin_raise_exception(c, "ABSOLUTETIMEOUT");
                                /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
-                               c->whentohangup = 0;
+                               memset(&c->whentohangup, 0, sizeof(c->whentohangup));
                                c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
                        } else if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
                                c->_softhangup = 0;
@@ -3664,7 +3664,7 @@ static int __ast_pbx_run(struct ast_channel *c)
                                } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
                                        set_ext_pri(c, "T", 1); 
                                        /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
-                                       c->whentohangup = 0;
+                                       memset(&c->whentohangup, 0, sizeof(c->whentohangup));
                                        c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
                                        continue;
                                } else {
@@ -3707,9 +3707,9 @@ static int __ast_pbx_run(struct ast_channel *c)
                } else {        /* keypress received, get more digits for a full extension */
                        int waittime = 0;
                        if (digit)
-                               waittime = c->pbx->dtimeout;
+                               waittime = c->pbx->dtimeoutms;
                        else if (!autofallthrough)
-                               waittime = c->pbx->rtimeout;
+                               waittime = c->pbx->rtimeoutms;
                        if (!waittime) {
                                const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
                                if (!status)
@@ -7617,7 +7617,7 @@ static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
        if (args.timeout && (s = atof(args.timeout)) > 0)
                 ms = s * 1000.0;
        else if (chan->pbx)
-               ms = chan->pbx->rtimeout * 1000;
+               ms = chan->pbx->rtimeoutms;
        else
                ms = 10000;
 
index 4370654..4675b5f 100644 (file)
@@ -980,9 +980,9 @@ static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *
 
        if ( argc == 5 )
                timeout = atoi(argv[4]);
-       else if (chan->pbx->dtimeout) {
+       else if (chan->pbx->dtimeoutms) {
                /* by default dtimeout is set to 5sec */
-               timeout = chan->pbx->dtimeout * 1000; /* in msec */
+               timeout = chan->pbx->dtimeoutms; /* in msec */
        }
 
        if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
@@ -1398,18 +1398,20 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
 
 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
 {
-       int timeout;
+       double timeout;
+       struct timeval whentohangup = { 0, 0 };
 
        if (argc != 3)
                return RESULT_SHOWUSAGE;
-       if (sscanf(argv[2], "%d", &timeout) != 1)
+       if (sscanf(argv[2], "%lf", &timeout) != 1)
                return RESULT_SHOWUSAGE;
        if (timeout < 0)
                timeout = 0;
-       if (timeout)
-               chan->whentohangup = time(NULL) + timeout;
-       else
-               chan->whentohangup = 0;
+       if (timeout) {
+               whentohangup.tv_sec = timeout;
+               whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
+       }
+       ast_channel_setwhentohangup_tv(chan, whentohangup);
        ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
        return RESULT_SUCCESS;
 }